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.pytengo 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

unittestproyectos, 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.foocuando los ejecuto.cdentrarPyImportsy ejecutarpython -m unittest tests.test_abs, por ejemplo.Respuestas:
Si. No lo estás usando como un paquete.
fuente
__init__.pytodo 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.pyen el shell de Unix) sería útil. Todo este problema fue bastante complicado para mí descubrir o encontrar documentación concisa y comprensible.pkgen el punto donde llama a esta línea desde la CLI. Entonces, debería funcionar como se esperaba. Si estás dentropkgy llamaspython -m tests.core_test, no funcionará. Al menos no fue para mí.__init__.pyarchivos, pero sigues recibiendo elValueError: Attempted relative import in non-packageerror. 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
-mopció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_testdesde eltestssubdirectorio; 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.pyen el paquetepack.subpack, a continuación, estableciendo que es__package__apack.subpackle permitirá hacerlofrom ..module import somethinga 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.coredirectamente 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 sysparece 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.corefunciona 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.pypara iniciar la sesión de depuración.import pdb; pdb.set_trace()en el código (en línea).insertlugar 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.pyuse 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__.pyarchivo 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,
nosetestspero 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.pyentonces 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.pyen 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 fooentonces 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__.pyarchivos 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.