I'm unable to capture stdout of runpy.run_module into a variable using StringIO.
To demonstrate the problem, I created a script called runpy_test.py (code below) using an arg switch;
0 = do not redirect stdout.
1 = redirect using StringIO, capture into variable, print variable.
Console Output
(base) PS C:\Users\justi\Documents> python .\runpy_test.py 0
pip 20.0.2 from C:\ProgramData\Anaconda3\lib\site-packages\pip (python 3.6)
(base) PS C:\Users\justi\Documents> python .\runpy_test.py 1
(base) PS C:\Users\justi\Documents>
I was expecting python .\runpy_test.py 1 to print pip 20.0.2 from C:\ProgramData\Anaconda3\lib\site-packages\pip (python 3.6), but as you can see from the above console capture, I'm getting nothing.
runpy_test.py
import io
import sys
import runpy
import copy
capture_stdout = bool(sys.argv[1] == "1")
if capture_stdout:
_stdout = sys.stdout
sys.stdout = io.StringIO()
_argv = copy.deepcopy(sys.argv)
sys.argv = ['', '-V']
runpy.run_module("pip", run_name="__main__")
sys.argv = _argv
if capture_stdout:
result = sys.stdout.getvalue()
sys.stdout = _stdout
print(f"result: {result}")
I'm guessing sys.stdout is not being correctly re-initialised before I print because of something related to runpy.run_module, but not really sure how to debug. Any ideas would be great, solutions even better.
My environment is Python 3.6.10 using conda 4.8.3.
Thanks in advance.
Using subprocess.check_output instead of runpy.run_module solved my problem.
See Installing python module within code
You can use capsys in the pytest framework:
def test_main(capsys):
runpy.run_module(
"helloworld",
init_globals=None,
run_name="__main__",
alter_sys=False)
captured = capsys.readouterr()
assert captured.out == "Hello, World!"
Related
I am trying to print output using sys.stdout but getting none on stdout. please check
# Read input from STDIN. Print output to STDOUT
import math
import os
import random
import re
import sys
def stdin(s):
if (len(s)>=2 and len(s)<=10000):
ev=[s[i] for i in range(len(s)) if i%2==0]
od=[s[i] for i in range(len(s)) if i%2!=0]
even=''.join(map(str,ev))
odd=''.join(map(str,od))
sys.stdout.write("{0} {1}".format(even,odd)) #print outpout using stdout but error got
sys.stdout.flush()
if __name__ == '__main__':
s = input().strip()
stdin(s)
By default python uses stdout when using the built in print() function. It will also read from stdin when using input(). I would suggest going that route as it will be less prone to error. Otherwise could you share the exact error message you are getting? The code is running without error for me.
I have an interesting set of requirements that I am trying to conduct using the Python subprocess module and docker-compose. This whole setup is possible in one docker-compose but due to requirement this is what I would like to setup:
call the docker-compose using python subprocess to activate the
test-servers
print all the std-out of above docker-compose running.
as soon as the test-server up and running via docker-compose; call the testing scripts for that server.
This is my docker-compose.py looks like:
import subprocess
from subprocess import PIPE
import os
from datetime import datetime
class MyLog:
def my_log(self, message):
date_now = datetime.today().strftime('%d-%m-%Y %H:%M:%S')
print("{0} || {1}".format(date_now, message))
class DockercomposeRun:
log = MyLog()
def __init__(self):
dir_name, _ = os.path.split(os.path.abspath(__file__))
self.dirname = dir_name
def run_docker_compose(self, filename):
command_name = ["docker-compose", "-f", self.dirname + filename, "up"]
popen = subprocess.Popen(command_name, stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=True)
return popen
now in my test.py
as soon as my stdout is blank I would like to break the loop of printing and run the rest of the test in test.py.
docker_compose_run = DockercomposeRun()
rc = docker_compose_run.run_docker_compose('/docker-compose.yml.sas-viya-1')
for line in iter(rc.stdout.readline, ''):
print(line, end='')
if line == '':
break
popen.stdout.close()
# start here actual test cases
.......
But for me the loop is never broken even though the stdout of docker-compose goes blank after the server is up and running. And, the test cases are never executed.
Is it the right approach or how I can achieve this?
I think the issue here is because you are not running docker-compose in detached mode and its blocking the application run. Can you try adding "-d" to command_name?
A terminal command that we type in the terminal might print some output on the terminal. When we use this command in a python script and call a system call say:
os.system('ls')
we do obtain the output, but somehow it returns an integer to indicate a successful execution of the process:
>>> x = os.system('ls') #prints some output
>>> x
>>> 0
I need a function that stores the output in x as a string that I need to parse. What is the python function that does this?
You would use the subprocess module.
from subprocess import PIPE, Popen
proc = Popen(["ls"], stdout=PIPE)
stdout, stderr = proc.communicate()
Or if you're using Python 3.5 or greater, then run is recommended.
import subprocess
completed = subprocess.run(["ls", "-l"], stdout=subprocess.PIPE, encoding="utf-8")
#output is stored in completed.stdout
Why do the "subprocess.Popen.stdin.write" commands seem to fail?
#!/usr/bin/env python3
# coding=utf-8
import os
import subprocess
bash = subprocess.Popen(['bash'],
stdout=subprocess.PIPE, stdin=subprocess.PIPE,
stderr=subprocess.PIPE, shell=True)
(shell=True: see edit 2)
bash.stdin.write(b'echo foo\n')
print(bash.stdout.readline())
bash.stdin.write(b'echo bar\n')
print(bash.stdout.readline())
edit: It blocks at the first subprocess.Popen.stdout.readline(), probably because there are no lines in subprocess.Popen.stdout. It is supposed to print out:
foo
bar
edit 2: This still hangs.
This answer for my question works as long as you run GNU/Linux(maybe others, haven't tested) and install pexpect("pip install pexpect").
#!/usr/bin/env python3
# coding=utf-8
"""
Python command line software control example
"""
import pexpect
encode = 'UTF-8'
bash = pexpect.spawn('/usr/bin/env bash', encoding=encode)
bash.sendline('echo foo')
print(bash.readline())
bash.sendline('echo bar')
print(bash.readline())
I've got a problem using the standard error, whenever I try to use it my computer gives me a syntax error which i can't explain.
So this is my code:
import sys
def main(argv):
if len(argv) != 3:
print("Usage: python walk.py n l", file=sys.stderr)
else:
l = argv[2]
n = argv[1]
print("You ended up", simuleer(n,l), "positions from the starting point.")
if __name__ == "__main__":
main(sys.argv)
And this is my error
MacBook-Air-van-Luuk:documents luuk$ python walk.py 5 1 2
File "walk.py", line 21
print("Usage: python walk.py n l", file=sys.stderr)
^
I hope someone can explain me why this happens, thanks in advance!
You think you're using Python 3.x, but it's actually Python 2.x. On most systems python executable means Python 2.x.
print is not a function in Python 2.x, and can't be used like that, causing a syntax error.
You should look for some way to run Python 3.x instead.
For this particular case, you could also use from __future__ import print_function, which would make the code compatible with both versions.
There is a way to fix it
Just remove the "file=" from print method
e.g:
print("Usage: python walk.py n l", sys.stderr)