Python3 -m 运行 Eclipse 中的配置

Python3 -m run configuration in Eclipse

2021 年更新解决方案内置于 PyDev/Eclipse

有关详细信息,请参阅已接受的答案

下面的原始问题(和旧答案)

SO 和其他地方的许多 comments/questions/rants 会告诉您,使用相对导入的 Python3 包希望 运行 来自中央 __main__.py 文件。如果模块在包中说“modA”,说“packA”,使用相对导入需要是 运行(例如,因为测试包是 运行 if __name__ == '__main__' ),如果 sys.path() 不包含 modA 上面的目录,我们会被告知 运行 而不是 modA 上面的目录中的 运行 python3 -m modA.packA。我可能不喜欢这种范式,但我可以解决它。

当尝试从 Eclipse/PyDev 运行 modA 时,我不知道如何指定 运行 配置来正确执行模块-m 标志。有没有人想出如何设置可以正确执行此操作的 运行 配置?

参考文献:Relative imports for the billionth time ; Relative import in Python 3 is not working ; Multilevel relative import

现在(自 PyDev 5.4.0 (2016-11-28))你可以去 Settings > PyDev > Run 和 select Launch modules with python -m mod.name 而不是 python filename.py ;)

参见:https://www.pydev.org/history_pydev.html


对于旧版本的 PyDev(旧答案)

不幸的是,现在,它在 PyDev 中不是自动的 运行 -m,所以,我将提供 3 个在 PyDev 中工作的选择,相对导入前面有一个 dot(在 PyDev 版本 4.3.0 中):

  1. 不要使用相对导入,只在 __main__ 模块中使用绝对导入。

  2. __main__ 创建一个单独的模块,它将对您想要 运行 和 运行 的模块进行绝对导入(如果您'分发您的应用程序,无论如何这可能是需要的,因为人们在 Python 中启动您的代码的通常方式是将脚本作为参数传递给 Python 而不是使用 -m开关)。

  3. 通过执行以下操作将 -m module 添加到 运行 配置中的 vm 参数:

  • 制作运行(由于相对导入会失败)
  • 右键单击编辑器 > 复制上下文限定名称
  • 打开运行配置:Alt、R、N(即:工具栏>运行>运行配置)
  • 打开参数选项卡并添加“-m Ctrl+V”(添加 -m 和您之前复制的模块名称)。

虽然这绝对不是理想的:你现在会收到一个带有文件名的参数(因为 PyDev 总是将它传递给 运行 文件)并且整个过程很麻烦。

请注意,我确实希望尽快提供一种使用 -m 在 PyDev 中制作 运行s 的方法(希望 PyDev 4.4.0)...虽然如果文件 运行 不在 PYTHONPATH 下这可能是不可能的(即:对于 运行 外部文件它仍然必须支持没有 [=13= 的选项]).

2021 年更新不再需要此答案。有关详细信息,请参阅已接受的答案。

这是在 Fabio 的伟大建议之后我能够做到的。

创建一个名为 /usr/local/bin/runPy3M 的程序,具有世界 read/execute 权限,代码如下:

#!/usr/local/bin/python3 -u
'''
Run submodules inside packages (with relative imports) given
a base path and a path (relative or absolute) to the submodule
inside the package.

Either specify the package root with -b, or setenv ECLIPSE_PROJECT_LOC.
'''

import argparse
import os
import re
import subprocess
import sys

def baseAndFileToModule(basePath, pyFile):
    '''
    Takes a base path referring to the root of a package
    and a (relative or absolute) path to a python submodule
    and returns a string of a module name to be called with
    python -m MODULE, if the current working directory is
    changed to basePath.

    Here the CWD is '/Users/cuthbert/git/t/server/tornadoHandlers/'.

    >>> baseAndFileToModule('/Users/cuthbert/git/t/', 'bankHandler.py')
    'server.tornadoHandlers.bankHandler'
    '''
    absPyFilePath = os.path.abspath(pyFile)
    absBasePath = None
    if basePath is not None:
        absBasePath = os.path.abspath(basePath)
        commonPrefix = os.path.commonprefix([absBasePath, absPyFilePath])
        uncommonPyFile = absPyFilePath[len(commonPrefix):]
    else:
        commonPrefix = ""
        uncommonPyFile = absPyFilePath 

    if commonPrefix not in sys.path:
        sys.path.append(commonPrefix)

    moduleize = uncommonPyFile.replace(os.path.sep, ".")
    moduleize = re.sub("\.py.?$", "", moduleize)
    moduleize = re.sub("^\.", "", moduleize)
    return moduleize    

def exitIfPyDevSetup():
    '''
    If PyDev is trying to see if this program is a valid
    Python Interpreter, it expects to function just like Python.
    This is a little module that does this if the last argument
    is 'interpreterInfo.py' and then exits.
    '''
    if 'interpreterInfo.py' in sys.argv[-1]:
        interarg = " ".join([sys.executable] + sys.argv[1:])
        subprocess.call(interarg.split())
        exit()
    return

exitIfPyDevSetup()

parser = argparse.ArgumentParser(description='Run a python file or files as a module.')
parser.add_argument('file', metavar='pyfile', type=str, nargs=1,
                   help='filename to run, with .py')
parser.add_argument('-b', '--basepath', type=str, default=None, metavar='path',
                   help='path to directory to consider the root above the package')
parser.add_argument('-u', action='store_true', help='unbuffered binary stdout and stderr (assumed)')
args = parser.parse_args()
pyFile = args.file[0]
basePath = args.basepath

if basePath is None and 'ECLIPSE_PROJECT_LOC' in os.environ:
    basePath = os.environ['ECLIPSE_PROJECT_LOC']

modName = baseAndFileToModule(basePath, pyFile)

allPath = ""
if basePath:
   allPath += "cd '" + basePath + "'; "

allPath += sys.executable
allPath += " -m " + modName 

subprocess.call(allPath, shell=True)  # maybe possible with runpy instead...

然后向 PyDev 添加一个新的解释器——将其命名为您喜欢的名称(例如,runPy3M)并将解释器指向 /usr/local/bin/runPy3M。点击确定。如果需要,然后将其移到列表中。然后添加到解释器的环境中,变量:ECLIPSE_PROJECT_LOC(此处的名称很重要),值为 ${project_loc}.

现在,选择此解释器的包内的子模块将 运行 作为与子包相关的模块。

我希望看到 baseAndFileToModule(basePath, pyFile) 最终作为另一个 运行 选项添加到 runpy,但这暂时有效。

编辑:不幸的是,在设置完所有这些之后,这个配置似乎阻止了 Eclipse/PyDev 识别诸如“None”、“True”、“False”、“ isinstnance," 等。所以不是一个完美的解决方案。

这里有一个有点讨厌的技巧可以解决这个问题。我正在使用 PyDev 9.2.0

将你的 venv 放在工作区中,比如在目录“venv”下。

刷新您的 eclipse 工作区并确保它使用此 venv(通过您的解释器设置)。

刷新后,转到 运行 配置并通过单击浏览按钮编辑“主模块”。 现在将出现 venv。

浏览到 venv/lib/python3.8/site-packages

在那里你会找到 pip 安装的模块源代码,你可以 select 你想要的模块 运行。