Tengo una estructura de directorio similar a la siguiente
meta_project
project1
__init__.py
lib
module.py
__init__.py
notebook_folder
notebook.jpynb
Cuando se trabaja en notebook.jpynb
si trato de usar una importación relativa a acceder a una función function()
en module.py
la:
from ..project1.lib.module import function
Obtuve el siguiente error:
SystemError Traceback (most recent call last)
<ipython-input-7-6393744d93ab> in <module>()
----> 1 from ..project1.lib.module import function
SystemError: Parent module '' not loaded, cannot perform relative import
¿Hay alguna forma de hacer que esto funcione usando importaciones relativas?
Tenga en cuenta que se crea una instancia del servidor del cuaderno en el nivel del meta_project
directorio, por lo que debería tener acceso a la información de esos archivos.
Tenga en cuenta también que, al menos como se pretendía originalmente, project1
no se pensó en un módulo y, por lo tanto, no tiene un __init__.py
archivo, solo se pensó como un directorio del sistema de archivos. Si la solución al problema requiere tratarlo como un módulo e incluir un __init__.py
archivo (incluso uno en blanco) está bien, pero hacerlo no es suficiente para resolver el problema.
Comparto este directorio entre máquinas y las importaciones relativas me permiten usar el mismo código en todas partes y, a menudo, utilizo cuadernos para la creación rápida de prototipos, por lo que es poco probable que las sugerencias que impliquen piratear rutas absolutas juntas sean útiles.
Editar: Esto es diferente a las importaciones relativas en Python 3 , que habla de las importaciones relativas en Python 3 en general y, en particular, de ejecutar un script desde el directorio de un paquete. Esto tiene que ver con trabajar dentro de un cuaderno jupyter tratando de llamar a una función en un módulo local en otro directorio que tiene aspectos generales y particulares diferentes.
__init__
archivos en el directorio de su paquete?lib
directorio.Respuestas:
Tuve casi el mismo ejemplo que usted en este cuaderno en el que quería ilustrar el uso de la función de un módulo adyacente de manera SECA.
Mi solución fue decirle a Python de esa ruta de importación de módulo adicional agregando un fragmento como este al cuaderno:
Esto le permite importar la función deseada de la jerarquía del módulo:
Tenga en cuenta que es necesario agregar
__init__.py
archivos vacíos a las carpetas project1 / y lib / si aún no los tiene.fuente
Vine aquí en busca de las mejores prácticas para abstraer código en submódulos cuando trabajaba en Notebooks. No estoy seguro de que exista una buena práctica. He estado proponiendo esto.
Una jerarquía de proyectos como tal:
Y de
20170609-Initial_Database_Connection.ipynb
:Esto funciona porque, de forma predeterminada, Jupyter Notebook puede analizar el
cd
comando. Tenga en cuenta que esto no hace uso de la magia de Python Notebook. Simplemente funciona sin anteponer%bash
.Teniendo en cuenta que 99 de cada 100 veces estoy trabajando en Docker usando una de las imágenes de Project Jupyter Docker , la siguiente modificación es idempotente
fuente
chdir
lugar de agregar a la ruta, ya que estoy interesado tanto en importar desde el repositorio principal como en interactuar con algunos archivos allí.if os.path.isdir('../lib/'): os.chdir('../lib')
:; o, mejor, úselo../lib/db/
con supostgres.py
para no subir accidentalmente a un directorio superior que también contenga otrolib
.cd ..
dos veces.Hasta ahora, la respuesta aceptada me ha funcionado mejor. Sin embargo, mi preocupación siempre ha sido que existe un escenario probable en el que podría refactorizar el
notebooks
directorio en subdirectorios, requiriendo cambiar elmodule_path
en cada cuaderno. Decidí agregar un archivo de Python dentro de cada directorio de cuaderno para importar los módulos requeridos.Así, teniendo la siguiente estructura de proyecto:
Agregué el archivo
project_path.py
en cada subdirectorio del cuaderno (notebooks/explore
ynotebooks/explain
). Este archivo contiene el código para las importaciones relativas (de @metakermit):De esta manera, solo necesito hacer importaciones relativas dentro del
project_path.py
archivo y no en los cuadernos. Los archivos de los cuadernos solo tendrían que importarproject_path
antes de importarlib
. Por ejemplo en0.0-notebook.ipynb
:La advertencia aquí es que revertir las importaciones no funcionaría. ESTO NO FUNCIONA:
Por lo tanto, se debe tener cuidado durante las importaciones.
fuente
Acabo de encontrar esta bonita solución:
Solo quieres algunas funciones de ese archivo
Si la versión de python> = 3.3 no necesita el archivo init.py en la carpeta
fuente
if ".." not in sys.path: ... sys.path.insert(0,"..")
Investigando este tema yo mismo y después de leer las respuestas, recomiendo usar la biblioteca path.py, ya que proporciona un administrador de contexto para cambiar el directorio de trabajo actual.
Entonces tienes algo como
Aunque, puede omitir la
isdir
declaración.Aquí agregaré declaraciones impresas para que sea más fácil seguir lo que está sucediendo
que produce en este ejemplo (donde lib está en
/home/jovyan/shared/notebooks/by-team/data-vis/demos/lib
):Dado que la solución utiliza un administrador de contexto, se le garantiza que volverá a su directorio de trabajo anterior, sin importar en qué estado estaba su kernel antes de la celda y sin importar qué excepciones se produzcan al importar el código de su biblioteca.
fuente
Aquí están mis 2 centavos:
importar sys
mapee la ruta donde se encuentra el archivo del módulo. En mi caso fue el escritorio
sys.path.append ('/ Usuarios / John / Escritorio')
O importe todo el módulo de mapeo PERO entonces debe usar la .notation para mapear las clases como mapeo.
import mapping # mapping.py es el nombre de mi archivo de módulo
shipit = mapping.Shipment () #Shipment es el nombre de la clase que necesito usar en el módulo de mapeo
O importar la clase específica del módulo de mapeo
desde el mapeo importar mapeo
shipit = Shipment () #Ahora no tienes que usar el .notation
fuente
He descubierto que python-dotenv ayuda a resolver este problema con bastante eficacia. La estructura de su proyecto termina cambiando ligeramente, pero el código en su cuaderno es un poco más simple y consistente en todos los cuadernos.
Para su proyecto, instale un poco.
Luego, el proyecto cambia a:
Y finalmente, su importación cambia a:
Un +1 para este paquete es que sus cuadernos pueden tener varios directorios de profundidad. python-dotenv encontrará el más cercano en un directorio principal y lo usará. Un +2 para este enfoque es que jupyter cargará variables de entorno desde el archivo .env al inicio. Doble golpe.
fuente