Expandir la ruta de búsqueda de Python a otra fuente

106

Me acabo de unir a un proyecto con una base de código existente bastante grande. Desarrollamos en linux y no utilizamos ni IDE. Pasamos por la línea de comandos. Estoy tratando de averiguar cómo hacer que Python busque la ruta correcta cuando ejecuto los módulos del proyecto. Por ejemplo, cuando ejecuto algo como:

python someprojectfile.py

yo obtengo

ImportError: no module named core.'somemodule'

Recibo esto para todas mis importaciones y supongo que es un problema con la ruta.

TLDR:

¿Cómo hago para que Python busque ~/codez/project/y todos los archivos y carpetas para archivos * .py durante las declaraciones de importación?

el maestro
fuente

Respuestas:

171

Hay algunas formas posibles de hacer esto:

  • Establezca la variable de entorno PYTHONPATHen una lista de directorios separados por dos puntos para buscar módulos importados.
  • En su programa, use sys.path.append('/path/to/search')para agregar los nombres de los directorios en los que desea que Python busque los módulos importados. sys.pathes solo la lista de directorios que Python busca cada vez que se le pide que importe un módulo, y puede modificarlo según sea necesario (¡aunque no recomendaría eliminar ninguno de los directorios estándar!). Cualquier directorio que coloque en la variable de entorno PYTHONPATHse insertará en sys.pathcuando Python se inicie.
  • Úselo site.addsitedirpara agregar un directorio sys.path. La diferencia entre esto y simplemente agregar es que cuando lo usa addsitedir, también busca .ptharchivos dentro de ese directorio y los usa para posiblemente agregar directorios adicionales sys.pathsegún el contenido de los archivos. Consulte la documentación para obtener más detalles.

Cuál de estos desea utilizar depende de su situación. Recuerde que cuando distribuye su proyecto a otros usuarios, normalmente lo instalan de tal manera que el importador de Python detectará automáticamente los archivos de código de Python (es decir, los paquetes generalmente se instalan en el site-packagesdirectorio), así que si se mete con sys.pathsu código , eso puede ser innecesario e incluso puede tener efectos adversos cuando ese código se ejecuta en otra computadora. Para el desarrollo, me atrevería a suponer que la configuración PYTHONPATHsuele ser la mejor manera de hacerlo.

Sin embargo, cuando está usando algo que simplemente se ejecuta en su propia computadora (o cuando tiene configuraciones no estándar, por ejemplo, a veces en marcos de aplicaciones web), no es del todo raro hacer algo como

import sys
from os.path import dirname
sys.path.append(dirname(__file__))
David Z
fuente
Entonces, si tuviera como 15 subdirectorios, ¿tendría que agregar individualmente cada uno?
themaestro
y ¿podría dar un ejemplo de un argumento de línea de comando para cambiar PYTHONPATH?
themaestro
3
Para establecer PYTHONPATH: en .bashrco cualquier archivo de inicio que use su shell (si no es Bash), escriba export PYTHONPATH=$PYTHONPATH:$HOME/codez/project. Pero si tiene un montón de subdirectorios, haría un .ptharchivo y usaría site.addsitedir. Puede crear un módulo sitecustomizeque pueda llamar a la función por usted; intente ponerlo en ~/.local/lib/python2.6/sitecustomize.py(sustituya su versión de Python) para que se importe automáticamente.
David Z
Puse lo siguiente en mi archivo .bashrc y todavía no tengo suerte con esas importaciones. ¿Algunas ideas? ¿Cómo haría un archivo .pth de todos modos? exportar PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / export PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / proyecto exportar PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / proyecto / core export PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / project / proxies export PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / project / conf
themaestro
Intente abrir una terminal y ejecutar echo $PYTHONPATH. Si la variable de entorno se ha configurado correctamente, debería ver una lista de directorios separados por dos puntos. Para obtener información sobre .ptharchivos, consulte la documentación del sitemódulo al que me vinculé en mi respuesta. Te dice cuáles deben ser los contenidos y cómo usarlos.
David Z
13

También debería leer acerca de los paquetes de Python aquí: http://docs.python.org/tutorial/modules.html .

Por tu ejemplo, supongo que realmente tienes un paquete en ~/codez/project. El archivo __init__.pyen un directorio de Python asigna un directorio a un espacio de nombres. Si todos sus subdirectorios tienen un __init__.pyarchivo, entonces solo necesita agregar el directorio base a su PYTHONPATH. Por ejemplo:

PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / proyecto

Además de probar su variable de entorno PYTHONPATH, como explica David, puede probarla en Python de esta manera:

$ python
>>> import project                      # should work if PYTHONPATH set
>>> import sys
>>> for line in sys.path: print line    # print current python path

...

