Ben Finney <ben+deb...@benfinney.id.au> writes: > How can I specify to Pybuild that an application should have its > modules all in a private namespace, but have the Distutils metadata > also available to `pkg_resources` queries?
I've made a real, minimal example of a Debian package of a Python distribution, with the properties I've described. * The ‘console_scripts’ entry point is used to specify command line programs, ‘lorem’ and ‘ipsum’, using that Distutils feature. Those are the correct names for the commands, so I don't want to mess with that. * The ‘--install-lib’ option is used in ‘PYBUILD_INSTALL_ARGS’ to place the Python packages in an application-private directory, ‘/usr/share/foo-app/’. The point of that is so they won't be on the Python module search path. * The ‘--install-scripts’ option is *not* used, because Distutils places the constructed scripts in the correct directory (‘/usr/bin/’) by default. * The script names are correct, but are identical to names of directories in the ‘/usr/share/foo-app/’ top level. That's another good reason not to use the ‘--install-scripts’ option. It is also normal and expected, and shouldn't be a problem because the scripts will not exist there; they belong in ‘/usr/bin/’. * The console scripts constructed by Distutils call the function ‘pkg_resources.load_entry_point’. That requires that the Distutils metadata (the ‘FooApp-1.2.3.egg-info/’ directory) be available to that function. According to Robert's earlier message, that means the Distutils metadata file needs to be not in the application's private directory, but in a directory on the Python module search path. That seems odd to me, since this is not amodule import being done. What happens is that the Distutils metadata also gets hidden away in the private directory. Then the ‘pkg_resources.load_entry_point’ function tries to find the distribution, and can't because it's not in the Python module search path. So what i'm looking for is a way to tell Distutils at install time: * Install the Python libraries to this specific private path that isn't part of the Python module search path” (‘--install-lib’). * Ensure the Distutils metadata can be found by these specific console scripts (and, ideally, not by others) when they run. Either: * Construct the console scripts, at install time, to load the Distutils metadata at run time from that same private directory where Distutils installed it. Or: * Construct the Distutils metadata, at install time, such that it points to the private directory for these libraries. Put this metadata where it will be found at run time. * Install the scripts to the default, public script install location. That facility would ideally be an option I can just add to ‘PYBUILD_INSTALL_ARGS’. Here is the output from the example. I can provide the files if anyone wants to experiment. ===== $ pwd /home/bignose/Projects/debian/foo-app-1.2.3 $ find . . ./setup.py ./lorem ./lorem/amet.py ./lorem/dolor.py ./lorem/sit.py ./lorem/__init__.py ./ipsum ./ipsum/elit.py ./ipsum/adipiscing.py ./ipsum/consecteur.py ./ipsum/__init__.py ./debian ./debian/compat ./debian/rules ./debian/changelog ./debian/control $ cat ./setup.py from setuptools import (setup, find_packages) setup( name="FooApp", version="1.2.3", packages=find_packages(), entry_points={ 'console_scripts': [ "lorem = FooApp.lorem.dolor:main", "ipsum = FooApp.ipsum.consecteur:main", ], }, ) $ cat ./debian/rules #! /usr/bin/make -f export PYBUILD_INSTALL_ARGS ?= --install-lib=/usr/share/foo-app/ %: dh $@ --with=python2 --buildsystem=pybuild $ ./debian/rules clean dh clean --with=python2 --buildsystem=pybuild dh_testdir -O--buildsystem=pybuild dh_auto_clean -O--buildsystem=pybuild I: pybuild base:170: python2.7 setup.py clean running clean removing '/home/bignose/Projects/debian/foo-app-1.2.3/.pybuild/pythonX.Y_2.7/build' (and everything under it) 'build/bdist.linux-x86_64' does not exist -- can't clean it 'build/scripts-2.7' does not exist -- can't clean it dh_clean -O--buildsystem=pybuild $ fakeroot ./debian/rules binary dh binary --with=python2 --buildsystem=pybuild dh_testroot -O--buildsystem=pybuild dh_prep -O--buildsystem=pybuild dh_auto_install -O--buildsystem=pybuild I: pybuild base:170: /usr/bin/python setup.py install --root /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app --install-lib=/usr/share/foo-app/ running install running build running build_py running install_lib creating /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr creating /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr/share creating /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr/share/foo-app creating /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr/share/foo-app/ipsum copying /home/bignose/Projects/debian/foo-app-1.2.3/.pybuild/pythonX.Y_2.7/build/ipsum/elit.py -> /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr/share/foo-app/ipsum copying /home/bignose/Projects/debian/foo-app-1.2.3/.pybuild/pythonX.Y_2.7/build/ipsum/adipiscing.py -> /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr/share/foo-app/ipsum copying /home/bignose/Projects/debian/foo-app-1.2.3/.pybuild/pythonX.Y_2.7/build/ipsum/consecteur.py -> /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr/share/foo-app/ipsum copying /home/bignose/Projects/debian/foo-app-1.2.3/.pybuild/pythonX.Y_2.7/build/ipsum/__init__.py -> /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr/share/foo-app/ipsum creating /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr/share/foo-app/lorem copying /home/bignose/Projects/debian/foo-app-1.2.3/.pybuild/pythonX.Y_2.7/build/lorem/amet.py -> /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr/share/foo-app/lorem copying /home/bignose/Projects/debian/foo-app-1.2.3/.pybuild/pythonX.Y_2.7/build/lorem/dolor.py -> /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr/share/foo-app/lorem copying /home/bignose/Projects/debian/foo-app-1.2.3/.pybuild/pythonX.Y_2.7/build/lorem/sit.py -> /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr/share/foo-app/lorem copying /home/bignose/Projects/debian/foo-app-1.2.3/.pybuild/pythonX.Y_2.7/build/lorem/__init__.py -> /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr/share/foo-app/lorem byte-compiling /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr/share/foo-app/ipsum/elit.py to elit.pyc byte-compiling /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr/share/foo-app/ipsum/adipiscing.py to adipiscing.pyc byte-compiling /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr/share/foo-app/ipsum/consecteur.py to consecteur.pyc byte-compiling /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr/share/foo-app/ipsum/__init__.py to __init__.pyc byte-compiling /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr/share/foo-app/lorem/amet.py to amet.pyc byte-compiling /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr/share/foo-app/lorem/dolor.py to dolor.pyc byte-compiling /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr/share/foo-app/lorem/sit.py to sit.pyc byte-compiling /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr/share/foo-app/lorem/__init__.py to __init__.pyc running install_egg_info running egg_info creating FooApp.egg-info writing FooApp.egg-info/PKG-INFO writing top-level names to FooApp.egg-info/top_level.txt writing dependency_links to FooApp.egg-info/dependency_links.txt writing entry points to FooApp.egg-info/entry_points.txt writing manifest file 'FooApp.egg-info/SOURCES.txt' reading manifest file 'FooApp.egg-info/SOURCES.txt' writing manifest file 'FooApp.egg-info/SOURCES.txt' Copying FooApp.egg-info to /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr/share/foo-app/FooApp-1.2.3.egg-info running install_scripts Installing ipsum script to /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr/bin Installing lorem script to /home/bignose/Projects/debian/foo-app-1.2.3/debian/foo-app/usr/bin dh_installdocs -O--buildsystem=pybuild dh_installchangelogs -O--buildsystem=pybuild dh_python2 -O--buildsystem=pybuild dh_perl -O--buildsystem=pybuild dh_link -O--buildsystem=pybuild dh_compress -O--buildsystem=pybuild dh_fixperms -O--buildsystem=pybuild dh_installdeb -O--buildsystem=pybuild dh_gencontrol -O--buildsystem=pybuild dh_md5sums -O--buildsystem=pybuild dh_builddeb -O--buildsystem=pybuild dpkg-deb: building package 'foo-app' in '../foo-app_1.2.3-1_all.deb'. $ sudo dpkg -i ../foo-app_1.2.3-1_all.deb (Reading database ... 812074 files and directories currently installed.) Preparing to unpack .../debian/foo-app_1.2.3-1_all.deb ... Unpacking foo-app (1.2.3-1) over (1.2.3-1) ... Setting up foo-app (1.2.3-1) ... $ dpkg --listfiles foo-app /. /usr /usr/bin /usr/bin/ipsum /usr/bin/lorem /usr/share /usr/share/doc /usr/share/doc/foo-app /usr/share/doc/foo-app/changelog.Debian.gz /usr/share/python /usr/share/python/runtime.d /usr/share/python/runtime.d/foo-app.rtupdate /usr/share/foo-app /usr/share/foo-app/FooApp-1.2.3.egg-info /usr/share/foo-app/FooApp-1.2.3.egg-info/top_level.txt /usr/share/foo-app/FooApp-1.2.3.egg-info/dependency_links.txt /usr/share/foo-app/FooApp-1.2.3.egg-info/entry_points.txt /usr/share/foo-app/FooApp-1.2.3.egg-info/PKG-INFO /usr/share/foo-app/ipsum /usr/share/foo-app/ipsum/elit.py /usr/share/foo-app/ipsum/adipiscing.py /usr/share/foo-app/ipsum/consecteur.py /usr/share/foo-app/ipsum/__init__.py /usr/share/foo-app/lorem /usr/share/foo-app/lorem/amet.py /usr/share/foo-app/lorem/dolor.py /usr/share/foo-app/lorem/sit.py /usr/share/foo-app/lorem/__init__.py $ cat /usr/bin/lorem #!/usr/bin/python # EASY-INSTALL-ENTRY-SCRIPT: 'FooApp==1.2.3','console_scripts','lorem' __requires__ = 'FooApp==1.2.3' import sys from pkg_resources import load_entry_point if __name__ == '__main__': sys.exit( load_entry_point('FooApp==1.2.3', 'console_scripts', 'lorem')() ) $ /usr/bin/lorem Traceback (most recent call last): File "/usr/bin/lorem", line 5, in <module> from pkg_resources import load_entry_point File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 3084, in <module> @_call_aside File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 3070, in _call_aside f(*args, **kwargs) File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 3097, in _initialize_master_working_set working_set = WorkingSet._build_master() File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 651, in _build_master ws.require(__requires__) File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 952, in require needed = self.resolve(parse_requirements(requirements)) File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 839, in resolve raise DistributionNotFound(req, requirers) pkg_resources.DistributionNotFound: The 'FooApp==1.2.3' distribution was not found and is required by the application ===== -- \ “Absurdity, n. A statement or belief manifestly inconsistent | `\ with one's own opinion.” —Ambrose Bierce, _The Devil's | _o__) Dictionary_, 1906 | Ben Finney