¿Cansado de los sys.path hacks?
Hay muchos sys.path.append
trucos disponibles, pero encontré una forma alternativa de resolver el problema.
Resumen
- Envuelva el código en una carpeta (por ejemplo
packaged_stuff
)
- Use crear
setup.py
script donde use setuptools.setup () .
- Pip instala el paquete en estado editable con
pip install -e <myproject_folder>
- Importar usando
from packaged_stuff.modulename import function_name
Preparar
El punto de partida es la estructura de archivos que ha proporcionado, envuelta en una carpeta llamada 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
Llamaré a la .
carpeta raíz y, en mi caso de ejemplo, se encuentra en C:\tmp\test_imports\
.
api.py
Como caso de prueba, usemos lo siguiente ./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()
Intenta ejecutar 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'
También intentar las importaciones relativas no funcionará:
Usar from ..api.api import function_from_api
resultaría en
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
Pasos
- Cree un archivo setup.py en el directorio del nivel raíz
El contenido para el setup.py
sería *
from setuptools import setup, find_packages
setup(name='myproject', version='1.0', packages=find_packages())
- Usa un entorno virtual
Si está familiarizado con los entornos virtuales, active uno y salte al siguiente paso. El uso de entornos virtuales no es absolutamente obligatorio, pero realmente lo ayudarán a largo plazo (cuando tenga más de 1 proyecto en curso ...). Los pasos más básicos son (ejecutar en la carpeta raíz)
- Crea env virtual
- Activar env virtual
source ./venv/bin/activate
(Linux, macOS) o ./venv/Scripts/activate
(Win)
Para obtener más información sobre esto, solo busque en Google "tutorial de python virtual env" o similar. Probablemente nunca necesite más comandos que crear, activar y desactivar.
Una vez que haya creado y activado un entorno virtual, su consola debe indicar el nombre del entorno virtual entre paréntesis
PS C:\tmp\test_imports> python -m venv venv
PS C:\tmp\test_imports> .\venv\Scripts\activate
(venv) PS C:\tmp\test_imports>
y tu árbol de carpetas debería verse así **
.
├── 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]
- pip instala tu proyecto en estado editable
Instale su paquete de nivel superior myproject
usando pip
. El truco es usar la -e
bandera al hacer la instalación. De esta forma, se instala en un estado editable, y todas las ediciones realizadas en los archivos .py se incluirán automáticamente en el paquete instalado.
En el directorio raíz, ejecute
pip install -e .
(tenga en cuenta el punto, significa "directorio actual")
También puede ver que se instala utilizando 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
- Agregar
myproject.
a sus importaciones
Tenga en cuenta que tendrá que agregar myproject.
solo a las importaciones que de otro modo no funcionarían. Las importaciones que funcionaron sin el setup.py
& pip install
funcionarán aún funcionan bien. Vea un ejemplo a continuación.
Prueba la solución
Ahora, probemos la solución usando los api.py
definidos anteriormente y los test_one.py
definidos a continuación.
test_one.py
from myproject.api.api import function_from_api
def test_function():
print(function_from_api())
if __name__ == '__main__':
test_function()
corriendo la prueba
(venv) PS C:\tmp\test_imports> python .\myproject\tests\test_one.py
I am the return value from api.api!
* Consulte los documentos de setuptools para obtener ejemplos más detallados de setup.py.
** En realidad, podría colocar su entorno virtual en cualquier parte de su disco duro.
sys.path
hacks y leer la única solución real que se ha publicado hasta ahora (¡después de 7 años!).