How to run a python script without specifying the file extension (cross platform solution)?
Asked Answered
D

6

9

Let's say that we have a Python script do.py and we want to be able to call it without extension, like do or ./do.

If we rename the file from do.py to do and assure we have a valid shebang line it will work for all platforms but Windows. On Windows there is no way of executing file without extension.

On Windows, if we keep the original file extension we'll be able to call the script without the full name because the Python installer registers the .py extension as an executable one.

It looks that we need to deliver the same script under two different names in order to be call it on Windows and non-Windows environments. I really do not like this and I'm looking for a solution without this redundancy.

Another common approach on this is to add a do.cmd wrapper batch file that is calling the original do.py file. This has at least one major issue: it does break the Ctrl+C / Ctrl+Break because there is no way to prevent cmd.exe from prompting you with Terminate batch job? (Y/N) message.

If we are about to use a wrapper we need to be sure that:

  • return the errorcode (errorlevel) returned by the original script
  • it will not change the environment
  • it will reuse the same console (no new windows)
  • doesn't interfere with STDOUT, STDIN or STDERR
  • be friendly with Ctrl-C (no prompts)

I suppose the optimal solution is still to use a wrapper. Batch won't work, native executable would add a lot of complexity so probably a wrapper wrote in python itself would do.

Distilled answered 27/2, 2010 at 10:49 Comment(4)
may be answer lies in the question "why you want to be able to call it without extension" ?Waterloo
Wow, what a lot of work for no real benefit. What's wrong with do.py? That's perfectly cross platform with no work at all.Unkindly
For those who are wondering: without extension means that we hide implementation details: for example if next year I want to replace current Python script with a Ruby script I don't want be need to change all calls to the script. Another less important argument: less to write from command line.Distilled
On Windows, if we keep the original file extension we'll be able to call the script without the full name because the Python installer registers the .py extension as an executable one Not true. Registering the extension doesn't allow calling the script without giving the extension. For this you need also to add the extension to the PATHEXT environment variable as RoMa suggested.Accommodating
D
2

So far I came up with this solution that seams to work. Create a file yourname.py with this content:

import os, sys
filename = os.path.splitext(os.path.basename(sys.argv[0]))[0]
if not os.path.exists(filename):
    # filename does not exists, we will emulate cmd behaviour
    sys.stderr.write("'%s' is not recognized as an internal or external command,\noperable program or batch file." % filename)
    sys.exit(9009)
ret = os.system("python %s %s" % (
        filename,
        " ".join(sys.argv[1:])
        ))
exit(ret)
Distilled answered 27/2, 2010 at 15:24 Comment(1)
M
5

On windows i added the '.py' extension to the 'PATHEXT' environment variable and that works for me - if the .py file is stored in an directory that is part of the 'PATH' environment variable.

C:\>echo %PATHEXT%
.COM;.EXE;.BAT;.CMD;.PY;.JS;.JSE
Mihrab answered 27/2, 2010 at 16:22 Comment(2)
This worked for me in command shells but for the Run prompt I had to add a fake "python_script.exe" key to the registry - HKLM\Software\Microsoft\Windows\CurrentVersion\App Paths\ Then I set the default value to my python_script.py path and then I was able to just type "python_script" in the Run prompt.Thorstein
But how does this also work on non-Windows? Can I type do without the extension?Rota
G
5

Write your main Python module with a .py extension. Set up PATHEXT correctly, and it will run on Windows without having to type the extension.

On Unix, write a second Python program that simply imports the first, using she-bang syntax. No extension on this file - it's a shell script. Like this:

#!/usr/bin/env python
import do

This will have the effect of importing do.py.

Only do needs to be marked as executable for Unix. do.py is a module in that environment.

When you import a module, the code in the module is run once.

It doesn't completely remove redundancy, but it's close. And it is probably the best solution possible for cross-platform scripting.

Globuliferous answered 28/8, 2010 at 19:55 Comment(1)
It's symmetrical solution to the one given by OP but it's simpler thus seems to be better.Accommodating
D
2

So far I came up with this solution that seams to work. Create a file yourname.py with this content:

import os, sys
filename = os.path.splitext(os.path.basename(sys.argv[0]))[0]
if not os.path.exists(filename):
    # filename does not exists, we will emulate cmd behaviour
    sys.stderr.write("'%s' is not recognized as an internal or external command,\noperable program or batch file." % filename)
    sys.exit(9009)
ret = os.system("python %s %s" % (
        filename,
        " ".join(sys.argv[1:])
        ))
exit(ret)
Distilled answered 27/2, 2010 at 15:24 Comment(1)
A
1

You can use distutils to install scripts into the Python installation (the easy_install tool is installed like that, for example).

For Windows, you can use py2exe to create a script that can be executed without file extension. On Linux you can simply use a file without extension, but including a shebang line.

Adverb answered 27/2, 2010 at 11:6 Comment(1)
If you install the script you can run it with python -m moduleName. That's cross-platform, also.Unkindly
A
0

you can always call your script with the Python interpreter. You get the same consistency in *nix, when you use the interpreter.

Windows

c:\> python c:\path\to\myscript 

*nix

$ python /path/to/myscript

If its not what you want, then i am mis-interpreting your question.

Annunciata answered 27/2, 2010 at 10:56 Comment(1)
That's not what he wants. He wants to run it like any other executable in the system - without specifying anything but the name of executable (script) in the command line.Accommodating
R
0

Jason's answer is clearer and simpler, but a generic version gets the module name from the filename:

#!/usr/bin/env python
import importlib, os, sys
importlib.import_module(os.path.basename(sys.argv[0]))

Having said that, I prefer Jason's where it's immediately clear what's going on:

#!/usr/bin/env python
import do
Rota answered 25/2, 2014 at 9:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.