Скрипт Python 3, использующий относительный импорт при стандартном вводе, выдает ошибку: нет модуля с именем ' main .XXX';' main ' не является пакетом
Если у меня есть сценарий Python 3, который использует оператор относительного импорта в форме
from .subscript2 import subfunc2
А некоторые другие сценарии импортируютПриведенный выше скрипт как модуль работает без проблем.Однако, когда я выполняю скрипт, содержащий вышеуказанную строку, при стандартном вводе в интерпретатор Python, я получаю сообщение об ошибке вида:
ModuleNotFoundError: No module named '__main__.subscript2'; '__main__' is not a package
Причина, по которой мне нужно использовать stdin, заключается в том, что мне нужно использоватьElpy (https://elpy.readthedocs.io/en/latest/), который позволяет мне оценить этот скрипт (используя привязку Cc Cc) и затем добавить дополнительный код Python для вызова функций в этом скрипте, аналогично команде pdb 'взаимодействовать'.
Ниже приведен автономный скрипт для демонстрации происходящего:
#!/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
Для того, чтобы сделать вышедля работы, я должен был бы установить PYTHONPATH
в среде на разделенный двоеточиями список каталогов со всеми сценариями, которые я использую. Это будет работать, для моих собственных сценариев, но так же быстро, как только я захочу прочитать другие опубликованныескриптыв python через stdin, он снова сломается, если я не пройду через эти скрипты и временно не удалю начальный "." (что создает трудности и подвержен ошибкам).
Итак, есть ли способ заставить эту работудля всех этих случаев?У меня есть возможность изменить инструмент, который я использую (тот, который передает скрипт в stdin Python), чтобы добавить дополнительный код в этот поток stdin, за до реального скрипта, но если это решениекакие утверждения заставили бы его работать?
Полезный справочный материал, помогающий в понимании, но который не выявил решения: