python module and command line program - python

I have a code which I'd like people to be able to use as a stand alone python program, or to import as a module for their own codes. Is there a way to package a module which can also include a program that can be run from the command line?
I.e. from the command-line:
> ZHermesCode
or within ipython or a python script:
import ZHermesCode

Look up Setuptools automatic script creation. For example, python-scss uses this technique to make scss an executable shell command.
In setup.py:
setup(
# ...
entry_points={
'console_scripts': [
'scss = scss.tool:main',
]
},
)
Then defining a function main in scss/tool.py. It also uses the technique mentioned by Loocid to make the tool.py file itself directly executable (as opposed to the wrapper script that is publicly installed by setuptools according to the recipe above):
if __name__ == '__main__':
main()

If you use:
if name == '__main__':
The code held in that 'if' statement will only be ran if someone runs your program from the command line.
If someone was to import your module instead, the code will not run.
Eg
def test(st):
return(st)
if name == "__main__":
print(test("hello"))
If you run this program from the command line, it will print "hello". However, someone could also import this module and have access to the "test" function to use in their own programs.

Related

Python distutils.core.run_setup fails when running from within script?

I'm trying to run a Python setup script from within a python script. That is, instead of:
python path_to/setup.py build --build-base="build_dir" install --prefix="install_dir"
which works fine. I want to be able to call
from distutils.core import run_setup
args = ['build', '--build-base="build_dir"', 'install', '--prefix="install_dir"']
run_setup("path_to/setup.py", script_args=args, stop_after='run')
from within another Python script (as automated/on the fly installation). This does not seem to work at the moment as the call returns the error
RuntimeError: 'distutils.core.setup()' was never called
-- perhaps 'setup.py' is not a Distutils setup script?
which is strange since calling it from outside the script works. Is there something wrong with this approach? The setup.py script looks normal:
from distutils.core import setup
from distutils.command.build_py import build_py
# ...
if __name__ == '__main__':
setup( ... )
Alternatively, I'm thinking about just calling "subprocess" from the script, but then want to ensure I'm using the same Python instance/runtime as the running Python instance (in case many python versions are installed). How could I do this, ensure to call the top command from a subprocess with the same python?

How to run module from command line?

Suppose there is a module somewhere, which I can import with
from sound.effects import echo
How can I run echo directly from command line?
Command
python sound/effects/echo.py
does not work since the relative path is generally incorrect
If the module has top-level code executing on import, you can use the -m switch to run it from the command line (using Python attribute notation):
python -m sound.effect.echo
The module is then executed as a script, so a if __name__ == '__main__': guard will pass. See for example the timeit module, which executes the timeit.main() function when run from the command line like this.

Why different behaviors between running Python module as an executable vs. Python [filename]

So, I created a simple python module, test.py
import commands
def main():
cmd = 'ls -l'
(status, output) = commands.getstatusoutput(cmd)
print status, output
if __name__ == '__main__':
main()
When I ran it using "Python test.py", I got the result that I expected. But when I ran it as an executable (yes, it has the 'x' permission), the program didn't respond at all and I had to Ctrl+C to quit it. Why is that? Shouldn't both ways give the same result?
Add a hash-bang line to the top:
#!/usr/bin/env python
import commands
...
This tells your system what interpreter to use to execute the script. Without it it doesn't know if it's a shell script, Perl script, Python script, what.
You need the hashbang to be the first line of your script, referencing the path of the Python interpreter. Otherwise, all the OS knows is that you're trying to execute a script, and it has no idea how to go about doing that.

how do I use py2app?

Ok - here goes. I am trying to learn how to use py2app, so I created a simple python file; just hello_world.py
#! /usr/bin/env python
def main():
print "Hello"
if __name__=="__main__":
main()
I followed a tutorial and did the following:
py2applet --make-setup hello.py
python setup.py py2app -A
This created two sub-directories (build and dist), within dist there was a file called hello.app. I attempted to launch it through the GUI but it launched for less than a second and then disappeared. I then went to the CL but simply trying to run it didn't work so I used:
python hello.app
with the following error:
/Library/Frameworks/Python.framework/Versions/2.6/Resources/Python.app/Contents/MacOS/Python: can't find '__main__.py' in 'hello.app'
I've spent all day googling but can't find any tutorials or guides etc. I'm really stuck :-(
I don't know if this helps but this is what is in the setup.py
"""
This is a setup.py script generated by py2applet
Usage:
python setup.py py2app
"""
from setuptools import setup
APP = ['hello.py']
DATA_FILES = []
OPTIONS = {'argv_emulation': True}
setup(
app=APP,
data_files=DATA_FILES,
options={'py2app': OPTIONS},
setup_requires=['py2app'],
)
You have successfully used py2app - it just opens, prints "hello" and then closes really quickly!
If you want to see something, then make it pause for a bit:
print "Hello"
import time
time.sleep(5)
time.sleep pauses a program for the number of seconds given.
You really only want to use py2app with GUI apps, or ones that run in the background.
If you want to run the py2app-built application from the command line, you need to execute the binary inside the application bundle; the bundle itself is not directly executable, so something like this:
dist/hello.app/Contents/MacOS/hello
For scripts that just print to stdout you might try Platypus (though it doesn't do the dependency-packaging stuff of py2app).
It seems that it was working all along - the script was just running so quickly I didn't have a chance to see it. If anyone comes across this go to http://svn.pythonmac.org/py2app/py2app/trunk/doc/index.html and follow the tutorial. Please also read the answers given and the replies I left.

Does python's setuptools support the `__name__ == "__main__"` style of execution?

I'm just getting into packaging with setuptools, and it seems that the recommended way to install a python script along with one's module is to specify a script name that calls the name of a function, like this:
setup(
# ...
entry_points = {
"console_scripts": [
"script_name": "project.main:main",
],
}
)
This clearly precludes the standard way of making a python module executable, which is (last time I checked, which was a while ago) to use if __name__ == "__main__": do_stuff(). Does setuptools support this style, or should I switch to defining a main function and specifying it in entry_points?
It is: "script_name = project.main:do_stuff with setuptools
Setuptools creates scripts named script_name that imports and runs the function project.main:do_stuff, not run the script directly. You should re-read this part (alternate link, if you use Distribute) of the setuptools docs again to understand why it's this way. The script it creates contains if __name__ == "__main__" still. So yes, this is still the defacto way of making it execute.
This is a copy of easy_install installed with setuptools
#!/usr/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'distribute==0.6.14','console_scripts','easy_install'
__requires__ = 'distribute==0.6.14'
import sys
from pkg_resources import load_entry_point
if __name__ == '__main__':
sys.exit(
load_entry_point('distribute==0.6.14', 'console_scripts', 'easy_install')()
)
I think it's best to define an entry point and a script similar to easy_install. That imports and uses the entry point, like you show in your example if __name__ == "__main__": do_stuff(). It's great for debugging and early testing, also if you use distutils, there is no need to add/change anything. You can also have another app to call do_stuff() to access your app with out the overhead of running it in the shell, which is what setuptools is doing, distutils copy's the script.

Categories