Устали от взлома sys.path?
Существует множество хаков sys.path.append
, но я нашел альтернативный способ решения проблемы: setuptools .Я не уверен, есть ли крайние случаи, которые не работают с этим.Следующее проверено на Python 3.6.5, (Anaconda, conda 4.5.1), на компьютере с Windows 10.
Настройка
Отправной точкой является предоставленная вами структура файла,обернутый в папку с именем myproject
.
.
└── myproject
├── api
│ ├── api_key.py
│ ├── api.py
│ └── __init__.py
├── examples
│ ├── example_one.py
│ ├── example_two.py
│ └── __init__.py
├── LICENCE.md
├── README.md
└── tests
├── __init__.py
└── test_one.py
Я назову .
корневой папкой, и в моем примере это находится в C:\tmp\test_imports\
.
api.py
В качестве тестового примера давайте используем следующее ./api/api.py
def function_from_api():
return 'I am the return value from api.api!'
test_one.py
from api.api import function_from_api
def test_function():
print(function_from_api())
if __name__ == '__main__':
test_function()
Попробуйте запустить test_one:
PS C:\tmp\test_imports> python .\myproject\tests\test_one.py
Traceback (most recent call last):
File ".\myproject\tests\test_one.py", line 1, in <module>
from api.api import function_from_api
ModuleNotFoundError: No module named 'api'
Также попытка относительного импорта не будет работать:
Использование from ..api.api import function_from_api
приведет к
PS C:\tmp\test_imports> python .\myproject\tests\test_one.py
Traceback (most recent call last):
File ".\tests\test_one.py", line 1, in <module>
from ..api.api import function_from_api
ValueError: attempted relative import beyond top-level package
Steps
1) Создатьфайл setup.py в корневой каталог
Содержание для setup.py
будет *
from setuptools import setup, find_packages
setup(name='myproject', version='1.0', packages=find_packages())
2) Использовать виртуальную среду
Если вы знакомы с виртуальными средами, активируйте одну и переходите к следующему шагу. Использование виртуальных сред не абсолютно , но они действительно помогут вамв долгосрочной перспективе (когда у вас более 1 проекта ..).Основные шаги (запуск в корневой папке)
- Создание виртуального env
- Активация виртуального env
source ./venv/bin/activate
(Linux, macOS) или ./venv/Scripts/activate
(Win)
Чтобы узнать больше об этом, просто посмотрите в Google "Python Virtual Env Tutorial" илианалогичный.Вам, вероятно, никогда не понадобятся какие-либо другие команды, кроме создания, активации и деактивации.
После того, как вы создали и активировали виртуальную среду, ваша консоль должна дать имя виртуальной среды в скобках
PS C:\tmp\test_imports> python -m venv venv
PS C:\tmp\test_imports> .\venv\Scripts\activate
(venv) PS C:\tmp\test_imports>
, и ваше дерево папок должно выглядеть следующим образом **
.
├── myproject
│ ├── api
│ │ ├── api_key.py
│ │ ├── api.py
│ │ └── __init__.py
│ ├── examples
│ │ ├── example_one.py
│ │ ├── example_two.py
│ │ └── __init__.py
│ ├── LICENCE.md
│ ├── README.md
│ └── tests
│ ├── __init__.py
│ └── test_one.py
├── setup.py
└── venv
├── Include
├── Lib
├── pyvenv.cfg
└── Scripts [87 entries exceeds filelimit, not opening dir]
3) pip установите ваш проект в редактируемом состоянии
Установите пакет верхнего уровня myproject
, используя pip
.Хитрость заключается в использовании флага -e
при установке.Таким образом, он устанавливается в редактируемом состоянии, и все изменения, внесенные в файлы .py, будут автоматически включены в установленный пакет.
В корневом каталоге запустите
pip install -e .
(обратите внимание на точку, она означает «текущий каталог»)
Вы также можете увидеть, что она установлена с помощьюpip freeze
(venv) PS C:\tmp\test_imports> pip install -e .
Obtaining file:///C:/tmp/test_imports
Installing collected packages: myproject
Running setup.py develop for myproject
Successfully installed myproject
(venv) PS C:\tmp\test_imports> pip freeze
myproject==1.0
4) Добавьте myproject.
в ваш импорт
Обратите внимание, что вам придется добавлять myproject.
только в импорт, который иначе не будет работать.Импорт, который работал без setup.py
& pip install
, будет работать по-прежнему нормально.См. Пример ниже.
Проверка решения
Теперь давайте проверим решение, используя api.py
, определенный выше, и test_one.py
, определенный ниже.
test_one.py
from myproject.api.api import function_from_api
def test_function():
print(function_from_api())
if __name__ == '__main__':
test_function()
запуск теста
(venv) PS C:\tmp\test_imports> python .\myproject\tests\test_one.py
I am the return value from api.api!
* См. документацию setuptools для более подробных примеров setup.py.
** На самом деле вы можете поместить свою виртуальную среду в любое место на жестком диске.