I am working on a custom command line interpreter, and I want to implement the 'clear' command, just like the the one in bash shell. Is there any way to do that?
I have attempted it but I don't think it is correct at all:
#!/usr/bin/python3
import cmd
import sys
import os
class HBNBCommand(cmd.Cmd):
"""Command line interpreter"""
def do_clear(self):
"""Clear command similar to clear from shell"""
os.system('clear')
if __name__ == '__main__':
HBNBCommand().cmdloop()
When I try it, it gives me the exception:
Traceback (most recent call last):
File "/home/leuel/PycharmProjects/AirBnB_clone/./console.py", line 22, in <module>
HBNBCommand().cmdloop()
File "/usr/lib/python3.10/cmd.py", line 138, in cmdloop
stop = self.onecmd(line)
File "/usr/lib/python3.10/cmd.py", line 217, in onecmd
return func(arg)
TypeError: HBNBCommand.do_clear() takes 1 positional argument but 2 were given
When inheriting from cmd to build your custom shell, methods expect at least one argument. To quote from this resource, "The interpreter uses a loop to read all lines from its input, parse them, and then dispatch the command to an appropriate command handler. Input lines are parsed into two parts. The command, and any other text on the line."
Since do_clear has not provided for an argument, the command cannot handle any additional input, even when that input does not exist.
class HBNBCommand(cmd.Cmd):
"""Command line interpreter"""
def do_clear(self, arg):
"""Clear command similar to clear from shell"""
os.system('clear')
if __name__ == '__main__':
HBNBCommand().cmdloop()
You can also refer to the Cmd example in the Python docs: https://docs.python.org/3/library/cmd.html#cmd-example
Related
UPDATE: this seems to be specific to uncaught exceptions inside a function called by the slot/signal flow of PyQt5 (PyQt 5.11 running in Python 3.7.0). See UPDATE farther down this question text.
The overall goal is to tee the stdout and stderr of a python program to screen and to the same file, on a Windows 10 machine; I'd prefer to do this redirection at the operating system level (i.e. the shell that invokes python - Windows in this case); doing it cleanly from within the python program hasn't worked out at any rate.
Check out the broken stderr redirection lines below.
radiolog.py is a large python program which shouldn't be relevant here; inside it I trigger an exception in order to test this logging workflow. radiolog_log.ps1 is a powershell wrapper around radiolog.py:
python -u radiolog.py 2>&1 | % ToString | Tee-Object log.txt
Running radiolog_log.ps1 from inside a powershell terminal:
PS C:\Users\caver\Documents\GitHub\radiolog> .\radiolog_log.ps1
6319:Operating system is Windows.
6319:PowerShell.exe is in the path.
... (omitting a bunch of irrelevant radiolog transcript output)
6329:Accepted2
Traceback (most recent call last):
File "
radiolog.py", line 3796, in keyPress
Eve
n
t
sel
f.accept
(
)
File "
r
adio
l
og.
py"
,
line 3
9
13, in accept
rprint(1/0)
ZeroD
ivi
sionError: division by zero
PS C:\Users\caver\Documents\GitHub\radiolog>
There are some good posts and answers out there about powershell stderr redirection splitting lines at the width of the console... however, this one seems to be splitting the lines every few characters, and it's not the same each time.
The | % ToString gets rid of the (in this case) redundant layer of powershell's exception handling; without | % ToString it looks like this (everything beginning with 'python: Traceback' is in red text):
6851:Accepted2
python : Traceback (most recent call last):
At line:1 char:1
+ python -u radiolog.py 2>&1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (Traceback (most recent call last)::String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
F
ile "radiolog.py", line 3796, in keyPressEvent
self.accept()
File "ra
diol
o
g.p
y",
lin
e 39
13, in accept
rp
r
int(1/0)
Ze
r
oDivisio
n
Error:
div
i
sion by zero
PS C:\Users\caver\Documents\GitHub\radiolog>
Another attempt is to run a .bat file from the powershell terminal, then do the tee in powershell.
radiolog_log.bat:
python -u radiolog.py 2>&1
In the powershell terminal:
PS C:\Users\caver\Documents\GitHub\radiolog> .\radiolog_log.bat | % ToString | Tee-Object log.dat
which results in the following terminal display - everything as expected:
C:\Users\caver\Documents\GitHub\radiolog>python -u radiolog.py 2>&1
8314:Operating system is Windows.
8314:PowerShell.exe is in the path.
...
8327:Accepted2
Traceback (most recent call last):
File "radiolog.py", line 3796, in keyPressEvent
self.accept()
File "radiolog.py", line 3913, in accept
rprint(1/0)
ZeroDivisionError: division by zero
PS C:\Users\caver\Documents\GitHub\radiolog>
However log.dat is written in unicode, i.e. is not human-readable as a plain text file. Microsoft says as much in the Tee documentation here - not sure why...? Found a question about converting it to ascii on the fly, but, it doesn't look like you can have the same real-time file and terminal output, negating a big part of the reasoning for tee in the first place.
Any ideas on how to get everything to just play nice like it would in linux?
UPDATE: PyQt5 slot/signal flow seems to be triggering this behavior. Example code, massively pared down from the original radiolog.py:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
self.pushButton = QPushButton(Dialog)
self.pushButton.setObjectName("pushButton")
self.pushButton.setText(" Add Entry ")
self.horizontalLayout = QHBoxLayout(Dialog)
self.horizontalLayout.addWidget(self.pushButton)
class MyWindow(QDialog,Ui_Dialog):
def __init__(self,parent):
QDialog.__init__(self)
self.ui=Ui_Dialog()
self.ui.setupUi(self)
# click the button to see that stderr inserts line breaks every few
# characters (different on each occurrance) when openNewEntry is called
# from the slot/signal flow:
self.ui.pushButton.clicked.connect(self.openNewEntry)
# uncomment the following line to see that stderr is line-buffered when
# openNewEntry is called from code:
# self.openNewEntry()
def openNewEntry(self):
print(1/0)
def main():
app = QApplication(sys.argv)
w = MyWindow(app)
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
In a powershell terminal, after defining STD-Handler as per the earliest answer to this question (not required to observe the broken lines, but, it does make cleaner output without the powershell-exception header as well as making a plain-text log file), then execute as follows:
python -u r.py *>&1 | STD-Handler log.txt
Click the button in the GUI and you get this:
[636765635572699130]: Traceback (most recent call last):
[636765635572808866]:
[636765635572918571]: File "r.py", line 33,
[636765635573028268]:
[636765635573118026]: in open
[636765635573207784]: New
[636765635573307659]: E
[636765635573407558]: ntry
print(1/0)
ZeroDivisionError: division by z
[636765635573506983]: ero
Now uncomment the line in the python code as noted, so that the exception is called from code rather than from user interaction; run the same line at the powershell terminal and you get this:
[636765639350787977]: Traceback (most recent call last):
[636765639350877842]: File "r.py", line 42, in <module>
[636765639350997857]:
[636765639351077838]: main()
File "r.py", line 37, in main
[636765639351187538]:
[636765639351282570]: w = MyWindow(app)
File "r.py", line 30, in __init__
[636765639351372787]:
[636765639351467301]: self.openNewEntry()
File "r.py", line 33, in openNewEntry
[636765639351554768]:
[636765639351660016]: print(1/0)
ZeroDivisionError: division by zero
So, this probably merits a new question to the PyQt community which I'll put together soon and cross-reference here - though help on this thread would still be great!
I tried to replicate this issue with some dummy script, but got proper file and terminal outputs in both cases (ps and bat). I guess you can just use your bat script, then fix file encoding at the end. If you really need the file to be updated live, below is a possible workaround. Basically you can create some custom "Tee-Object" and handle stdout as it comes. $_ is an object coming from a pipeline (stdout), even if it broken you can fix encoding or remove new line characters inside Process block
function STD-Handler
{ param ($outFile)
Begin { $null > $outFile }
Process {
$line = "[" + (get-date).Ticks + "]: " + $_
Write-Host $line
$line >> $outFile
}
End { <# can do smth with the file at the end#>}
}
usage:
python -u C:\stack\stdout.py *>&1 | STD-Handler "C:\temp\log.txt"
Partial Bingo - some other questions talk about the way PyQt5 treats uncaught exceptions. Not really sure of the interactions between PyQt's stderr handling and powershell's stderr handling, but, overriding sys.excepthook in python to have the 'old' behavior does the trick. Here's the new entire r.py python code - the only changes from the updated question code are the 'def except_hook' and 'sys.excepthook = except_hook' in the 'if name' clause:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
self.pushButton = QPushButton(Dialog)
self.pushButton.setObjectName("pushButton")
self.pushButton.setText(" Add Entry ")
self.horizontalLayout = QHBoxLayout(Dialog)
self.horizontalLayout.addWidget(self.pushButton)
class MyWindow(QDialog,Ui_Dialog):
def __init__(self,parent):
QDialog.__init__(self)
self.ui=Ui_Dialog()
self.ui.setupUi(self)
# click the button to see that stderr inserts line breaks every few
# characters (different on each occurrance) when openNewEntry is called
# from the slot/signal flow:
self.ui.pushButton.clicked.connect(self.openNewEntry)
# uncomment the following line to see that stderr is line-buffered when
# openNewEntry is called from code:
# self.openNewEntry()
def openNewEntry(self):
print(1/0)
def except_hook(cls, exception, traceback):
sys.__excepthook__(cls, exception, traceback)
exit(-1)
def main():
app = QApplication(sys.argv)
w = MyWindow(app)
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
sys.excepthook = except_hook
main()
Now, clicking the button produces this output:
[636766143015640817]: Traceback (most recent call last):
[636766143015760489]: File "r.py", line 33, in openNewEntry
[636766143015911442]:
[636766143016031102]: print(1/0)
ZeroDivisionError: division by zero
Sometimes (not repeatably) it comes out a bit fractured at punctuation and such, but, this is a lot more manageable:
[636766144719906619]: Traceback (most recent call last):
[636766144720006506]: File "r.py", line 47, in <module>
[636766144720096055]:
[636766144720195662]: main()
File "r.py", line 41, in main
[636766144720275744]:
[636766144720375114]: w = MyWindow(app)
[636766144720469728]: File "r.py", line 30, in __init__
[636766144720565688]:
[636766144720657318]: self.openNewEntry()
File "r.py", line 33, in openNewEntry
[636766144720757052]:
[636766144720852021]: print(1/0)
ZeroDivisionError
[636766144720946788]: :
[636766144721046802]: division by zero
[636766144721132731]:
And this better-behaved output happens in the full program too (radiolog.py).
So, it would be great if anyone can shed more light on why the intermittent partial fracturing still happens, but, I think this is a workable solution. Thanks
I have some input file in a directory and want to make a python script with 2 functions and run the script for all of the input files in the same directory.
the script that I made still does not work. there are 2 functions. the first one is the one which takes the input files and returns the output files. if I run this function on every single input file, it will work perfectly. so there is no problem with the function "convert".
the 2nd function in main function which is made for "argparse". the script has problem in this function.
import argparse
import pytools
def convert(infile, outfile):
x = pytools.split(infile)
x.coverage(bh=True, split=True)\
.saveas(outfile, type='bh')
print "done"
return
def main():
parser=argparse.ArgumentParser()
parser.add_argument("-b", "--infile", required=True)
parser.add_argument("-o", "--output", required=True)
args = parser.parse_args()
input = args.infile
output = convert(args.infile)
if __name__ == '__main__':
main()
my problem is that, I do not know if introducing the input files and call for output files is done in a correct way or not. in fact I think the problem of this script is in this part:
input = args.infile
output = convert(args.infile)
do you know how to fix the script?
this is the problem I get after running the script:
Traceback (most recent call last):
File "bam2bg.py", line 39, in <module>
main()
File "bam2bg.py", line 35, in main
input = args.infile
AttributeError: 'Namespace' object has no attribute 'infile'
Windows 10, Python 3.5.1 x64 here.
This is weird... Let's say I have this script, called do.py. Please note the import string statement:
import string
# Please note that if the print statement is OUTSIDE 'main()', it works.
# It's like if 'main()' can't see the imported symbols from 'string'
def main():
print(string.ascii_lowercase)
main()
I want to run it from a "launcher script", in a subthread, like this (launcher.py):
import sys
import threading
sys.argv.append('do.py')
def run(script, filename):
exec(compile(script, filename, 'exec'))
with open(sys.argv[1], 'rb') as _:
script = _.read()
# But this WORKS:
# exec(compile(script, sys.argv[1], 'exec'))
thread = threading.Thread(name='Runner', target=run, args=(script, sys.argv[1]))
thread.start()
thread.join()
It dies with the following error:
Exception in thread Runner:
Traceback (most recent call last):
File "C:\Program Files\Python35\lib\threading.py", line 914, in _bootstrap_inner
self.run()
File "C:\Program Files\Python35\lib\threading.py", line 862, in run
self._target(*self._args, **self._kwargs)
File "tmpgui.py", line 7, in run
exec(compile(script, filename, 'exec'))
File "do.py", line 6, in <module>
main()
File "do.py", line 4, in main
print(string.ascii_lowercase)
NameError: name 'string' is not defined
That is, the exec'ed code is not importing string properly or something like that, and within main() the string module is not visible.
This is not the full code of my project, which is too big to post here, but the bare minimum I've created which mimics the problem.
Just in case someone is curious, I'm rewriting an old program of mine which imported the main() function of a script and ran that function with the standard output streams redirected to a tkinter text box. Instead of importing a function from the script, I want to load the script and run it. I don't want to use subprocess for a whole variety of reasons, I prefer to run the "redirected" code in a thread and communicate with the main thread which is the one handling the GUI. And that part works perfectly, the only problem I have is this and I can't understand why is happening!
My best bet: I should be passing something in globals or locals dictionaries to exec, but I'm at a lost here...
Thanks a lot in advance!
exec(thing) is equivalent to exec(thing, globals(), locals()).
Thus,
the local symbol table of do.py is the local symbol table of the run function
the global symbol table of do.py is the global symbol table of launcher.py
import string imports the module and binds it to the variable in the local space, which is the local space of the run function. You can verify this:
def run(script, filename):
try:
exec(compile(script, filename, 'exec'))
finally:
assert 'string' in locals(), "won't fail because 'import' worked properly"
main has a separate local scope, but it shares the global symbol table with do.py and, consequently, with launcher.py.
Python tried to find the variable named string inside both local (it's empty) and global symbol tables of main, but failed, and raised the NameError.
Pass one empty dictionary in a call to exec:
def run(script, filename):
exec(compile(script, filename, 'exec'), {})
I'm sure that the answer for this is out there, but I've read the site info, I've watched the video they made and I've tried to find a really basic tutorial but I can't. I've been messing about with this for most of the day and It's not really making sense to me.
Here's my error:
vco#geoHP:~$ python3 a_blah.py "don't scare the cats" magic
Traceback (most recent call last):
File "a_blah.py", line 20, in <module>
arguments = docopt.docopt(__doc__)
File "/usr/lib/python3/dist-packages/docopt.py", line 579, in docopt
raise DocoptExit()
docopt.DocoptExit: Usage:
a_blah.py <start>... <end>
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "a_blah.py", line 33, in <module>
except DocoptExit:
NameError: name 'DocoptExit' is not defined
line 20 - I don't see why that line is creating an error, it worked before and I've seen that exact line in others programmes?
I don't know why the line 570 of docopt is creating an error - I've seen others use DocoptExit(), isn't this something that's just part of Docopt? Do I have to write my own exit function for this? (I've not seen anyone else do that)
here's the code
import docopt
if __name__ == '__main__':
try:
arguments = docopt.docopt(__doc__)
print(arguments['<start>'])
print("that was that")
print(arguments['<end>'])
except docopt.DocoptExit:
print("this hasn't worked")
What I'm trying to make this for is a script that I've written that moves files from one place to another based on their extension.
So the arguments at the command line will be file type, start directory, destination directory, and an option to delete them from the start directory after they've been moved.
I'm trying (and failing) to get docopt working on it's own prior to including it in the other script though.
The exception you want is in docopt's namespace. You never import it into your global namespace, so you can't refer to it simply with it's name. You need to import it separately or refer to it through the module. You also shouldn't use parenthesis after the exception.
import docopt
try:
# stuff
except docopt.DocoptExit:
# other stuff
or
import docopt
from docopt import DocoptExit
try:
# stuff
except DocoptExit:
# other stuff
I'm having a problem with the Python multiprocessing package. Below is a simple example code that illustrates my problem.
import multiprocessing as mp
import time
def test_file(f):
f.write("Testing...\n")
print f.name
return None
if __name__ == "__main__":
f = open("test.txt", 'w')
proc = mp.Process(target=test_file, args=[f])
proc.start()
proc.join()
When I run this, I get the following error.
Process Process-1:
Traceback (most recent call last):
File "C:\Python27\lib\multiprocessing\process.py", line 258, in _bootstrap
self.run()
File "C:\Python27\lib\multiprocessing\process.py", line 114, in run
self.target(*self._args, **self._kwargs)
File "C:\Users\Ray\Google Drive\Programming\Python\tests\follow_test.py", line 24, in test_file
f.write("Testing...\n")
ValueError: I/O operation on closed file
Press any key to continue . . .
It seems that somehow the file handle is 'lost' during the creation of the new process. Could someone please explain what's going on?
I had similar issues in the past. Not sure whether it is done within the multiprocessing module or whether open sets the close-on-exec flag by default but I know for sure that file handles opened in the main process are closed in the multiprocessing children.
The obvious work around is to pass the filename as a parameter to the child process' init function and open it once within each child (if using a pool), or to pass it as a parameter to the target function and open/close on each invocation. The former requires the use of a global to store the file handle (not a good thing) - unless someone can show me how to avoid that :) - and the latter can incur a performance hit (but can be used with multiprocessing.Process directly).
Example of the former:
filehandle = None
def child_init(filename):
global filehandle
filehandle = open(filename,...)
../..
def child_target(args):
../..
if __name__ == '__main__':
# some code which defines filename
proc = multiprocessing.Pool(processes=1,initializer=child_init,initargs=[filename])
proc.apply(child_target,args)