Estoy tratando de seguir PEP 328 , con la siguiente estructura de directorios:
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, aparece 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
Al buscar, encontré que "la ruta relativa no funcionaba incluso con __init__.py " e " Importar un módulo desde una ruta relativa ", pero no me ayudaron.
¿Hay algo que me falta aquí?
python
package
python-import
importerror
init
Skytreader
fuente
fuente
unittest
proyectos, así que escribí este proyecto de muestra bastante exhaustivo que cubre la anidación profunda de módulos, importaciones relativas y absolutas (donde funcionan y no), y referencias relativas y absolutas desde dentro de un paquete, así como importación de clases simple, doble y a nivel de paquete. Ayudado a aclarar las cosas hasta para mí!no module named myimports.foo
cuando los ejecuto.cd
entrarPyImports
y ejecutarpython -m unittest tests.test_abs
, por ejemplo.Respuestas:
Si. No lo estás usando como un paquete.
fuente
__init__.py
todo el camino hacia abajo y el__package__
truco de modificación (descrito a continuación por BrenBarn) necesario para permitir estas importaciones de scripts ejecutables (por ejemplo, cuando se usa un shebang y hacer./my_script.py
en el shell de Unix) sería útil. Todo este problema fue bastante complicado para mí descubrir o encontrar documentación concisa y comprensible.pkg
en el punto donde llama a esta línea desde la CLI. Entonces, debería funcionar como se esperaba. Si estás dentropkg
y llamaspython -m tests.core_test
, no funcionará. Al menos no fue para mí.__init__.py
archivos, pero sigues recibiendo elValueError: Attempted relative import in non-package
error. Pagaría un dinero realmente bueno para que alguien, en algún lugar, finalmente explicara en inglés simple cómo funciona todo esto.Para elaborar sobre 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. Entonces las importaciones relativas no funcionan.Puede, como sugirió Igancio, ejecutarlo usando la
-m
opción Si tiene una parte de su paquete que debe ejecutarse como un script, también puede usar el__package__
atributo para decirle a ese archivo qué nombre se supone que debe tener en la jerarquía del paquete.Ver http://www.python.org/dev/peps/pep-0366/ para más detalles.
fuente
python -m core_test
desde eltests
subdirectorio; tiene que ser desde el padre o debe agregar el padre a la ruta.__package__
para garantizar que los archivos de script ejecutables puedan importar relativamente otros módulos desde el mismo paquete. No hay forma de importar relativamente desde "todo el sistema". Ni siquiera estoy seguro de por qué querrías hacer esto.__package__
símbolo está configurado como "parent.child", entonces podrá importar "parent.other_child". Quizás no lo dije tan bien.script.py
en el paquetepack.subpack
, a continuación, estableciendo que es__package__
apack.subpack
le permitirá hacerlofrom ..module import something
a importar algo depack.module
. Tenga en cuenta que, como dice la documentación, aún debe tener el paquete de nivel superior en la ruta del sistema. Así es como funcionan las cosas para los módulos importados. Lo único que__package__
hace es permitirle usar ese comportamiento también para scripts ejecutados directamente.__package__
en la secuencia de comandos que se ejecuta directamente, pero desafortunadamente, aparece el siguiente error: "El módulo principal 'xxx' no está cargado, no se puede realizar una importación relativa"Puede usarlo
import components.core
directamente si agrega el directorio actual asys.path
:fuente
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
esto también funcionaráfrom os import sys
parece trampa :)sys.path
- el padre del directorio del archivo actual se encuentra.import sys, os.path as path
.import os; os.sys.path.append(os.path.dirname(os.path.abspath('.')))
. Entonces, una rectaimport components.core
funciona para mí, importando desde el directorio principal del cuaderno como lo desee.Depende de cómo quieras iniciar tu script.
Si desea iniciar su UnitTest desde la línea de comandos de una manera clásica, es decir:
Entonces, dado que en este caso 'componentes' y 'pruebas' son carpetas de hermanos, puede importar el módulo relativo utilizando el método insert o append del módulo sys.path . Algo como:
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:
En tal caso, simplemente puede usar la importación relativa como lo estaba haciendo:
Finalmente puede mezclar los dos enfoques, para que su script funcione sin importar cómo se llame. Por ejemplo:
fuente
python -m pdb myscript.py
para iniciar la sesión de depuración.import pdb; pdb.set_trace()
en el código (en línea).insert
lugar deappend
? Es decir,sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
En core_test.py, haga lo siguiente:
fuente
Si su caso de uso es para ejecutar pruebas, y parece que es así, puede hacer lo siguiente. En lugar de ejecutar su script de prueba,
python core_test.py
use un marco de prueba comopytest
. Luego en la línea de comando puedes ingresarEso ejecutará las pruebas en su directorio. Esto evita el problema de
__name__
ser__main__
que fue señalado por @BrenBarn. Luego, coloque un__init__.py
archivo vacío en su directorio de prueba, esto hará que el directorio de prueba forme parte de su paquete. Entonces podrás hacerSin embargo, si ejecuta su script de prueba como programa principal, las cosas volverán a fallar. Así que solo usa el corredor de prueba. Tal vez esto también funcione con otros corredores de prueba como,
nosetests
pero no lo he comprobado. Espero que esto ayude.fuente
Mi solución rápida es agregar el directorio a la ruta:
fuente
El problema es con su método de prueba,
intentaste
python core_test.py
entonces obtendrá este error ValueError: intento de importación relativa en un paquete no
Motivo: está probando su embalaje desde una fuente que no es el paquete.
prueba tu módulo desde la fuente del paquete.
si esta es la estructura de tu proyecto,
paquete de cd
o desde fuera del paquete /
solo
.
si desea importar desde la carpeta en el mismo directorio. para cada paso atrás agregue uno más.en
how.py
en caso de que quieras importar cómo desde hello.py
fuente
from .. import how
, ¿cómo se importa una clase / método específico del archivo 'cómo'? cuando hago el equivalente defrom ..how import foo
entonces obtengo "intento de importación relativa más allá del paquete de nivel superior"Hilo viejo. Descubrí que la adición de una
__all__= ['submodule', ...]
a la __init__.py archivo y luego usar elfrom <CURRENT_MODULE> import *
en el objetivo de obras excelentes.fuente
Puede usar
from pkg.components.core import GameLoopEvents
, por ejemplo, uso pycharm, la siguiente es la imagen de la estructura de mi proyecto, solo importo desde el paquete raíz, luego funciona:fuente
Como dijo Paolo , tenemos 2 métodos de invocación:
Una diferencia entre ellos es la cadena sys.path [0]. Dado que la interpretación buscará sys.path al importar , podemos hacer lo siguiente
tests/core_test.py
:Y más después de esto, podemos ejecutar core_test.py con otros métodos:
Nota, py36 probado solo.
fuente
Este enfoque funcionó para mí y está menos abarrotado que algunas soluciones:
El directorio padre está en mi PYTHONPATH, y hay
__init__.py
archivos en el directorio padre y este directorio.Lo anterior siempre funcionó en Python 2, pero Python 3 a veces golpeó un ImportError o ModuleNotFoundError (este último es nuevo en Python 3.6 y una subclase de ImportError), por lo que el siguiente ajuste funciona para mí en Python 2 y 3:
fuente
Prueba esto
fuente
Si alguien está buscando una solución, me topé con una. Aquí hay un poco de contexto. Quería probar uno de los métodos que tengo en un archivo. Cuando lo ejecuto desde dentro
siempre se quejaba de las importaciones relativas. Traté de 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. Sin embargo, no es una gran solución, funciona.
fuente
Aquí hay una manera que molestará a todos, pero funcionará bastante bien. En pruebas ejecutadas:
Luego solo importe componentes como lo haría normalmente.
fuente
Esto es muy confuso, y si está utilizando IDE como pycharm, es un poco más confuso. Lo que funcionó para mí: 1. Realice la configuración del proyecto pycharm (si está ejecutando python desde un VE o desde el directorio de python) 2. No hay ningún error en la forma en que lo definió. a veces funciona con la clase de importación folder1.file1
si no funciona, use import folder1.file1 3. Su variable de entorno debe mencionarse correctamente en el sistema o proporcionarla en su argumento de línea de comando.
fuente
Debido a que su código contiene
if __name__ == "__main__"
, que no se importa como un paquete, será mejor que lo usesys.path.append()
para resolver el problema.fuente
if __name__ == "__main__"
en su archivo haga una diferencia en nada relacionado con la importación.