Windows Cmd.exe Window

G

Giles Brown

For my sins I'm a MS Windows user at work and apart from that I have a
small problem ...

I like to write python scripts to do small tasks and then double click
on them from the file explorer to run them.

Unfortunately I'm not perfect and sometimes I make mistakes and have
unhandled exceptions or syntax errors when running the scripts. The
default behaviour is to shut down the command window which leaves you
no chance of reading the exception.

In the past I have created .bat wrapper files that just call the python
interpreter, but it is a bit tedious to have to create a matching .bat
file for every script. So I came up with the following approach...

1. Copy python.exe to pythoncmd.exe
2. Add a bit of stuff to sitecustomize.py
3. Add a special first line to every python script and give it a .cmd
extension.

The stuff added to sitecustomize.py (actually I created a
sitecustomize.py for this) is:
"""
import sys
import os

if os.path.basename(sys.executable) == 'pythoncmd.exe':

def cmdexcepthook(*args):
sys.__excepthook__(*args)
# Let use confirm/inspect error
os.system('pause')

sys.excepthook = cmdexcepthook
"""

The special first line is:

@pythoncmd -x "%~f0" %* & exit /b

(In the python.org FAQ for windows it says
@setlocal enableextensions & python -x %~f0 %* & goto :EOF
but since I have no idea which is "right" I chose the simpler looking
one)

This approach does require pythoncmd.exe to by in your %PATH% but I
think that is reasonable ;)

I am a bit disappointed I couldn't think of a way of deciding if I was
running a ".cmd" file in sitecustomize.py so that I could just use the
normal python.exe. Using a renamed interpreter .exe is just a trick
for detecting when I am running .cmd files, but it means that the
script won't run on another machine that hasn't had the python.exe
copied to pythoncmd.exe on it. Which is a shame.

So my question. Is there a better way? I'm not really happy with this
approach. Should I stop worrying and go and play my new ukulele?
Answers please.

Giles
 
T

Thorsten Kampe

* Giles Brown (2005-07-07 13:56 +0100)
For my sins I'm a MS Windows user at work and apart from that I have a
small problem ...

I like to write python scripts to do small tasks and then double click
on them from the file explorer to run them.

Unfortunately I'm not perfect and sometimes I make mistakes and have
unhandled exceptions or syntax errors when running the scripts. The
default behaviour is to shut down the command window which leaves you
no chance of reading the exception.

In the past I have created .bat wrapper files that just call the python
interpreter, but it is a bit tedious to have to create a matching .bat
file for every script. So I came up with the following approach...

1. Copy python.exe to pythoncmd.exe
2. Add a bit of stuff to sitecustomize.py
3. Add a special first line to every python script and give it a .cmd
extension.

The stuff added to sitecustomize.py (actually I created a
sitecustomize.py for this) is:
"""
import sys
import os

if os.path.basename(sys.executable) == 'pythoncmd.exe':

def cmdexcepthook(*args):
sys.__excepthook__(*args)
# Let use confirm/inspect error
os.system('pause')

sys.excepthook = cmdexcepthook
"""

The special first line is:

@pythoncmd -x "%~f0" %* & exit /b

(In the python.org FAQ for windows it says
@setlocal enableextensions & python -x %~f0 %* & goto :EOF
but since I have no idea which is "right" I chose the simpler looking
one)

This approach does require pythoncmd.exe to by in your %PATH% but I
think that is reasonable ;)

I am a bit disappointed I couldn't think of a way of deciding if I was
running a ".cmd" file in sitecustomize.py so that I could just use the
normal python.exe. Using a renamed interpreter .exe is just a trick
for detecting when I am running .cmd files, but it means that the
script won't run on another machine that hasn't had the python.exe
copied to pythoncmd.exe on it. Which is a shame.

So my question. Is there a better way? I'm not really happy with this
approach. Should I stop worrying and go and play my new ukulele?
Answers please.

I think it's a FAQ to: use raw_input at the end to prevent closing.
 
G

Giles Brown

Nah. You're missing my point. I only want the command window not to
be closed if there is an *exception*. Picky I know, but there you go.

Giles
 
L

Larry Bates

Use sys.excepthook to hook a function you define and in that function
print a traceback and pause before exiting. Something like (not tested
but copied from working example):

import sys
def Myexcepthook(type, value, traceback):
print "in Myexcepthook-type=", type," value=",value," traceback=",traceback
import traceback
lines=traceback.format_exception(type, value, traceback)
print "---------------------Traceback lines-----------------------"
print "\n".join(lines)
print "-----------------------------------------------------------"
t=raw_input("Press return to continue")
sys.exit(2)

#
# set sys.excepthook
#
sys.excepthook=Myexcepthook
#
# create an uncaught divide by zero exception
#
a=1/0


-Larry Bates
 
H

harold fellermann

Nah. You're missing my point. I only want the command window not to
be closed if there is an *exception*. Picky I know, but there you go.

well, then register raw_input as exit function:

works fine in my terminal. should do in your framework also.

cheers,

- harold -
 
H

harold fellermann

well, then register raw_input as exit function:


works fine in my terminal. should do in your framework also.

sorry, I did not think. if you want to wait for input _only_ if
an exception occured, your exit function needs to check for the
exception:
.... import sys
.... if sys.exc_type :
.... raw_input()
....
this should do the job, now.

- harold -
 
G

Giles Brown

Thanks for your replies.

I think we might have a miscommunication here as (to my understanding)
neither of your replies actually solve my problem.

