get console output - python-3.x

how can i receive the console output of any python file (errors, everything printed using the print() command)?
example:
main.py starts test.py and gets its output

You can use sys.stderr from the sys module. print() uses sys.stdout by default.
import sys
# Print to standard output stream
print("Normal output...")
# Print to standard error stream
print("Error output...", file=sys.stderr)

i dont know if this will help but im sure it will give you an idea.
in vb.net or c#.net we capture console stream using the process StandardOutput like this:
Dim p as Process = Process.Start("cmd")
p.WaitForExit(Integer.MaxValue)
dim output as String = p.StandardOutput

Related

syntax error in AWS Greengrass V2 hello_world.py

I am experimenting with AWS IoT greengrass V2. I am just following the manual that has the following python code:
import sys
import datetime
message = f"Hello, {sys.argv[1]}! Current time: {str(datetime.datetime.now())}."
# Print the message to stdout.
print(message)
# Append the message to the log file.
with open('/tmp/Greengrass_HelloWorld.log', 'a') as f:
print(message, file=f)
According to my logging there is a syntax error in line 4. Replacing line 4 with the following works fine:
message = "Hello"
Does anyone see what is wrong with this line:
message = f"Hello, {sys.argv[1]}! Current time: {str(datetime.datetime.now())}."
Thanks.
I'm one of the documentation writers for AWS IoT Greengrass.
Formatted strings literals (f"some content") are a feature of Python 3.6+, and this syntax results in a syntax error in earlier versions. The getting started tutorial requirements incorrectly list Python 3.5 as a requirement, but Python 3.5 doesn't support formatted string literals. We'll update this requirement to say 3.6 or update the script to remove the formatted string literal.
To resolve this issue, you can upgrade to Python 3.6+ or modify the script to remove the formatted string literal. Thank you for finding this issue!
For the record: I altered the code, avoiding the f"stringliteral" :
import sys
import datetime
constrmessage ="Hello, ",str(sys.argv[1])," "+str(datetime.datetime.now())
#change from tuple to string
message = ''.join(constrmessage)
#print message to screen
print(message)
original_stdout = sys.stdout
# Append the message to the log file.
with open('/tmp/Greengrass_HelloWorld.log', 'a') as f:
sys.stdout = f
print(message)
sys.stdout = original_stdout

tqdm progress bar not updating when using paramiko

When using Paramiko to execute commands remotely, I can't see an updating progress bar using tqdm. I'm guessing this is because it isn't printing a new line when tqdm updates the bar
Here's a simple code example I've been using, but you'll need to supply your own SSH credentials
ssh = paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.connect('8.tcp.ngrok.io', username=username, get_pty=True)
command = 'python3 -c "import tqdm; import time; [time.sleep(1) for i in tqdm.tqdm(range(5))]"'
stdin, stdout, stderr = ssh_client.exec_command('sudo -S '+command)
stdin.write(password+'\n')
stdin.flush()
###new_method
for l, approach in line_buffered(stdout):
if approach=='print':
print( l)
if approach=='overlay':
print( l, end='\r')
ssh.close()
Is there a way I can print the tqdm bar as it updates?
Based on Martin Prikryl's suggestion, I tried to incorporate the solution from:
Paramiko with continuous stdout
And adapted the code to print regardless of a new line
def line_buffered(f):
line_buf = ""
while not f.channel.exit_status_ready():
# f.read(1).decode("utf-8")
line_buf += f.read(1).decode("utf-8", 'ignore')
if line_buf.endswith('\n'):
yield line_buf, 'print'
line_buf = ''
# elif len(line_buf)>40:
elif line_buf.endswith('\r'):
yield line_buf, 'overlay'
This does successfully print the as the output as it is generated, and reprints on the tqdm line, but when I run this code I get the following output
100%|| 5/5 [00:05<00:00, 1.00s/it]1.00s/it]1.00s/it]1.00s/it]1.00s/it]?, ?it/s]
Not very pretty, and getting swamped by the iteration time. It doesn't seem to be printing the actual progress bar. any ideas?
It probably because you are (correctly) using non-interactive session to automate your command execution.
Most decently designed commands do not print an output intended for an interactive human use, like progress, when executed non-interactively.
If you really want to see the progress display, try setting get_pty argument of SSHClient.exec_command to true.
stdin, stdout, stderr = ssh_client.exec_command('sudo -S '+command, get_pty=True)

