如何正确获取console_scripts install_scripts目录?

时间:2019-01-21 13:06:22

标签: python pip package setuptools setup.py

伙计,

我将复杂的Python脚本拆分为一个程序包,以便于维护和分发。我使用setup.py入口点和包结构创建了一个全新的setupmeta(使用console_scripts)。到目前为止,一切都很好。

不过,我有一些不寻常的要求:

  • 该软件包始终安装在virtualenvwrapper项目中,
  • 因此脚本已安装在${VIRTUAL_ENV}/bin目录中...
  • ...并且我必须${VIRTUALENVWRAPPER_PROJECT_PATH}/bin目录中创建一个针对脚本的符号链接。 (不要问...:-)

为此,

  1. 我在locate_project_path()脚本中添加了setup.py函数,
  2. 将以下install_and_symlink_script子类添加到setuptools.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)                        
    
  3. 并通过以下方式配置setup()

    setup(
        ...
        entry_points={
            "console_scripts": ["%s=myscriptpackage.cli:main" % SCRIPT_NAME],
        },
        cmdclass={
            "install": install_and_symlink_script,
        },
        ...
    )
    

在执行本地python ./setup.py install时,软件包安装和符号链接创建可以完美运行。

但是执行pip install git+ssh://.../myscriptpackage.git时失败:

...
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
...

含义,当通过pip而不是python ./setup.py install安装时:

  1. 它无法检测到现有的符号链接,并取消链接。
  2. install_and_symlink_script.install_scripts变量指向构建目录内的脚本 而不是最终脚本安装目录...:-|

那么...您知道一种获取正确的脚本安装目录的方法,该目录与pip installpython ./setup.py install兼容吗?

(顺便说一句,我正在使用python 2.7.13,setuptools 39.1.0,Debian 9下的virtualenvwrapper 4.8.2)

更新1

我知道error: [Errno 17] File exists的问题来自于os.path.exists(symlink_path)的电话。

我只是理解为什么:如果从以前的安装中创建了符号链接,则在新安装期间该符号链接会中断。 os.path.exists对于断开的符号链接返回False。 OTOH,如果符号链接存在,损坏或不存在,os.path.lexists返回True

2 个答案:

答案 0 :(得分:0)

我怀疑您机器上的管理员权限可能是一个问题。 能否请您尝试在管理员模式下运行cmd,然后转到setup.py所在的路径后,即可运行:

 python setup.py 

接下来,它尝试在文件夹中创建符号链接

build/bdist.linux-x86_64/wheel/myscriptpackage-0.4.0.data/scripts/my-script

I request you to try making symlink on your own in this folder.

如果这不是解决方案,则说明版本不匹配。 请告诉我是否有帮助

答案 1 :(得分:0)

当使用python ./setup.py install函数通过pip installwheel.paths.get_install_paths()安装时,我找到了一种一致获取脚本安装目录的方法。

我的setuptools自定义安装命令现在是:

...
from wheel.paths import get_install_paths

__title__ = "myscriptpackage"
...

class install_and_symlink_script(install):                            
    """Do normal install, but symlink script to project directory"""  

    def run(self):                                                    
        install.run(self)                                             

        wheel_install_paths = get_install_paths(__title__)            
        script_path = os.path.join(wheel_install_paths['scripts'], SCRIPT_NAME)                  
        # instead of: 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.lexists(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)