I splitted a complex Python script into a package for easier maintenance and distribution. I created a fresh setup.py (using setupmeta) with a console_scripts entry point and the package structure. So far, so good.
I had some unusual requirements, though:
- the package is to always be installed in a
virtualenvwrapperproject, - so the script is installed in the
${VIRTUAL_ENV}/bindirectory... - ...and I must create a symlink targetting the script in the
${VIRTUALENVWRAPPER_PROJECT_PATH}/bindirectory. (don't ask... :-)
For that purpose:
I added a
locate_project_path()function in thesetup.pyscript,added the following
install_and_symlink_scriptsubclass tosetuptools.command.install.install:class install_and_symlink_script(install): """Do normal install, but symlink script to project directory""" def run(self): install.run(self) script_path = os.path.join(self.install_scripts, SCRIPT_NAME) project_path = locate_project_path() symlink_path = os.path.join(project_path, "bin", SCRIPT_NAME) print("creating %s script symlink" % SCRIPT_NAME) if os.path.exists(symlink_path): print("removing existing symlink %s" % symlink_path) os.unlink(symlink_path) print("creating symlink from %s to %s" % ( symlink_path, script_path)) os.symlink(script_path, symlink_path)and configured
setup()this way:setup( ... entry_points={ "console_scripts": ["%s=myscriptpackage.cli:main" % SCRIPT_NAME], }, cmdclass={ "install": install_and_symlink_script, }, ... )
When performing a local python ./setup.py install, the package installation and symlink creation works perfectly.
But when performing a pip install git+ssh://.../myscriptpackage.git, it fails:
...
running install_egg_info
Copying src/myscriptpackage.egg-info to build/bdist.linux-x86_64/wheel/myscriptpackage-0.4.0-py2.7.egg-info
running install_scripts
creating my-script script symlink
creating symlink from /path/to/virtualenvwrapper/project/bin/my-script to build/bdist.linux-x86_64/wheel/myscriptpackage-0.4.0.data/scripts/my-script
error: [Errno 17] File exists
error
Failed building wheel for myscriptpackage
...
Meaning, when installing through pip instead of a python ./setup.py install:
- it fails to detect an existing symlink, and unlink it.
- the
install_and_symlink_script.install_scriptsvariable point to the script inside the build directory instead of the final scripts installation directory... :-|
So... do you know a way to get the correct scripts installation directory, compatible with both a pip install and a python ./setup.py install ?
(Btw, I'm using python 2.7.13, setuptools 39.1.0, virtualenvwrapper 4.8.2 under Debian 9)
UPDATE 1
I knew the error: [Errno 17] File exists issue was coming from the os.path.exists(symlink_path) call.
I just understood why: if a symlink was created from a previous install, that symlink is broken during the new install. os.path.exists returns False for a broken symlink. OTOH, os.path.lexists returns True if the symlink exists, broken or not...
python ./setup.py install, the script is correctly installed in the${VIRTUAL_ENV}/bin/directory and the symlink created in the${PROJECT_PATH}/bin/directory. (thesetuptools.command.install.install.install_scriptsvariable is set to${VIRTUAL_ENV}/bin/directory). With apip install, thesetuptools.command.install.install.install_scriptsvariable is set to a directory inside a wheel, in the build directory, not the to${VIRTUAL_ENV}/bin/directory. I need apip installto work correctly, as my package has to be included in arequirements.txtfile.