在标准输入上使用相对导入的Python 3脚本给出错误:没有名为'__main__.XXX'的模块; '__main__'不是一个包

时间:2019-04-28 22:14:45

标签: python-3.x python-import elpy

在标准输入上使用相对导入的Python 3脚本会产生错误:没有名为' main .XXX'的模块; “ 主要”不是软件包

如果我有一个使用以下形式的相对import语句的Python 3脚本


<TableRow key={n.id}>    
    <TableCell 
        component="th" 
        align="center"
        scope="row">
        <Chip 
            label={n.procedure} 
            variant="outlined" 
            color="primary"
            clickable={true}
            onClick={this.chipFilter} />
    </TableCell>

    <TableCell align="center">
        <Chip 
            label={n.doctor} 
            variant="outlined" 
            color="primary"
            clickable={true}
            onClick={this.chipFilter} />
    </TableCell>
        .
        .
        .
</TableRow>

以及其他一些脚本将上述脚本作为模块导入,它可以正常工作。但是,当我在Python解释器的标准输入上执行包含上述行的脚本时,出现以下错误:

from .subscript2 import subfunc2

我需要使用stdin的原因是,因为我需要使用Elpy(https://elpy.readthedocs.io/en/latest/),使我能够评估该脚本(使用Cc Cc键绑定),然后添加其他Python代码以在其中调用函数该脚本,类似于pdb'interact'命令。

下面是用于演示正在发生的事情的自包含脚本:

ModuleNotFoundError: No module named '__main__.subscript2'; '__main__' is not a package

以下是上面的输出:

#!/bin/bash

rm -rf /tmp/topdir
mkdir /tmp/topdir
mkdir /tmp/topdir/subdir

unset PYTHONPATH

cat > /tmp/topdir/topscript.py <<'EOF'
from subdir.subscript1 import subfunc1
EOF

touch /tmp/topdir/subdir/__init__.py

cat > /tmp/topdir/subdir/subscript1.py <<'EOF'
from .subscript2 import subfunc2

def subfunc1():
    subfunc2()

print('subscript1 loaded successfully')
EOF

cat > /tmp/topdir/subdir/subscript2.py <<'EOF'
import os
def subfunc2():
    print('subfunc2 called. Current working directory: {}'.format(os.getcwd()))

print('subscript2 loaded successfully')
subfunc2()
EOF

echo
echo ////////////////////////////////////////////////////////////////////////////////
echo Python version:
echo ////////////////////////////////////////////////////////////////////////////////
python --version

cd /tmp
echo
echo ////////////////////////////////////////////////////////////////////////////////
echo Direct execution of topscript.py from inside $(pwd)
echo ////////////////////////////////////////////////////////////////////////////////
python /tmp/topdir/topscript.py

cd /tmp/topdir
echo
echo ////////////////////////////////////////////////////////////////////////////////
echo Using stdin on topscript.py from inside $(pwd):
echo ////////////////////////////////////////////////////////////////////////////////
python < topscript.py

cd /tmp/topdir/subdir
echo
echo ////////////////////////////////////////////////////////////////////////////////
echo Using stdin on subscript1.py from inside $(pwd):
echo ////////////////////////////////////////////////////////////////////////////////
python < subscript1.py

cd /tmp/topdir/subdir
echo
echo ////////////////////////////////////////////////////////////////////////////////
echo Using -m subscript1 from inside $(pwd):
echo ////////////////////////////////////////////////////////////////////////////////
python -m subscript1

cd /tmp/topdir/subdir
echo
echo ////////////////////////////////////////////////////////////////////////////////
echo Using stdin on subscript2.py from inside $(pwd):
echo ////////////////////////////////////////////////////////////////////////////////
python < subscript2.py

# This one was added in response to https://stackoverflow.com/a/55895684/257924
cd /tmp/topdir
echo
echo ////////////////////////////////////////////////////////////////////////////////
echo Using -m on subdir.subscript1 from inside $(pwd):
echo ////////////////////////////////////////////////////////////////////////////////
python -m subdir.subscript1

# This one is a variation of https://stackoverflow.com/a/55895684/257924 using symlinks:
cd /tmp/topdir/subdir
echo
echo ////////////////////////////////////////////////////////////////////////////////
echo "Using -m on selfdir.subscript1 from inside $(pwd) (where selfdir is a symlink):"
echo ////////////////////////////////////////////////////////////////////////////////
ln -s ../subdir selfdir
python -m selfdir.subscript1

我尝试了各种方法,但无法提出解决方案。我所能做的最好是删除开头的“。”像这样:

////////////////////////////////////////////////////////////////////////////////
Python version:
////////////////////////////////////////////////////////////////////////////////
Python 3.7.3

////////////////////////////////////////////////////////////////////////////////
Direct execution of topscript.py from inside /tmp
////////////////////////////////////////////////////////////////////////////////
subscript2 loaded successfully
subfunc2 called. Current working directory: /tmp
subscript1 loaded successfully

////////////////////////////////////////////////////////////////////////////////
Using stdin on topscript.py from inside /tmp/topdir:
////////////////////////////////////////////////////////////////////////////////
subscript2 loaded successfully
subfunc2 called. Current working directory: /tmp/topdir
subscript1 loaded successfully

////////////////////////////////////////////////////////////////////////////////
Using stdin on subscript1.py from inside /tmp/topdir/subdir:
////////////////////////////////////////////////////////////////////////////////
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named '__main__.subscript2'; '__main__' is not a package

////////////////////////////////////////////////////////////////////////////////
Using -m subscript1 from inside /tmp/topdir/subdir:
////////////////////////////////////////////////////////////////////////////////
Traceback (most recent call last):
  File "/home/drunkard/conda/Ubuntu.18.04.miniconda3/envs/envpython3/lib/python3.7/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/home/drunkard/conda/Ubuntu.18.04.miniconda3/envs/envpython3/lib/python3.7/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/tmp/topdir/subdir/subscript1.py", line 1, in <module>
    from .subscript2 import subfunc2
ImportError: attempted relative import with no known parent package

////////////////////////////////////////////////////////////////////////////////
Using stdin on subscript2.py from inside /tmp/topdir/subdir:
////////////////////////////////////////////////////////////////////////////////
subscript2 loaded successfully
subfunc2 called. Current working directory: /tmp/topdir/subdir

////////////////////////////////////////////////////////////////////////////////
Using -m on subdir.subscript1 from inside /tmp/topdir:
////////////////////////////////////////////////////////////////////////////////
subscript2 loaded successfully
subfunc2 called. Current working directory: /tmp/topdir
subscript1 loaded successfully

////////////////////////////////////////////////////////////////////////////////
Using -m on selfdir.subscript1 from inside /tmp/topdir/subdir (where selfdir is a symlink):
////////////////////////////////////////////////////////////////////////////////
subscript2 loaded successfully
subfunc2 called. Current working directory: /tmp/topdir/subdir
subscript1 loaded successfully

但它破坏了正常执行:

from subscript2 import subfunc2

为了使上述工作有效,我必须在环境中将//////////////////////////////////////////////////////////////////////////////// Python version: //////////////////////////////////////////////////////////////////////////////// Python 3.7.3 //////////////////////////////////////////////////////////////////////////////// Direct execution of topscript.py from inside /tmp //////////////////////////////////////////////////////////////////////////////// Traceback (most recent call last): File "/tmp/topdir/topscript.py", line 1, in <module> from subdir.subscript1 import subfunc1 File "/tmp/topdir/subdir/subscript1.py", line 1, in <module> from subscript2 import subfunc2 ModuleNotFoundError: No module named 'subscript2' //////////////////////////////////////////////////////////////////////////////// Using stdin on topscript.py from inside /tmp/topdir: //////////////////////////////////////////////////////////////////////////////// Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/tmp/topdir/subdir/subscript1.py", line 1, in <module> from subscript2 import subfunc2 ModuleNotFoundError: No module named 'subscript2' //////////////////////////////////////////////////////////////////////////////// Using stdin on subscript1.py from inside /tmp/topdir/subdir: //////////////////////////////////////////////////////////////////////////////// subscript2 loaded successfully subfunc2 called. Current working directory: /tmp/topdir/subdir subscript1 loaded successfully //////////////////////////////////////////////////////////////////////////////// Using -m subscript1 from inside /tmp/topdir/subdir: //////////////////////////////////////////////////////////////////////////////// subscript2 loaded successfully subfunc2 called. Current working directory: /tmp/topdir/subdir subscript1 loaded successfully //////////////////////////////////////////////////////////////////////////////// Using stdin on subscript2.py from inside /tmp/topdir/subdir: //////////////////////////////////////////////////////////////////////////////// subscript2 loaded successfully subfunc2 called. Current working directory: /tmp/topdir/subdir //////////////////////////////////////////////////////////////////////////////// Using -m on subdir.subscript1 from inside /tmp/topdir: //////////////////////////////////////////////////////////////////////////////// Traceback (most recent call last): File "/home/drunkard/conda/Ubuntu.18.04.miniconda3/envs/envpython3/lib/python3.7/runpy.py", line 193, in _run_module_as_main "__main__", mod_spec) File "/home/drunkard/conda/Ubuntu.18.04.miniconda3/envs/envpython3/lib/python3.7/runpy.py", line 85, in _run_code exec(code, run_globals) File "/tmp/topdir/subdir/subscript1.py", line 1, in <module> from subscript2 import subfunc2 ModuleNotFoundError: No module named 'subscript2' //////////////////////////////////////////////////////////////////////////////// Using -m on selfdir.subscript1 from inside /tmp/topdir/subdir (where selfdir is a symlink): //////////////////////////////////////////////////////////////////////////////// subscript2 loaded successfully subfunc2 called. Current working directory: /tmp/topdir/subdir subscript1 loaded successfully 设置为包含我使用的所有脚本的目录的冒号分隔列表。对于我自己的脚本,这将起作用,但是,一旦我想通过stdin将其他已发布的脚本读入python,除非我浏览这些脚本并删除初始的“”,否则它将再次中断。暂时(这很麻烦且容易出错)。

那么,有没有办法使所有这些情况都可行?我确实可以选择更改我正在使用的工具(将脚本提供给python的stdin的工具),以便在实际脚本之前 将其他代码添加到该stdin流中,但是如果是这样的话解决方案,哪些语句将迫使它起作用?

有助于理解的有用参考资料,但这并未揭示解决方案:

2 个答案:

答案 0 :(得分:1)

您需要在-m subdir.subscript1中使用topdirsubdir文件夹是一个软件包,当您使用-m时,需要为要运行的模块提供完全限定的名称,否则就无法确定它应该是其中的一部分。软件包而不是顶层模块。

尝试一下:

echo
echo ////////////////////////////////////////////////////////////////////////////////
echo Using -m on subscript1.py:
echo ////////////////////////////////////////////////////////////////////////////////
cd /tmp/topdir                        # note, changed folder here
python -m subdir.subscript1           # add package name prefix here

答案 1 :(得分:0)

我花了很多时间寻找使我能够做自己想做的聪明的选择,而且我能想到的所有解决方案都太复杂而无法付诸实践,所以:

我最终通过在顶级脚本所在的目录中使用符号链接来避免这种情况。这不是很好,但是比必须在工作环境中更改PYTHONPATH更好。因此,如果我在〜/ bin / python目录中存储了实用程序模块,但是实际上我正在使用〜/ some_project_dir / my_top_level.py中的脚本工作,那么我将创建一个符号链接,如下所示:

ln -s ~/bin/python ~/some_project_dir/python

然后在my_top_level.py文件中,我使用导入语句,例如:

from python.file_utils import read_lines_from_file
lines = read_lines_from_file("/tmp/some_file")

因此,如果我曾经将〜/ some_project_dir重定位到其他目录,则符号链接将随之而来。如果我曾经要移动〜/ bin / python目录,那么我确实有更新符号链接的琐事,但这只是次要的杂事,而且不会发生那么多的事情。