I'm working on Windows and developing an application that will be distributed to end users.
I have one setupttools distribution that contains a nandful of python packages. This distribution declares some console_scripts entrypoints that point to various functions in my code.
One of these entrypoints is destined to be an updater application. I currently am launching it as a child process using subprocess and specifying the full path to a python script.
What i'd like to do instead is use the generated setuptools entrypoint stub executable as the subprocess to launch.
I can get the entrypoint to my subapplication via something like:
import pkg_resources
updatefunc = pkg_resources.load_entry_point('iti_reporter', 'console_scripts', 'my_update_ui')
which gives me the python function for it. Is there any way to go from this function to the generated setuptools script wrapper that resides in my venv?
Thanks for the assistance.
Figured it out by just doing what the script would have done anyway:
def _get_entry_script(dist, entrytype, entryname):
import pkg_resources
mainfunc = pkg_resources.load_entry_point(dist, entrytype, entryname)
entry_load_script = """import sys; from pkg_resources import load_entry_point;
sys.exit(
load_entry_point('%s', '%s', '%s')()
)"""
script = entry_load_script%(dist, entrytype, entryname)
script = ''.join(x.strip() for x in script.split('\n') if x.strip())
return script
def _get_updater_script_arg_dev():
return _get_entry_script('mydist', 'console_scripts', 'mypkg_update_ui')
def launch_updater():
cmd = (os.path.abspath(sys.executable), '-c', _get_updater_script_arg_dev(), '--arg1', '--arg2')
return subprocess.Popen(cmd)
Related
So I'm trying to create a setup.py file do deploy a test framework in python.
The library has dependencies in pexpect and easy_install. So, after installing easy_install, I need to install s3cmd which is a tool to work with Amazon's S3.
However, to configure s3cmd I use pexpect, but if you want to run setup.py from a fresh VM, so we run into an ImportError:
import subprocess
import sys
import pexpect # pexpect is not installed ... it will be
def install_s3cmd():
subprocess.call(['sudo easy_install s3cmd'])
# now use pexpect to configure s3cdm
child = pexpect.spawn('s3cmd --configure')
child.expect ('(?i)Access Key')
# ... more code down there
def main():
subprocess.call(['sudo apt-get install python-setuptools']) # installs easy_install
subprocess.call(['sudo easy_install pexpect']) # installs pexpect
install_s3cmd()
# ... more code down here
if __name__ == "__main__":
main()
I know of course I could create a another file, initial_setup.py to have easy_install and pexpect installed, before using setup.py, but my question is: Is there a way to import pexpect before having it installed? The library will be installed before using it, but does the Python interpreter will accept the import pexpect command?
It won't accept it like that, but Python allows you to import things everywhere, not only in the global scope. So you can postpone the import until the time when you really need it:
def install_s3cmd():
subprocess.call(['easy_install', 's3cmd'])
# assuming that by now it's already been installed
import pexpect
# now use pexpect to configure s3cdm
child = pexpect.spawn('s3cmd --configure')
child.expect ('(?i)Access Key')
# ... more code down there
EDIT: there is a peculiarity with using setuptools this way, since the .pth file will not be reloaded until Python relaunches. You can enforce reloading though (found here):
import subprocess, pkg_resources
subprocess.call(['easy_install', 'pexpect'])
pkg_resources.get_distribution('pexpect').activate()
import pexpect # Now works
(Unrelated: I'd rather assume that the script itself is called with the needed privileges, not use sudo in it. That will be useful with virtualenv.)
I am newbie in python.
Could anybody answer what does __requires__ means in the following code?
Why would they put __requires__ = 'flower==0.4.0' in the beginning of the file?
#!/srv/virtualenvs/zeusenv/bin/python
__requires__ = 'flower==0.4.0'
import sys
from pkg_resources import load_entry_point
sys.exit(
load_entry_point('flower==0.4.0', 'console_scripts', 'flower')()
)
The __requires__ line is part of a generated console script. It has no meaning to Python itself, only the setuptools library uses this information.
Console scripts are python scripts defined in a python package metadata, and setuptools installs wrapper script files to let you run them as command line scripts. The flower file installed in your virtualenv is such a script, defined by the flower package setup.py file.
The pkg_resources module imported in the wrapper script inspects the value of __requires__ in the main script to make sure the correct version of the library is available and loaded before the load_entry_point function (or any other pkg_resources function) is run. It'll not install the version specified, it is assumed that that version is already installed on your system. It's purpose is to avoid loading incorrect, incompatible resources when the script runs and loads dependencies.
I want to force a script to be run with python -S, I'm defining the script using entry_points in the setup.py. Is there an option for this?
Thanks!
I don't think there is such option in setuptools. You could create a stub script and specify it in the scripts distutils option instead. Bases on Is it possible to set the python -O (optimize) flag within a script?:
#!/usr/bin/env python
from your_package.script import main
if __name__=="__main__":
import os, sys
sentinel_option = '--dont-add-no-site-option'
if sentinel_option not in sys.argv:
sys.argv.append(sentinel_option)
os.execl(sys.executable, sys.executable, '-S', *sys.argv)
else:
sys.argv.remove(sentinel_option)
main()
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.
I need to install a python module in the site packages that also will be used as a command line application. Suppose I have a module like:
app.py
def main():
print 'Dummy message'
if __name__ == '__main__':
main()
setup.py
import distutils
try:
from setuptools import setup
except ImportError:
from distutils.core import setup
if __name__ == '__main__':
setup(name = 'dummy',
version = '1.0',
packages = ['dummy'],
)
Creating the dist by:
setup.py sdist
Install:
setup.py install
And now I would like to use it as a command line application by opening the command window and typing just: dummy
Is it possible to create such application under windows without to carry out registering system pat variables and so on ...
You can use the options in setup.py to declare command line scripts. Please refer to this article. On Windows, the script will be created in "C:\Python26\Scripts" (if you didn't change the path) - lots of tools store their scripts there (e.g. "easy_install", "hg", ...).
Put the following in dummy.cmd:
python.exe -m dummy
Or is it dummy.app...
Oh well, it's one of those.