【问题标题】:correct way to find scripts directory from setup.py in Python distutils?在 Python distutils 中从 setup.py 中找到脚本目录的正确方法?
【发布时间】:2012-10-10 03:27:42
【问题描述】:

我正在分发具有这种结构的包:

mymodule:
  mymodule/__init__.py
  mymodule/code.py
  scripts/script1.py
  scripts/script2.py

mymodulemymodule 子目录包含代码,scripts 子目录包含用户可执行的脚本。

setup.py 中描述包安装时,我使用:

scripts=['myscripts/script1.py']

指定脚本应该去哪里。在安装过程中,它们通常进入某个平台/用户特定的bin 目录。我在mymodule/mymodule 中的代码需要调用脚本。然后找到这些脚本的完整路径的正确方法是什么?理想情况下,它们应该在用户的路径上,所以如果我想从 shell 中调用它们,我应该能够做到:

os.system('script1.py args')

但我想通过其绝对路径调用脚本,而不是依赖于 PATH 上的平台特定 bin 目录,如下所示:

# get the directory where the scripts reside in current installation
scripts_dir = get_scripts_dir()
script1_path = os.path.join(scripts_dir, "script1.py")
os.system("%s args" %(script1_path))

如何做到这一点?谢谢。

EDIT 删除脚本之外的代码对我来说不是一个实用的解决方案。原因是我将作业分发到集群系统,而我通常这样做的方式是这样的:假设您有一组要运行的任务。我有一个脚本,它将所有任务作为输入,然后调用另一个脚本,该脚本仅在给定任务上运行。比如:

main.py:
for task in tasks:
  cmd = "python script.py %s" %(task)
  execute_on_system(cmd)

所以main.py 需要知道script.py 在哪里,因为它需要是execute_on_system 可执行的命令。

【问题讨论】:

  • execute_on_system() 长什么样子?
  • @PiotrDobrogost:execute_on_system 将对应于 shell 命令的字符串作为输入。然后它会创建一个名为cmd.sh 的临时文件,并在其中放入命令,以及说明作业应该如何运行的必要前缀(特定于用户系统上使用的集群系统)——例如,作业应该进入哪个队列in 等。然后它接受这个脚本 cmd.sh 并以系统特定的方式执行它,例如通过这样做:os.system("qsub cmd.sh")
  • 看来问题源于您坚持从cmd.sh shell 脚本运行 Python 脚本。如果我在上面理解你将cmd.sh 脚本传输到目标机器,任务将在其中运行。不能用同样的方式转移script.py,让你知道这个脚本在目标机器上的位置吗?

标签: python setuptools distutils setup.py distribute


【解决方案1】:

我认为你应该构建你的代码,这样你就不需要从你的代码中调用脚本。将您需要的代码从脚本移动到您的包中,然后您可以从您的脚本和代码中调用此代码。

【讨论】:

  • 我喜欢这个想法,但实际上它对我不起作用,请参阅即将进行的编辑
  • 我在您的工作流程中看不到任何内容阻止将某些代码从脚本移动到包中。
  • 我需要能够创建一个调用 Python 脚本的命令,这是我的包的一部分。类似“python myscript.py someargs”的东西。因此,我需要知道 在哪里 myscript.py 生活......即使 myscript.py 是包的一部分,而不是在脚本目录中,我仍然需要使用像 __file__ 这样的黑客找出脚本在哪里。从设计的角度来看,这会比试图找出脚本目录的位置更好吗?两种解决方案似乎都不优雅
【解决方案2】:

我的用例是检查我的脚本安装到的目录是否在用户的路径中,如果不是,则发出警告(因为如果使用 --user 安装,它通常不在路径中)。这是我想出的解决方案:

from setuptools.command.easy_install import easy_install

class my_easy_install( easy_install ):

    # Match the call signature of the easy_install version.
    def write_script(self, script_name, contents, mode="t", *ignored):

        # Run the normal version
        easy_install.write_script(self, script_name, contents, mode, *ignored)

        # Save the script install directory in the distribution object.
        # This is the same thing that is returned by the setup function.
        self.distribution.script_install_dir = self.script_dir

...

dist = setup(...,
             cmdclass = {'build_ext': my_builder,  # I also have one of these.
                         'easy_install': my_easy_install,
                        },
            )

if dist.script_install_dir not in os.environ['PATH'].split(':'):
    # Give a sensible warning message...

我应该指出,这是针对 setuptools 的。如果你使用 distutils,那么解决方案类似,但略有不同:

from distutils.command.install_scripts import install_scripts

class my_install_scripts( install_scripts ):  # For distutils
    def run(self):
        install_scripts.run(self)
        self.distribution.script_install_dir = self.install_dir

dist = setup(...,
             cmdclass = {'build_ext': my_builder,
                         'install_scripts': my_install_scripts,
                        },
            )

【讨论】:

    【解决方案3】:

    我认为正确的解决方案是

    scripts=glob("myscripts/*.py"),
    

    【讨论】:

      猜你喜欢
      • 2011-09-02
      • 2016-02-29
      • 2021-03-02
      • 1970-01-01
      • 2018-03-21
      • 1970-01-01
      • 2022-11-02
      • 2012-10-05
      • 2013-10-19
      相关资源
      最近更新 更多