好吧,您可以将--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,
},
)
可能的反对意见:
有些人不喜欢任何形式的代码生成。在这种情况下,它更像是配置,尽管将其放在包中的 .py 中可以很容易地从任何地方的 Python 代码中获取。
从表面上看,它看起来有点像 hack。但是,setuptools 专门设计用于允许自定义命令类。这里没有真正访问任何私有的东西,除了使用distribution 对象传递的值可能只是为了避免global。
只获取目录,不获取可执行文件名。不过,根据您的入口点配置,您应该知道名称。获取名称需要调用入口点规范的解析方法并生成更多代码。
如果你需要一些错误修复,例如无需安装即可构建。不过sdist 是安全的。
develop 是可能的,但需要另一个命令类。 install 不被调用,build_py 仅在您设置 use_2to3 时被调用。自定义develop 命令可以像install 示例一样获取路径,但可以使用self.script_dir。从那里您必须决定是否愿意将文件写入源目录,该目录位于self.egg_path 中——因为稍后它将被install 拾取,尽管它应该是同一个文件(并且构建命令无论如何都会覆盖文件)
附录
这个小小的瞬间可能会更优雅,因为它不需要在任何地方保存路径,但仍然可以获得 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
附录 2
刚刚意识到/记得pip 在egg-info 中创建了一个installed-files.txt,这是一个相对于包括脚本在内的所有文件的包根目录的路径列表。 pkg_resources.get_distribution('mypackage').get_metadata('installed-files.txt') 会得到这个。这只是 pip 的东西,不是由 setup.py install 创建的。您需要逐行查找脚本名称,然后根据包的目录获取绝对路径。