So I have an entry point defined in my setup.py [console_scripts] section. The command is properly installed and works fine, but I need a way to programatically find out the path to the script (e.g. on windows it'll be something like C:/my/virtual/env/scripts/my_console_script.exe). I need this so I can pass that script path as an argument to other commands, regardless of where the package is installed. Setuputils provides the pkg_resources
, but that doesn't seem to expose any way of actually getting at the raw installed paths, only loadable objects.
Edit: To make the use case plain here's the setup.
I have a plugin-driven application that communicates with various local services. One of these plug-ins ties into the alerting interface of an NMS package. The only way this alerting package can get alerts out to an arbitrary handler is to call a script - the path to execute (the console_scripts entry point in this case) is register as a complete path - that's the path I need to get.
Have you tried `os.path.abspath(__file__)' in your entry point script? It'll return yours entry point absolute path.
Or call
find_executable
fromdistutils.spawn
:import distutils.spawn distutils.spawn.find_executable('executable')
Well, you could pass an option of the form
--install-option="--install-scripts=/usr/local/bin"
topip
and just set the path yourself. But I understand why you might not want to hardcode that in a cross-platform project.So, we just need to find out what directory
setuptools
is actually using. Unfortunately, the path is determined in the middle of a whole bunch of actual setup code, rather than in a separate function we can just call.So the next step is to write a custom install command that observes and saves the path. (For that matter, you could also set
self.install_scripts
to a directory of your choice in this custom installer class, thereby keeping that piece of config in one place (the package) rather than in the package and in a command line arg to setup...)Example:
Possible objections:
Some people don't like any form of code generation. In this case it's more like configuration, though putting it in a
.py
in the package makes it easy to get at from Python code anywhere.On the surface it looks like a bit of a hack. However,
setuptools
is specifically designed to allow custom command classes. Nothing here is really accessing anything private, except maybe the value passing using thedistribution
object which is just to avoid aglobal
.Only gets the directory, not the executable names. You should know the names though, based on your entry point configuration. Getting the names would require calling the parsing methods for your entry point spec and generating more code.
It's going to need some bugfixing if you e.g. build without installing.
sdist
is safe though.develop
is possible but needs another command class.install
isn't called andbuild_py
is only called if you setuse_2to3
. A customdevelop
command can get the path as in theinstall
example, but asself.script_dir
. From there you have to decide if you're comfortable writing a file to your source directory, which is inself.egg_path
-- as it will get picked up byinstall
later, though it should be the same file (and the build command will overwrite the file anyway)Addendum
This little flash of insight may be more elegant as it does not require saving the path anywhere, but still gets the actual path setuptools uses, though of it assumes no configuration has changed since the install.
Addendum 2
Just realized/remembered that
pip
creates aninstalled-files.txt
in theegg-info
, which is a list of paths relative to the package root of all the files including the scripts.pkg_resources.get_distribution('mypackage').get_metadata('installed-files.txt')
will get this. It's only apip
thing though, not created bysetup.py install
. You'd need to go through the lines looking for your script name and then get the absolute path based on your package's directory.You could get the path for site_packages directory as follows:
If your script is somewhere relative to that path, either in site-packages or up a directory you could then join the relative path with the site-packages path as follows:
Another trick you could try is to import the associated module and then look at its file parameter. You could then look for your script the same way as the example above if you know what the relative path is to that file. Try it on the command line interface..
/usr/lib/python2.6/site-packages/django/init.pyc
Is the above advice on the right track?