S
S
S1riyS2021-01-02 14:45:03
Python
S1riyS, 2021-01-02 14:45:03

Why does subprocess.Popen.communicate return the result of the time (Linux) command as an error?

The question has several parts:
1) To run Docker images from python , I decided to use the subprocess library .
main.py :

import platform

from subprocess import call, Popen, PIPE


class Docker:
    def __init__(self):
        self._docker_compose_up()
        self.current_path_command = self._get_current_path_command()
        self.runner_images = {
            'cpp': 'compilers_cpp_runner',
            'python': 'compilers_python_runner'
        }

    @staticmethod
    def _get_current_path_command():
        if platform.system() == 'Windows':
            return '%CD%'
        return '$(pwd)'

    @staticmethod
    def _docker_compose_up():
        call('docker-compose up -d --build --force-recreate --renew-anon-volumes')

    @staticmethod
    def docker_compose_down():
        call('docker-compose down')

    def run_code(self, filename, language):
        image = self.runner_images[language]
        command = f'docker run -i -v {self.current_path_command}/temp:/temp --env FILENAME={filename} {image}'

        result = Popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=True, encoding='utf-8')
        output, error = result.communicate(input='12 2')

        return {'output': output, 'error': error}


docker = Docker()
print(docker.run_code('hello_world', 'cpp'))
print(docker.run_code('hello_world', 'python'))
docker.docker_compose_down()

Explanation of the code:
First I run docker-compose.yml, which is in the same directory as the python file.
Then I define a command to get the current location in the file system (If the OS is Windows , then this is %CD% , if something else, then $(pwd) )
Then I run the image (method run_code ), passing the file name and language there.

Dockerfile for python :
FROM python
ARG FILENAME_ARG
ENV FILENAME = $FILENAME_ARG
CMD export TIMEFORMAT='%3R'
CMD bash -c "time python temp/${FILENAME}.py"


As a result of executing the function, I get a dictionary with the keys output and error :
{'output': '10\n', 'error': '\nreal\t0m0.071s\nuser\t0m0.053s\nsys\t0m0.011s\n'}


Formatted output :
real	0m0.072s
user	0m0.061s
sys	0m0.001s


Why does the runtime flies to error and not to output ?

2) Am I implementing this normally, or are there some other ways to make everything more correct and more beautiful?
3) How to make it so that only real time in seconds is displayed (command CMD export TIMEFORMAT='%3R'did not work)

Answer the question

In order to leave comments, you need to log in

1 answer(s)
S
sergey, 2022-01-03
@S1riyS

here are two dockerfile examples
passing a format string to the time command via an option and an environment
and redirecting stderr to stdout

FROM python:3.8.2-alpine
ARG FILENAME_ARG
ENV FILENAME $FILENAME_ARG
# time on alpine does not recognize a long --format argument
CMD time -f '%U' python temp/${FILENAME} 2>&1

FROM python:3.8.2-alpine
ARG FILENAME_ARG
ENV FILENAME $FILENAME_ARG
ENV TIME '%u'
CMD time python temp/${FILENAME} 2>&1

and the easiest way to read which formats are supported is through man time
https://man7.org/linux/man-pages/man1/time.1.html
TIME(1)                     General Commands Manual                    TIME(1)

NAME
       time - run programs and summarize system resource usage


 %U     Total number of CPU-seconds that the process spent in user
              mode.
...
%R     Number of minor, or recoverable, page faults.

I don't think you need%R

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question