After all, the function raw_input is just another way of blocking until
user input. I was already doing that using "os.system('pause')".

To recap, what I'm looking for is a way of setting up specific scripts
(not every script) so that when I double click on it, it runs, but if
there is an exception (even a SyntaxError in the top level script) I
get a traceback in a window that doesn't disappear immediately.

The tricky elements of this are:
1) It can't be done using code in the script itself (such as using an
import statement) because in the presence of a SyntaxError the import
statement is never run. This is why I was looking at sitecustomize.py
2) I don't want to do unusual exception/atexit hooking for every script
and so need to be able to detect when I am running one of these .cmd
type scripts.

I hope this clarifies things. I had hoped that my question was worded
sufficiently well to indicate this wasn't a straight-down-the-line
newbie question (I've been programming in Python for seven years now).
Obviously it wasn't. My apologies.

Giles
 
T

Thomas Heller

Giles Brown said:
Nah. You're missing my point. I only want the command window not to
be closed if there is an *exception*. Picky I know, but there you go.

I find it useful to set an sys.excepthook which calls the debugger
pdb.pm(). This way I not only see the traceback, but I can also poke
around in the environment to find the problem.

Thomas
 
G

Giles Brown

Hi Larry,
I mentioned how I am already using "sys.excepthook" in my initial
posting.
What I'm looking for is:
1) Is there any better way of solving the problem than setting
sys.excepthook in sitecustomize.py?
2) Or is there a better way of detecting when I am running a .cmd based
script than the method I proposed?
Hope this clears up what I'm asking for.
Thanks,
Giles
 
D

Duncan Booth

harold said:
sorry, I did not think. if you want to wait for input _only_ if
an exception occured, your exit function needs to check for the
exception:

... import sys
... if sys.exc_type :
... raw_input()
...

this should do the job, now.

Did you think to test your code before posting it?

sys.exc_type is deprecated (you should use sys.exc_info() instead), but
neither will tell you whether the program is exiting as a result of an
exception when called from an atexit function, by the time the atexit
function is called the exception is no longer accessible.

As Larry Bates suggested, the OP needs to use a sys.excepthook.
Unfortunately he doesn't test his code either (the parameter 'traceback'
conflicts with the module 'traceback'), but at least the principle is
correct.
 
D

Duncan Booth

Giles said:
The special first line is:

@pythoncmd -x "%~f0" %* & exit /b

(In the python.org FAQ for windows it says
@setlocal enableextensions & python -x %~f0 %* & goto :EOF
but since I have no idea which is "right" I chose the simpler looking
one)

This approach does require pythoncmd.exe to by in your %PATH% but I
think that is reasonable ;)

I am a bit disappointed I couldn't think of a way of deciding if I was
running a ".cmd" file in sitecustomize.py so that I could just use the
normal python.exe. Using a renamed interpreter .exe is just a trick
for detecting when I am running .cmd files, but it means that the
script won't run on another machine that hasn't had the python.exe
copied to pythoncmd.exe on it. Which is a shame.

I'm having problems understanding your problem. If the file is a .cmd
file then surely the second line (i.e. the one immediately following the
python -x command) could simply do "import sethook" where sethook would
be a module that sets your excepthook.

Alternatively you could check at any point whether sys.argv[0] ends with
'.cmd' or '.bat' (after lowercasing).
So my question. Is there a better way? I'm not really happy with
this approach. Should I stop worrying and go and play my new ukulele?
Answers please.

Go on, upload some ukulele playing somewhere.

BTW, another solution is to push the pause command out to the shell:

-----------------------
@setlocal enableextensions & (python -x %~f0 %* || pause) & goto :EOF

import sys
if len(sys.argv) > 1:
sys.exit("this will pause")
 
G

Giles Brown

Hooray! We have a winner!

Thanks Duncan. Your improved shell line will do the job very nicely.
:)

(btw, the problem with "import sethook" at the top of the script is
that syntax errors in the top-level will prevent the import from being
run meaning we don't get our traceback anymore.)

Giles
 
G

Giles Brown

Addendum - forgot to mention that the problem with checking the
extension of sys.argv[0] is that sys.argv[0] is not set until after
sitecustomize.py is run (and it needs to be in sitecustomize.py not an
imported module due to the top-level SyntaxError problem mentioned in
my other post).

Cheers again for your elegant solution.
Giles
 
B

brian

In the past I have created .bat wrapper files that just call the python
interpreter, but it is a bit tedious to have to create a matching .bat
file for every script. So I came up with the following approach...

I frequently use a batch file wrapper. Typically it has a long
friendly name for others in my (non-IT) department, and calls the
actual python script in a subfolder, often with arguments. The last
line of the batch file is usually a pause command.

As an alternative, I have a couple of main procedures wrap a try/except
around the entire script, and if an error occurs, then logs the details
before quitting. I suppose you could also print the error, and add a
call raw_input() so its visible before the window closes.

Hope that helps,
Brian.
 
P

Peter Herndon

Giles, you keep mentioning syntax errors as the (/a) cause of the
problem. I suggest you avoid such problems, so that the import sethook
approach, et al. will actually work. The easiest thing to do is to run
PyChecker on your script prior to executing it. PyChecker will catch
your syntax errors (and a whole host of other things, some of which are
actual problems, some not) and let you know where they are. With that
simple bit of testing, the other approaches that rely on a
syntactically-correct script will work, because you will have corrected
the syntax errors.

You *will* have corrected the syntax errors, right? :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top