获取setuputils包中的入口点脚本文件位置?

Tyl*_*ves 10 python setuptools

所以我在setup.py [console_scripts]部分中定义了一个入口点.该命令已正确安装并正常工作,但我需要一种方法以编程方式找到脚本的路径(例如,在Windows上它将类似于C:/my/virtual/env/scripts/my_console_script.exe).我需要这个,所以我可以将该脚本路径作为参数传递给其他命令,无论软件包安装在何处.Setuputils提供了pkg_resources,但似乎没有暴露实际获取原始安装路径的任何方式,只有可加载对象.

编辑:要使用例是明确的设置.

我有一个插件驱动的应用程序,可以与各种本地服务进行通信.其中一个插件与NMS包的警报界面相关联.此警报包可以向任意处理程序发出警报的唯一方法是调用脚本 - 执行的路径(在本例中为console_scripts入口点)注册为完整路径 - 这是我需要获取的路径.

Jas*_*n S 7

嗯,你可以通过以下形式的选项--install-option="--install-scripts=/usr/local/bin"pip,只是为自己设定的路径.但我明白为什么你可能不想在跨平台项目中硬编码.

所以,我们只需要找出目录setuptools实际使用.不幸的是,路径是在一大堆实际设置代码的中间确定的,而不是在我们可以调用的单独函数中.

因此,下一步是编写一个观察并保存路径的自定义安装命令.(就此而言,你也可以在这个自定义安装程序类中设置 self.install_scripts一个你选择的目录,从而将该部分配置保存在一个地方(包)而不是在包中和命令行arg中设置... )

例:

from setuptools import setup
from setuptools.command.install import install
from distutils.command.build_py import build_py
import os

class InstallReadsScriptDir(install):
    def run(self):
        self.distribution._x_script_dir = self.install_scripts
        install.run(self)

class BuildConfiguresScriptDir(build_py):
    def run(self):
        build_py.run(self)
        if self.dry_run:
            return
        script_dir = self.distribution._x_script_dir  # todo: check exists
        target = os.path.join(self.build_lib, 'mypackage', 'scriptdir.py')
        with open(target, 'w') as outfile:
            outfile.write('path = """{}"""'.format(script_dir))

setup(
    name="MyPackage",
    version='0.0.1',
    packages = ['mypackage'],
    entry_points = {
        'console_scripts': [
            'footest = mypackage:main',
        ],
    },
    cmdclass= {
        'install': InstallReadsScriptDir,
        'build_py': BuildConfiguresScriptDir,
    },
)
Run Code Online (Sandbox Code Playgroud)

可能的反对意见:

  • 有些人不喜欢任何形式的代码生成.在这种情况下,它更像是配置,虽然将它放在.py包中可以很容易地从Python代码中获取.

  • 从表面上看,它看起来有点像黑客.但是,setuptools专门设计为允许自定义命令类.这里没有任何东西真正访问任何私有,除了可能使用distribution对象传递的值,这只是为了避免global.

  • 只获取目录,而不是可执行文件名.您应该根据入口点配置知道名称.获取名称需要调用入口点规范的解析方法并生成更多代码.

  • 如果您在没有安装的情况下进行构建,则需要一些错误修正.sdist虽然很安全.

  • develop是可能的,但需要另一个命令类.install没有被调用,build_py只有在你设置时才被调用use_2to3.自定义develop命令可以获取install示例中的路径,但是self.script_dir.从那里你必须决定你是否愿意将文件写入你的源目录,self.egg_path因为它将在install以后被提取,尽管它应该是相同的文件(并且build命令将覆盖文件无论如何)

附录

这个小小的洞察力可能更优雅,因为它不需要在任何地方保存路径,但仍然获得实际路径setuptools使用,但它假设自安装以来没有配置发生变化.

from setuptools import Distribution
from setuptools.command.install import install

class OnlyGetScriptPath(install):
    def run(self):
        # does not call install.run() by design
        self.distribution.install_scripts = self.install_scripts

def get_setuptools_script_dir():
    dist = Distribution({'cmdclass': {'install': OnlyGetScriptPath}})
    dist.dry_run = True  # not sure if necessary, but to be safe
    dist.parse_config_files()
    command = dist.get_command_obj('install')
    command.ensure_finalized()
    command.run()
    return dist.install_scripts
Run Code Online (Sandbox Code Playgroud)

附录2

刚刚意识到/记住,pip创建一个installed-files.txtegg-info,这是相对于所有文件,包括脚本的包根的路径列表.pkg_resources.get_distribution('mypackage').get_metadata('installed-files.txt')会得到这个.这只是一pip件事,而不是由创造setup.py install.您需要遍历查找脚本名称的行,然后根据程序包的目录获取绝对路径.