operator - python modules list
Cómo corregir "Intento de importación relativa en un no paquete" incluso con__init__.py (12)
Como dijo Paolo , tenemos 2 métodos de invocación:
1) python -m tests.core_test
2) python tests/core_test.py
Una diferencia entre ellos es sys.path [0] cadena. Como la interpretación buscará sys.path cuando se realice una importación , podemos hacerlo con tests/core_test.py
:
if __name__ == ''__main__'':
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from components import core
<other stuff>
Y más después de esto, podemos ejecutar core_test.py con otros métodos:
cd tests
python core_test.py
python -m core_test
...
Tenga en cuenta, py36 probado solamente.
Estoy tratando de seguir PEP 328 , con la siguiente estructura de directorio:
pkg/
__init__.py
components/
core.py
__init__.py
tests/
core_test.py
__init__.py
En core_test.py
tengo la siguiente declaración de importación
from ..components.core import GameLoopEvents
Sin embargo, cuando ejecuto, me sale el siguiente error:
tests$ python core_test.py
Traceback (most recent call last):
File "core_test.py", line 3, in <module>
from ..components.core import GameLoopEvents
ValueError: Attempted relative import in non-package
Buscando alrededor encontré " ruta relativa que no funciona incluso con __init__.py " e " Importar un módulo desde una ruta relativa " pero no ayudaron.
¿Hay algo que me esté perdiendo aquí?
Depende de cómo quieras lanzar tu script.
Si desea iniciar su UnitTest desde la línea de comandos de una manera clásica, es decir:
python tests/core_test.py
Luego, dado que en este caso los ''componentes'' y ''pruebas'' son carpetas de hermanos, puede importar el módulo relativo utilizando el método de inserción o el método de sys.path módulo sys.path . Algo como:
import sys
from os import path
sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
from components.core import GameLoopEvents
De lo contrario, puede iniciar su script con el argumento ''-m'' (tenga en cuenta que en este caso, estamos hablando de un paquete y, por lo tanto, no debe dar la extensión ''.py'' ), es decir:
python -m pkg.tests.core_test
En tal caso, simplemente puede usar la importación relativa como estaba haciendo:
from ..components.core import GameLoopEvents
Finalmente, puede mezclar los dos enfoques, para que su script funcione sin importar cómo se llame. Por ejemplo:
if __name__ == ''__main__'':
if __package__ is None:
import sys
from os import path
sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
from components.core import GameLoopEvents
else:
from ..components.core import GameLoopEvents
Hilo viejo. Descubrí que agregar un __all__= [''submodule'', ...]
al archivo __init__.py y luego usar la from <CURRENT_MODULE> import *
en el destino funciona bien.
Mi solución rápida es agregar el directorio a la ruta:
import sys
sys.path.insert(0, ''../components/'')
Para profundizar en la respuesta de Ignacio Vázquez-Abrams :
El mecanismo de importación de Python funciona en relación con el __name__
del archivo actual. Cuando ejecuta un archivo directamente, no tiene su nombre habitual, sino que tiene "__main__"
como su nombre. Así que las importaciones relativas no funcionan.
Puede, como sugirió Igancio, ejecutarlo usando la opción -m
. Si tiene una parte de su paquete que debe ejecutarse como una secuencia de comandos, también puede usar el atributo __package__
para indicar a ese archivo el nombre que se supone que debe tener en la jerarquía de paquetes.
Vea http://www.python.org/dev/peps/pep-0366/ para más detalles.
Prueba esto
import components
from components import *
Puede usar import components.core
directamente si sys.path
directorio actual a sys.path
:
if __name__ == ''__main__'' and __package__ is None:
from os import sys, path
sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
Sí. No lo estás utilizando como un paquete.
python -m pkg.tests.core_test
Si alguien está buscando una solución, me topé con uno. Aquí hay un poco de contexto. Quería probar uno de los métodos que tengo en un archivo. Cuando lo ejecuto desde dentro
if __name__ == "__main__":
Siempre se quejaba de las importaciones relativas. Intenté aplicar las soluciones anteriores, pero no funcionó, ya que había muchos archivos anidados, cada uno con múltiples importaciones.
Esto es lo que hice. Acabo de crear un lanzador, un programa externo que importaría los métodos necesarios y los llamaría. Aunque, no es una gran solución, funciona.
Si su caso de uso es para ejecutar pruebas y parece que sí, puede hacer lo siguiente. En lugar de ejecutar su script de prueba como python core_test.py
use un marco de prueba como pytest
. Luego en la línea de comando puedes ingresar
$$ py.test
Eso ejecutará las pruebas en su directorio. Esto __main__
el problema de que __name__
sea __main__
que fue señalado por @BrenBarn. Luego, coloque un archivo __init__.py
vacío en su directorio de prueba, esto hará que el directorio de prueba sea parte de su paquete. Entonces podrás hacer
from ..components.core import GameLoopEvents
Sin embargo, si ejecuta su script de prueba como un programa principal, las cosas volverán a fallar. Así que solo usa el corredor de prueba. Tal vez esto también funciona con otros corredores de prueba, como las nosetests
pero no lo he comprobado. Espero que esto ayude.
En core_test.py, haga lo siguiente:
import sys
sys.path.append(''../components'')
from core import GameLoopEvents