python 不要碰我的shebang

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1530702/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 22:30:39  来源:igfitidea点击:

Don't touch my shebang

pythondistutilsvirtualenv

提问by Stefano Borini

One thing I hate about distutils(I guess he is the evil who does this) is that it changes the shebang line. In other words, the more rational and environment-vars decided scripture

我讨厌distutils 的一件事(我猜他是这样做的邪恶)是它改变了 shebang 线。换句话说,更理性和环境变量决定了圣经

#!/usr/bin/env python

gets magically converted into

被神奇地转换成

#!/whatever/absolute/path/is/my/python

This is seen also with grok: I used grokproject in a virtualenv to start my project, but now I cannot move the development directory around anymore, because it puts absolute paths in the shebang directive.

这也可以通过 grok 看到:我在 virtualenv 中使用了 grokproject 来启动我的项目,但现在我无法再移动开发目录,因为它在 shebang 指令中放置了绝对路径。

The reason why I ask this is twofold

我问这个的原因是双重的

  • I want to move it around because I started developing in one directory (Experiments) and now I want to move it into a proper path, but I could not do it. So I created a new virtualenv and grokproject and copied my files. That fixes the issue, but leaves my curiosity for a more rational solution unsatisfied. In particular, if the reference to the virtualenv python interpreter was relative, the problem would not have been present in the first place. You know the layout of the virtualenv, and you can refer to the virtualenv python easily.
  • The second reason is that I would like to be able to scp the virtualenv to another computer and run it there without trouble. This is not possible if you have hardcoded paths.
  • 我想移动它,因为我开始在一个目录(实验)中开发,现在我想将它移动到正确的路径,但我无法做到。所以我创建了一个新的 virtualenv 和 grokproject 并复制了我的文件。这解决了问题,但让我对更合理的解决方案的好奇心没有得到满足。特别是,如果对 virtualenv python 解释器的引用是相对的,那么问题就不会首先出现。你知道virtualenv的布局,你可以很容易地参考virtualenv python。
  • 第二个原因是我希望能够将 virtualenv scp 到另一台计算机并在那里毫无问题地运行它。如果您有硬编码路径,这是不可能的。

采纳答案by Lennart Regebro

Of course you can move the development directory around. Distutils changes the paths to the python that you should run with when you run it. It's in Grok run when you run the buildout. Move and re-run the bootstrap and the buildout. Done!

当然你可以移动开发目录。Distutils 更改了运行时应使用的 python 的路径。当您运行构建时,它在 Grok run 中。移动并重新运行引导程序和构建。完毕!

Distutils changes the path to the Python you use to run distutils with. If it didn't, then you might end up installing a library in one python version, but when you try to run the script it would fail, because it would run with another python version that didn't have the library.

Distutils 更改了用于运行 distutils 的 Python 的路径。如果没有,那么您最终可能会在一个 Python 版本中安装一个库,但是当您尝试运行该脚本时,它会失败,因为它将与另一个没有该库的 Python 版本一起运行。

That's not insanity, it's in fact the only sane way to do it.

这不是精神错乱,事实上这是唯一明智的做法。

Update: If you know what you are doing, you can do this:

更新:如果你知道你在做什么,你可以这样做:

/path/to/install/python setup.py build -e "/the/path/you/want/python" install

Make sure you clean the build directory first though. :)

不过,请确保先清理构建目录。:)

回答by jathanism

Distutils will automatically replace the shebang with the location of the Python binary that was used to execute setup.py. To override this behavior you have two options:

Distutils 将自动将 shebang 替换为用于执行 setup.py 的 Python 二进制文件的位置。要覆盖此行为,您有两个选择:

Option 1: Manually

选项 1:手动

You may pass the flag --executable=/path/to/my/pythonto setup.py. Arguments are accepted.

您可以将标志--executable=/path/to/my/python传递给 setup.py。接受参数。

Example:

例子:

% python setup.py build --executable=/opt/local/bin/python -d

Option 2: Automatically

选项 2:自动

Your other option is to add a line to setup.cfg. If you aren't using setup.cfg, create it in the same directory as setup.py. Setup.py looks for this on startup. Any options specified here can still be overridden with flags at the command-line.