Andrew B.
fuente
Es posible que desee poner las __init__.pycomillas invertidas para dejar en claro que realmente quiere decir __init__.py, en lugar de init.py. Solo para evitar confundir a los novatos. :)
antred
4

Sé que este hilo es un poco antiguo, pero me tomó un tiempo llegar al meollo de esto, así que quería compartirlo.

En mi proyecto, tenía el script principal en un directorio principal y, para diferenciar los módulos, puse todos los módulos de soporte en una subcarpeta llamada "módulos". En mi script principal, importo estos módulos como este (para un módulo llamado report.py):

from modules.report import report, reportError

Si llamo a mi script principal, esto funciona. SIN EMBARGO, quería probar cada módulo al incluir un main()en cada uno y llamar a cada uno directamente, como:

python modules/report.py

Ahora Python se queja de que no puede encontrar "un módulo llamado módulos". La clave aquí es que, de forma predeterminada, Python incluye la carpeta del script en su ruta de búsqueda, PERO NO EL CWD. Entonces, lo que dice este error, en realidad, es "No puedo encontrar una subcarpeta de módulos". Esto se debe a que no hay un subdirectorio "módulos" en el directorio donde reside el módulo report.py.

Encuentro que la mejor solución para esto es agregar el CWD en la ruta de búsqueda de Python al incluir esto en la parte superior:

import sys

sys.path.append(".")

Ahora Python busca en el CWD (directorio actual), encuentra la subcarpeta "módulos" y todo está bien.

Tom Gordon
fuente
3

Leí esta pregunta buscando una respuesta y no me gustó ninguna de ellas.

Así que escribí una solución rápida y sucia. Simplemente coloque esto en algún lugar de su sys.path, y agregará cualquier directorio debajo folder(del directorio de trabajo actual), o debajo abspath:

#using.py

import sys, os.path

def all_from(folder='', abspath=None):
    """add all dirs under `folder` to sys.path if any .py files are found.
    Use an abspath if you'd rather do it that way.

    Uses the current working directory as the location of using.py. 
    Keep in mind that os.walk goes *all the way* down the directory tree.
    With that, try not to use this on something too close to '/'

    """
    add = set(sys.path)
    if abspath is None:
        cwd = os.path.abspath(os.path.curdir)
        abspath = os.path.join(cwd, folder)
    for root, dirs, files in os.walk(abspath):
        for f in files:
            if f[-3:] in '.py':
                add.add(root)
                break
    for i in add: sys.path.append(i)

>>> import using, sys, pprint
>>> using.all_from('py') #if in ~, /home/user/py/
>>> pprint.pprint(sys.path)
[
#that was easy
]

Y me gusta porque puedo tener una carpeta para algunas herramientas aleatorias y no hacer que formen parte de paquetes ni nada, y aún así tener acceso a algunas (o todas) de ellas en un par de líneas de código.

Droogans
fuente
3

La forma más fácil que encuentro es crear un archivo "any_name.pth" y ponerlo en su carpeta "\ Lib \ site-packages". Debería encontrar esa carpeta donde esté instalado Python.

En ese archivo, ponga una lista de directorios donde desea guardar los módulos para importar. Por ejemplo, haga una línea en ese archivo como esta:

C: \ Usuarios \ ejemplo ... \ ejemplo

Podrá saber que funciona ejecutando esto en Python:

import sys
for line in sys: print line

Verá su directorio impreso, entre otros desde donde también puede importar. Ahora puede importar un archivo "mymodule.py" que se encuentra en ese directorio tan fácilmente como:

import mymodule

Esto no importará subcarpetas. Para eso, puede imaginar la creación de un script de Python para crear un archivo .pth que contenga todas las subcarpetas de una carpeta que defina. Quizás se ejecute al inicio.

KieranPC
fuente
0

Nueva opción para preguntas anteriores.
Al instalar el fail2banpaquete en Debian, parece que está codificado para instalar en /usr/lib/python3/dist-packages/fail2banuna ruta que no está en python3 sys.path.


> python3
Python 3.7.3 (v3.7.3:ef4ec6ed12, Jun 25 2019, 18:51:50)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/usr/lib/python37.zip', '/usr/lib/python3.7', '/usr/lib/python3.7/lib-dynload', '/usr/lib/python3.7/site-packages']
>>>

entonces, en lugar de simplemente copiar, (bash) vinculé la biblioteca a versiones más nuevas.
Las futuras actualizaciones de la aplicación original también se aplicarán automáticamente a las versiones vinculadas.

 if [ -d /usr/lib/python3/dist-packages/fail2ban ]
   then
      for d in /usr/lib/python3.*
      do
         [ -d ${d}/fail2ban ] || \
            ln -vs /usr/lib/python3/dist-packages/fail2ban ${d}/
      done
   fi
fcm
fuente