Werkzeug: 从重新加载器调用的 Windows 控制台脚本

创建于 2017-06-13  ·  14评论  ·  资料来源: pallets/werkzeug

我在 python 3 上运行 apistar 并遇到了一个问题,导致我使用了 werkzeug 重新加载器。

(fresh) C:\Users\uskaxb07\PycharmProjects\testapi>apistar run
Starting up...
 * Restarting with stat
  File "C:\Users\uskaxb07\env\fresh\Scripts\apistar.exe", line 1
SyntaxError: Non-UTF-8 code starting with '\x90' in file C:\Users\uskaxb07\env\fresh\Scripts\apistar.exe on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details

从对run_simple()的调用中删除use_reloader run_simple()有效。 在深入研究了几条评论后,我发现https://github.com/pallets/werkzeug/blob/master/werkzeug/_reloader.py#L118正在对 latin1 进行一些编码,但仅当操作系统是 windows 和 python 版本时是 2. 这是否会导致我在 python3 中收到的非 UTF-8 语法错误?

所有14条评论

有没有我可以用来重现这个的小例子? 我不熟悉使用 apistar,也不经常使用 Windows。

我深入研究了一下。 问题实际上出在_get_args_for_reloading() 上。 该方法返回['python.exe', 'apistar.exe', 'run'] ,当传递给subprocess.call()生成该错误。 这与从命令行调用python.exe apistar.exe run没有什么不同。

所以问题不在于我最初认为的环境编码。 鉴于这在其他基于 werkzueg 的框架中很常见,我认为更改此方法以解决可以通过 console_script 生成的 .exe 调用的事实将使所有 Windows 用户受益。

我正在更改问题标题以解决此问题。

如果此方法在检查 windows 时处理了 rv 的 sys.executable 元素,则重新加载成功:

def _get_args_for_reloading():
    """Returns the executable. This contains a workaround for windows
    if the executable is incorrectly reported to not have the .exe
    extension which can cause bugs on reloading.
    """
    rv = [sys.executable]
    py_script = sys.argv[0]
    if os.name == 'nt' and not os.path.exists(py_script) and \
       os.path.exists(py_script + '.exe'):
        py_script += '.exe'
        rv.pop()
    rv.append(py_script)
    rv.extend(sys.argv[1:])
    return rv

如果您想提交 PR,我很乐意查看 PR。

我绝对愿意,但我有点坚持为此编写测试。 我只能看到它与 unittest.mock 库一起工作并修补 sys.executable 和 os.name,但我认为这不适用于您的项目,因为它也必须支持 27 中的自动化测试。 有什么建议吗?

另外这里使用的分支策略是什么? 问题的拉取请求是否与当前的维护分支背道而驰?

您可以从 0.12-maintenance 分支。 让我们先看看补丁是什么样子,然后找出测试。

我确实提交了一个拉取请求。 看起来 Travis CI 失败了,但原因与我所做的更改无关。 这是我的第一个 Pull Request,所以我不知道从哪里开始。

当您安装了 setuptools exe 启动器时,就会发生这种情况。 如果您通过最新的 pip 安装,它会安装一种新的 exe 启动器(来自distlib ),它将启动器脚本捆绑到 Python 可以直接执行的 zip 中的 exe 中( runpy docs )。

这并不意味着这不应该被修复,但如果您无法重现它,了解它会很有帮助。 例如,如果您在开发模式( pip install -e )下安装 Flask,它仍然会发生。

@androiddrew @davidism关于此公关的任何更新?

@segevfiner你能在你最近的评论中添加更多细节吗? 您是否建议我们应该在 setuptools 中而不是在 Flask 中修复根本原因?

@ewpete根本原因是在使用 setuptools 生成的启动器时,
sys.argv[0] 不能作为 Python 脚本执行,因为它是
启动器exe。 实际脚本的名称类似于带有 - “-script”的 exe
附加并且 exe 加载并运行它。

请注意,exe可以直接执行(Python脚本也是如此
我相信这是 setuptools 在 unices 上生成的 shebang)。 但
对 Windows 上的纯 Python 脚本这样做是不可靠的(当
pylauncher 未安装),因为它将使用任意 Python 启动
与注册表中的 .py 文件相关联,这可能不同
比我们正在使用的当前 Python。 当然,这同样适用于
我们可能被调用的任何随机 Python 脚本,甚至可能不是
可执行。

pip 安装(通过 distlib)一种新的 exe 启动器,它具有
生成的启动器脚本附加在文件末尾的 zip 中
可执行。 这将被检测为带有 __main__.py 脚本(A
zipapp) 并且可以直接传递给 Python 执行。

要在 setuptools 中解决此问题将意味着生成类似/相同的 kindbof
安装工具中的启动器。 本着http://xkcd.com/1172/的精神,这
可能会破坏需要 setuptools 启动器并尝试的代码
使用“*-script.py”文件来解决这个问题。 我没查
是否已经有关于此的问题/公关。

在这里有一个小的解决方法可能没问题,以便 Werkzeug
即使存在当前样式的设置工具,重新加载器也能正常工作
发射器。 但这真的取决于项目维护者。

בתאריך 28 בנוב' 2017 20:46, “ewpete”通知@github.com כתב:

@androiddrew https://github.com/androiddrew @davidism
https://github.com/davidism关于此 PR 的任何更新?

@segevfiner https://github.com/segevfiner你能补充一点吗
详细到您最近的评论? 你是不是建议我们应该
可能在 setuptools 中而不是在 Flask 中修复根本原因?


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/pallets/werkzeug/issues/1136#issuecomment-347623921
或静音线程
https://github.com/notifications/unsubscribe-auth/AXlg_8OSR3NdbPJzM87dyKPUAA9NpXJ6ks5s7FT7gaJpZM4N5Fcb
。这

@ewpete这是我的第一个 PR。 我尽力编写测试,遵循开发指南,并放置 PR。 我没有太多关于如何做到这一点的指导,但我确实根据公关评论做出了建议的更改。 我认为它已经完成,但从未收到关于它是否符合项目团队期望的回音。 从那以后就没有看过它,我不知道人们想用它做什么。

我在多个项目中的时间非常有限。 别担心,没有忘记这件事。

@davidism谢谢你,不仅是为了回应,而且是为了让这些项目保持活力!

虽然这仍未合并,但一种可能的临时修复方法是在使用_get_args_for_reloading()函数之前对其进行monkeypatch。 在 Flask 脚本的情况下,在manage.py文件的开头添加它有助于:

import werkzeug._reloader
import os, sys

def _get_args_for_reloading():
    rv = [sys.executable]
    py_script = sys.argv[0]
    if os.name == 'nt' and not os.path.exists(py_script) and \
       os.path.exists(py_script + '.exe'):
        py_script += '.exe'
    if os.path.splitext(rv[0])[1] == '.exe' and os.path.splitext(py_script)[1] == '.exe':
        rv.pop()
    rv.append(py_script)
    rv.extend(sys.argv[1:])
    return rv
werkzeug._reloader._get_args_for_reloading = _get_args_for_reloading
此页面是否有帮助?
0 / 5 - 0 等级

相关问题

abathur picture abathur  ·  13评论

paihu picture paihu  ·  7评论

KangOl picture KangOl  ·  16评论

golf-player picture golf-player  ·  10评论

caiz picture caiz  ·  3评论