您的另一个选择是在 setup.cfg 中添加一行。如果您不使用 setup.cfg,请在与 setup.py 相同的目录中创建它。Setup.py 在启动时寻找这个。此处指定的任何选项仍然可以用命令行中的标志覆盖。

% cat setup.cfg 
[build]
executable = /opt/local/bin/python -d

回答by edrabc

In one of the latest versions of distutils, there is a flag --no-autoreqthat have worked for me:

distutils的最新版本之一中,有一个标志--no-autoreq对我有用

--no-autoreq         do not automatically calculate dependencies

In my case, I was creating RPM files with python2.4 executable, in a server with both 2.4 and 2.6 installations. bdist just left the shebangs as they were, after running:

就我而言,我正在使用 python2.4 可执行文件在具有 2.4 和 2.6 安装的服务器中创建 RPM 文件。运行后,bdist 只是离开了shebangs:

python setup.py bdist_rpm --no-autoreq

In the case that you are handling the specfiles, you may use the solution explained at https://stackoverflow.com/a/7423994/722997, adding:

如果您正在处理规范文件,您可以使用https://stackoverflow.com/a/7423994/722997 中解释的解决方案,并添加:

AutoReq: no

回答by ede

had the same issue. tried to find a way to prevent the touching altogether by default. here is the solution. essentially we override the default script copy routine (build_scripts).

有同样的问题。试图找到一种默认情况下完全防止触摸的方法。这是解决方案。本质上,我们覆盖了默认的脚本复制例程(build_scripts)。

in setup.py add

在 setup.py 添加

from distutils.command.build_scripts import build_scripts

# don't touch my shebang
class BSCommand (build_scripts):
    def run(self):
        """
        Copy, chmod each script listed in 'self.scripts'
        essentially this is the stripped 
         distutils.command.build_scripts.copy_scripts()
        routine
        """
        from stat import ST_MODE
        from distutils.dep_util import newer
        from distutils import log
        import os

        self.mkpath(self.build_dir)
        outfiles = []
        for script in self.scripts:
            outfile = os.path.join(self.build_dir, os.path.basename(script))
            outfiles.append(outfile)

            if not self.force and not newer(script, outfile):
                log.debug("not copying %s (up-to-date)", script)
                continue

            log.info("copying and NOT adjusting %s -> %s", script,
                         self.build_dir)
            self.copy_file(script, outfile)

        if os.name == 'posix':
            for file in outfiles:
                if self.dry_run:
                    log.info("changing mode of %s", file)
                else:
                    oldmode = os.stat(file)[ST_MODE] & 0o7777
                    newmode = (oldmode | 0o555) & 0o7777
                    if newmode != oldmode:
                        log.info("changing mode of %s from %o to %o",
                                 file, oldmode, newmode)
                        os.chmod(file, newmode)

setup(name="name",
      version=version_string,
      description="desc",
      ...
      test_suite='testing',
      cmdclass={'build_scripts': BSCommand},
      )

.. ede/duply.net

.. ede/duply.net

回答by Stephan202

I have no solution to your problem, but I do see some rationale for the current behaviour of distutils.

我没有解决您的问题,但我确实看到了distutils当前行为的一些基本原理。

#!/usr/bin/env pythonexecutes the system's default Python version. That is fine as long as your code is compatible with said version. When the default version is updated (from 2.5 to 3, say) your code or other Python code which references /usr/bin/envmay stop working, even though the old Python version is still installed. For that reason it makes sense to "hardcode" the path to the appropriate python interpreter.

#!/usr/bin/env python执行系统的默认 Python 版本。只要您的代码与所述版本兼容就可以。当默认版本更新(例如从 2.5 到 3)时,您的代码或其他引用的 Python 代码/usr/bin/env可能会停止工作,即使仍然安装了旧的 Python 版本。出于这个原因,将路径“硬编码”到适当的 python 解释器是有意义的。

Edit:you are correct in asserting that specifying python2.4or similar solves this problem.

编辑:您断言指定python2.4或类似解决此问题是正确的。

Edit 2:things are not as clear cut when multiple installations of the same Python version are present, as Ned Deilypoints out in the comments below.

编辑 2:正如Ned Deily在下面的评论中指出的那样,当存在多个相同 Python 版本的安装时,事情就不那么明确了。