由于SO和其他地方的许多评论/问题/咆哮都会告诉您,使用相对导入的Python3包需要从中央__main__.py
文件运行。在模块的情况下,说" modA"在一个包中,比如" packA",需要运行相对导入(例如因为运行测试包if __name__ == '__main__'
),我们被告知运行而不是运行python3 -m modA.packA
如果modA
不包含sys.path()
上方的目录,请从上面的目录modA
开始。我可能不喜欢这种范式,但我可以解决它。
但是,当尝试从Eclipse / PyDev运行modA
时,我无法弄清楚如何指定将使用-m
标志正确执行模块的运行配置。有没有人想出如何设置一个能够正确执行此操作的运行配置?
参考文献:Relative imports for the billionth time; Relative import in Python 3 not working; Multilevel relative import
答案 0 :(得分:2)
不幸的是,现在,它并没有在PyDev中自动运行-m
,因此,我将提供3个选择在PyDev中使用相对导入,前面有dot
(在PyDev版本中) 4.3.0):
不要使用相对导入,只使用__main__
模块中的绝对导入。
为__main__
创建一个单独的模块,它将对您要运行的模块执行绝对导入并改为运行该模块(如果您正在分发应用程序,则可能需要这样做人们在Python中启动代码的通常方法是将脚本作为参数传递给Python,而不是使用-m
开关。
通过执行以下操作将-m module
添加到运行配置中的vm参数:
虽然这绝对不理想:你现在会收到一个带有文件名的参数(因为PyDev会一直传递它来运行文件),整个过程都很麻烦。
作为一个说明,我希望尽快使用-m
(希望PyDev 4.4.0 )提供一种在PyDev中运行的方法......虽然这可能不是如果正在运行的文件不在PYTHONPATH下(例如:运行外部文件,它仍然必须支持没有-m
的选项)。
答案 1 :(得分:0)
这是我在Fabio的第三个建议之后能够做到的。
创建一个名为/usr/local/bin/runPy3M
的程序,具有全局读取/执行权限,使用以下代码:
#!/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识别内置组件,如“无”,“真”,“假”,“实例”等。所以不是完美的解决方案。