Pexpect - Read from constantly outputting shell

I'm attempting to have pexpect begin running a command which basically continually outputs some information every few milliseconds until cancelled with Ctrl + C.
I've attempted getting pexpect to log to a file, though these outputs are simply ignored and are never logged.
child = pexpect.spawn(command)
child.logfile = open('mylogfile.txt', 'w')
This results in the command being logged with an empty output.
I have also attempted letting the process run for a few seconds, then sending an interrupt to see if that logs the data, but this again, results in an almost empty log.
child = pexpect.spawn(command)
child.logfile = open('mylogfile.txt', 'w')
time.sleep(5)
child.send('\003')
child.expect('$')
This is the data in question:
image showing the data constantly printing to the terminal
I've attempted the solution described here: Parsing pexpect output though it hasn't worked for me and results in a timeout.
Managed to get it working by using Python Subprocess for this, not sure of a way to do it with Pexpect, but this got what I described.
def echo(self, n_lines):
output = []
if self.running is False:
# start shell
self.current_shell = Popen(cmd, stdout=PIPE, shell=True)
self.running = True
i = 0
# Read the lines from stdout, break after reading the desired amount of lines.
for line in iter(self.current_shell.stdout.readline, ''):
output.append(line[0:].decode('utf-8').strip())
if i == n_lines:
break
i += 1
return output

Print in real time the result of a bash command launched with subprocess in Python

I'm using the subprocess module to run a bash command. I want to display the result in real time, including when there's no new line added, but the output is still modified.
I'm using python 3. My code is running with subprocess, but I'm open to any other module. I have some code that return a generator for every new line added.
import subprocess
import shlex
def run(command):
process = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE)
while True:
line = process.stdout.readline().rstrip()
if not line:
break
yield line.decode('utf-8')
cmd = 'ls -al'
for l in run(cmd):
print(l)
The problem comes with commands of the form rsync -P file.txt file2.txt for example, which shows a progress bar.
For example, we can start by creating a big file in bash:
base64 /dev/urandom | head -c 1000000000 > file.txt
Then try to use python to display the rsync command:
cmd = 'rsync -P file.txt file2.txt'
for l in run(cmd):
print(l)
With this code, the progress bar is only printed at the end of the process, but I want to print the progress in real time.
From this answer you can disable buffering when print in python:
You can skip buffering for a whole python process using "python -u"
(or #!/usr/bin/env python -u etc) or by setting the environment
variable PYTHONUNBUFFERED.
You could also replace sys.stdout with some other stream like wrapper
which does a flush after every call.
Something like this (not really tested) might work...but there are
probably problems that could pop up. For instance, I don't think it
will work in IDLE, since sys.stdout is already replaced with some
funny object there which doesn't like to be flushed. (This could be
considered a bug in IDLE though.)
>>> class Unbuffered:
.. def __init__(self, stream):
.. self.stream = stream
.. def write(self, data):
.. self.stream.write(data)
.. self.stream.flush()
.. def __getattr__(self, attr):
.. return getattr(self.stream, attr)
..
>>> import sys
>>> sys.stdout=Unbuffered(sys.stdout)
>>> print 'Hello'
Hello

Python error 'integer is required'

I am using the following code
# simpleSerialSend.py
import sys
import serial
import time
PORT = 'COM4' # The port my Arduino is on, on my WinXP box.
def main(val=5):
# Open a connection to the serial port. This will reset the Arduino, and
# make the LED flash once:
ser = serial.Serial(PORT)
# Must given Arduino time to rest.
# Any time less than this does not seem to work...
time.sleep(1.5)
# Now we can start sending data to it:
written = ser.write(val)
ser.close()
print ("Bytes Written to port:", written)
print ("Value written to port: '%s'"%val)
if __name__ == '__main__':
args = sys.argv
try:
main(args[1])
except IndexError:
main()
and I am kinda new to python.
So the error i get is like in the description said integer required.
I run it in my cmd with the following rule: c:\pyModules\simpleSerialSend.py 5
It is working fine only i get the error. What the code does is sending a variable to my arduino so a light goes blinking. The code of the arduino is correct.
The arguments are coming in as str. So, the solution to your problem is actually to just convert the string to int
main(int(args[1])) # assuming args[1] is a parsable numeric string
Also, maybe take a look at argparse.

Resources