如何正确获取 console_scripts install_scripts 目录?

How to properly get console_scripts install_scripts directory?

我将一个复杂的 Python 脚本拆分成一个包,以便于维护和分发。我创建了一个带有 console_scripts 入口点和包结构的新 setup.py(使用 setupmeta)。到目前为止,还不错。

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

为此目的:

  1. 我在setup.py脚本中添加了一个locate_project_path()函数,

  2. setuptools.command.install.install 添加了以下 install_and_symlink_script 子类:

    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 兼容?

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

更新 1

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

我刚刚明白了原因:如果符号链接是从以前的安装创建的,则该符号链接在新安装过程中会被破坏。 os.path.exists returns 错误的符号链接。 OTOH,os.path.lexists returns 如果符号链接存在,则为真,无论是否损坏...

我怀疑您机器上的管理员权限可能存在问题。 您能否在管理员模式下尝试 运行ning 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.

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

我找到了一种方法,可以在通过 python ./setup.py installpip install 安装时使用 wheel.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)