Tengo un proyecto de Python con un archivo de configuración en la raíz del proyecto. Es necesario acceder al archivo de configuración en algunos archivos diferentes a lo largo del proyecto.
Por lo que se ve algo como: <ROOT>/configuration.conf
<ROOT>/A/a.py
, <ROOT>/A/B/b.py
(cuando b, acceso a.py el archivo de configuración).
¿Cuál es la forma mejor / más fácil de obtener la ruta a la raíz del proyecto y el archivo de configuración sin depender del archivo dentro del proyecto en el que estoy? es decir, sin usar ../../
? Está bien suponer que conocemos el nombre de la raíz del proyecto.
<ROOT>/__init__.py
existe?os.path.expanduser('~/.myproject/myproject.conf')
. Funciona en Unix y Windows.Respuestas:
Puede hacer esto como lo hace Django: defina una variable para la raíz del proyecto desde un archivo que se encuentra en el nivel superior del proyecto. Por ejemplo, si así es como se ve la estructura de su proyecto:
En
definitions.py
puede definir (esto requiereimport os
):Por lo tanto, con la raíz del proyecto conocida, puede crear una variable que apunte a la ubicación de la configuración (esto se puede definir en cualquier lugar, pero un lugar lógico sería colocarlo en una ubicación donde se definen las constantes, por ejemplo
definitions.py
):A continuación, se puede acceder fácilmente a la constante (en cualquiera de los otros archivos) con la declaración de importación (por ejemplo, en
utils.py
):from definitions import CONFIG_PATH
.fuente
__init__.py
archivo al directorio raíz del proyecto también? ¿Debería ser eso correcto? Acabo de comenzar con Python y no estoy seguro de las mejores prácticas. Gracias.__init__.py
no se requerirá un archivo, ya que ese archivo solo se requiere al definir paquetes: los__init__.py
archivos son necesarios para que Python trate los directorios como si fueran paquetes; Esto se hace para evitar que los directorios con un nombre común, como cadena, oculten involuntariamente módulos válidos que aparecen más adelante en la ruta de búsqueda del módulo. En el caso más simple,__init__.py
puede ser simplemente un archivo vacío, pero también puede ejecutar el código de inicialización del paquete o establecer la__all__
variable, que se describe más adelante. Ver: docs.python.org/3/tutorial/modules.html#packages__init.py__
paquete raíz. Guardaría la creación de otro archivo, además de permitir la sintaxis más agradable defrom root_pack import ROOT_DIR, CONFIG_PATH
.__init__.py
vacío, pero eso no es estrictamente cierto (es una convención después de todo). Consulte esto para obtener más información: stackoverflow.com/questions/2361124/using-init-pyos.path.abspath
está llamando a una cadena,'__file__'
. Recuerde que en__file__
realidad es un atributo de importación que se define para los módulos de Python. En este caso,__file__
devolverá la ruta desde la que se carga el módulo. Lea más aquí (consulte la sección de módulos): docs.python.org/3/reference/datamodel.htmlOtras respuestas aconsejan utilizar un archivo en el nivel superior del proyecto. Esto no es necesario si usa
pathlib.Path
yparent
(Python 3.4 y superior). Considere la siguiente estructura de directorio donde se han omitido todos los archivos exceptoREADME.md
yutils.py
.En
utils.py
definimos la siguiente función.En cualquier módulo del proyecto, ahora podemos obtener la raíz del proyecto de la siguiente manera.
Beneficios : Cualquier módulo que llame
get_project_root
se puede mover sin cambiar el comportamiento del programa. Solo cuandoutils.py
se mueve el módulo , tenemos que actualizarget_project_root
y las importaciones (se pueden utilizar herramientas de refactorización para automatizar esto).fuente
Todas las soluciones anteriores parecen ser demasiado complicadas para lo que creo que necesita y, a menudo, no me funcionaron. El siguiente comando de una línea hace lo que quiere:
fuente
Para obtener la ruta del módulo "raíz", puede usar:
Pero lo más interesante es que si tiene un "objeto" de configuración en su módulo superior, podría leerlo así:
fuente
os
no está disponible de forma predeterminada. Necesita importaros
. Entonces, agregar la líneaimport os
haría que la respuesta fuera más completa.python3 -m topmodule.submodule.script
, dará en/path/to/topmodule/submodule
lugar de/path/to/topmodule
.Una forma estándar de lograr esto sería utilizar el
pkg_resources
módulo que forma parte delsetuptools
paquete.setuptools
se utiliza para crear un paquete de Python instalable.Puede usar
pkg_resources
para devolver el contenido de su archivo deseado como una cadena y puede usarpkg_resources
para obtener la ruta real del archivo deseado en su sistema.Digamos que tiene un paquete llamado
stackoverflow
.Ahora digamos que desea acceder al archivo Rush desde un módulo
app.run
. Úselopkg_resources.resouces_filename
para obtener el camino a Rush ypkg_resources.resource_string
para obtener el contenido de Rush; así:La salida:
Esto funciona para todos los paquetes en su ruta de Python. Entonces, si desea saber dónde
lxml.etree
existe en su sistema:salida:
El punto es que puede usar este método estándar para acceder a los archivos que están instalados en su sistema (por ejemplo, pip install xxx o yum -y install python-xxx) y archivos que están dentro del módulo en el que está trabajando actualmente.
fuente
Tratar:
fuente
Debajo del código Devuelve la ruta hasta la raíz de su proyecto
fuente
También luché con este problema hasta que llegué a esta solución. Esta es la solución más limpia en mi opinión.
En su setup.py agregue "paquetes"
En su python_script.py
fuente
python3 setup.py install
él ya no apuntaba a la carpeta del código fuente, sino al huevo dentro~./virtualenv/..../app.egg
. Entonces tuve que incluir el archivo de configuración en la instalación del paquete.Solo un ejemplo: quiero ejecutar runio.py desde helper1.py
Ejemplo de árbol de proyecto:
Obtener la raíz del proyecto:
Construir ruta al script:
fuente
Esto funcionó para mí usando un proyecto estándar de PyCharm con mi entorno virtual (venv) en el directorio raíz del proyecto.
El código siguiente no es el más bonito, pero siempre obtiene la raíz del proyecto. Devuelve la ruta completa del directorio a venv desde la
VIRTUAL_ENV
variable de entorno, por ejemplo/Users/NAME/documents/PROJECT/venv
Luego divide la ruta al final
/
, dando una matriz con dos elementos. El primer elemento será la ruta del proyecto, p. Ej./Users/NAME/documents/PROJECT
fuente
Recientemente he intentado hacer algo similar y he encontrado que estas respuestas son inadecuadas para mis casos de uso (una biblioteca distribuida que necesita detectar la raíz del proyecto). Principalmente he estado luchando contra diferentes entornos y plataformas, y todavía no he encontrado algo perfectamente universal.
Código local para proyectar
He visto este ejemplo mencionado y utilizado en algunos lugares, Django, etc.
Por simple que sea, solo funciona cuando el archivo en el que se encuentra el fragmento es realmente parte del proyecto. No recuperamos el directorio del proyecto, sino el directorio del fragmento
De manera similar, el enfoque sys.modules se rompe cuando se llama desde fuera del punto de entrada de la aplicación, específicamente, he observado que un hilo secundario no puede determinar esto sin relación con el módulo ' principal '. He puesto explícitamente la importación dentro de una función para demostrar una importación desde un hilo secundario, moverla al nivel superior de app.py lo solucionaría.
app.py
settings.py
La ejecución de este programa produce un error de atributo:
... de ahí una solución basada en subprocesos
Independiente de la ubicación
Usando la misma estructura de aplicación que antes pero modificando settings.py
Desglosando esto: Primero queremos encontrar con precisión el ID del hilo del hilo principal. En Python3.4 +, la biblioteca de subprocesos tiene
threading.main_thread()
, sin embargo, no todo el mundo usa 3.4+, por lo que buscamos en todos los subprocesos buscando el subproceso principal, salvo su ID. Si el hilo principal ya ha salido, no aparecerá en la listathreading.enumerate()
. Planteamos unRuntimeError()
en este caso hasta que encuentre una mejor solución.A continuación, encontramos el primer marco de pila del hilo principal. Usando la función específica de cPython
sys._current_frames()
obtenemos un diccionario del marco de pila actual de cada hilo. Luego, utilizandoinspect.getouterframes()
podemos recuperar la pila completa para el hilo principal y el primer marco. current_main_frame = sys._current_frames () [main_id] base_frame = inspect.getouterframes (current_main_frame) [- 1] Finalmente, las diferencias entre las implementaciones de Windows y Linuxinspect.getouterframes()
deben ser manejadas. Usar el nombre de archivo limpiadoos.path.abspath()
yos.path.dirname()
limpiar las cosas.Hasta ahora he probado esto en Python2.7 y 3.6 en Windows, así como Python3.4 en WSL
fuente
Si está trabajando con anaconda-project, puede consultar PROJECT_ROOT desde la variable de entorno -> os.getenv ('PROJECT_ROOT'). Esto solo funciona si el script se ejecuta a través de anaconda-project run.
Si no desea que anaconda-project ejecute su script, puede consultar la ruta absoluta del binario ejecutable del intérprete de Python que está usando y extraer la cadena de ruta hasta el directorio envs exclusiv. Por ejemplo: el intérprete de Python de mi conda env se encuentra en:
Esto solo funciona con conda-project con estructura de proyecto fija de un anaconda-project
fuente
Usé el método ../ para buscar la ruta actual del proyecto.
Ejemplo: Proyecto1 - D: \ proyectos
src
Archivos de configuración
Configuration.cfg
Ruta = "../ src / ConfigurationFiles / Configuration.cfg"
fuente
En el momento de escribir este artículo, ninguna de las otras soluciones es muy autónoma. Dependen de una variable de entorno o de la posición del módulo en la estructura del paquete. La respuesta principal con la solución 'Django' es víctima de esta última al requerir una importación relativa. También tiene la desventaja de tener que modificar un módulo en el nivel superior.
Este debería ser el enfoque correcto para encontrar la ruta del directorio del paquete de nivel superior:
Funciona tomando el primer componente en la cadena de puntos contenida en
__name__
y usándolo como una clave en lasys.modules
que devuelve el objeto de módulo del paquete de nivel superior. Su__file__
atributo contiene la ruta que queremos después de recortar/__init__.py
usandoos.path.dirname()
.Esta solución es autónoma. Funciona en cualquier parte de cualquier módulo del paquete, incluso en el
__init__.py
archivo de nivel superior .fuente
Tuve que implementar una solución personalizada porque no es tan simple como podría pensar. Mi solución se basa en la inspección de seguimiento de pila (
inspect.stack()
) +sys.path
y funciona bien sin importar la ubicación del módulo de Python en el que se invoca la función ni el intérprete (intenté ejecutarlo en PyCharm, en un shell de poesía y otros ... ). Esta es la implementación completa con comentarios:fuente
Hay muchas respuestas aquí, pero no pude encontrar algo simple que cubra todos los casos, así que permítame sugerir mi solución también:
fuente