para - Recuperando la ruta del módulo python




modulos y paquetes python (11)

Quiero detectar si el módulo ha cambiado. Ahora, usar inotify es simple, solo necesita saber el directorio del que desea recibir notificaciones.

¿Cómo recupero la ruta de un módulo en python?


Utilidad de línea de comandos

Puedes ajustarlo a una utilidad de línea de comandos,

python-which <package name>

Crea /usr/local/bin/python-which

#!/usr/bin/env python

import importlib
import os
import sys

args = sys.argv[1:]
if len(args) > 0:
    module = importlib.import_module(args[0])
    print os.path.dirname(module.__file__)

Hazlo ejecutable

sudo chmod +x /usr/local/bin/python-which

Así que pasé una buena cantidad de tiempo tratando de hacer esto con py2exe. El problema era obtener la carpeta base del script si se estaba ejecutando como un script de python o como un ejecutable de py2exe. También para que funcione, ya sea que se esté ejecutando desde la carpeta actual, otra carpeta o (esta fue la más difícil) desde la ruta del sistema.

Finalmente, utilicé este enfoque, utilizando sys.frozen como indicador de ejecución en py2exe:

import os,sys
if hasattr(sys,'frozen'): # only when running in py2exe this exists
    base = sys.prefix
else: # otherwise this is a regular python script
    base = os.path.dirname(os.path.realpath(__file__))

Desde los módulos de un paquete de python tuve que referirme a un archivo que se encontraba en el mismo directorio que el paquete. Ex.

some_dir/
  maincli.py
  top_package/
    __init__.py
    level_one_a/
      __init__.py
      my_lib_a.py
      level_two/
        __init__.py
        hello_world.py
    level_one_b/
      __init__.py
      my_lib_b.py

Así que en lo anterior tuve que llamar a maincli.py desde el módulo my_lib_a.py sabiendo que top_package y maincli.py están en el mismo directorio. Así es como obtengo el camino a maincli.py:

import sys
import os
import imp


class ConfigurationException(Exception):
    pass


# inside of my_lib_a.py
def get_maincli_path():
    maincli_path = os.path.abspath(imp.find_module('maincli')[1])
    # top_package = __package__.split('.')[0]
    # mod = sys.modules.get(top_package)
    # modfile = mod.__file__
    # pkg_in_dir = os.path.dirname(os.path.dirname(os.path.abspath(modfile)))
    # maincli_path = os.path.join(pkg_in_dir, 'maincli.py')

    if not os.path.exists(maincli_path):
        err_msg = 'This script expects that "maincli.py" be installed to the '\
        'same directory: "{0}"'.format(maincli_path)
        raise ConfigurationException(err_msg)

    return maincli_path

Basado en la publicación de PlasmaBinturong modifiqué el código.


Esto fue trivial.

Cada módulo tiene una variable __file__ que muestra su ruta relativa desde donde se encuentra ahora.

Por lo tanto, obtener un directorio para que el módulo lo notifique es simple como:

os.path.dirname(__file__)

Intentaré abordar algunas variaciones en esta pregunta también:

  1. Encontrar el camino del script llamado.
  2. Encontrar la ruta del script actualmente en ejecución
  3. Encontrar el directorio del script llamado.

(Algunas de estas preguntas se formularon en SO, pero se cerraron como duplicados y se redirigieron aquí).

Advertencias de usar __file__

Para un módulo que ha importado:

import something
something.__file__ 

Devolverá la ruta absoluta del módulo. Sin embargo, dado el siguiente script foo.py:

#foo.py
print '__file__', __file__

Llamándolo con 'python foo.py' Devolverá simplemente 'foo.py'. Si añades un shebang:

#!/usr/bin/python 
#foo.py
print '__file__', __file__

y llámelo usando ./foo.py, devolverá './foo.py'. Llamándolo desde un directorio diferente (por ejemplo, ponga foo.py en la barra de directorios), y luego llame a

python bar/foo.py

o agregando un shebang y ejecutando el archivo directamente:

bar/foo.py

devolverá 'bar / foo.py' (la ruta relativa ).

Encontrar el directorio

Ahora, desde allí para obtener el directorio, os.path.dirname(__file__) también puede ser complicado. Al menos en mi sistema, devuelve una cadena vacía si la llama desde el mismo directorio que el archivo. ex.

# foo.py
import os
print '__file__ is:', __file__
print 'os.path.dirname(__file__) is:', os.path.dirname(__file__)

saldrá:

__file__ is: foo.py
os.path.dirname(__file__) is: 

En otras palabras, devuelve una cadena vacía, por lo que esto no parece confiable si desea usarla para el archivo actual (a diferencia del archivo de un módulo importado). Para evitar esto, puede envolverlo en una llamada a abspath:

# foo.py
import os
print 'os.path.abspath(__file__) is:', os.path.abspath(__file__)
print 'os.path.dirname(os.path.abspath(__file__)) is:', os.path.dirname(os.path.abspath(__file__))

que produce algo como:

os.path.abspath(__file__) is: /home/user/bar/foo.py
os.path.dirname(os.path.abspath(__file__)) is: /home/user/bar

Tenga en cuenta que abspath () NO resuelve enlaces simbólicos. Si quieres hacer esto, usa realpath () en su lugar. Por ejemplo, haciendo un enlace simbólico file_import_testing_link apuntando a file_import_testing.py, con el siguiente contenido:

import os
print 'abspath(__file__)',os.path.abspath(__file__)
print 'realpath(__file__)',os.path.realpath(__file__)

ejecutando se imprimirán rutas absolutas algo así como:

abspath(__file__) /home/user/file_test_link
realpath(__file__) /home/user/file_test.py

file_import_testing_link -> file_import_testing.py

Utilizando inspeccionar

@SummerBreeze menciona el uso del módulo de inspect .

Esto parece funcionar bien, y es bastante conciso, para módulos importados:

import os
import inspect
print 'inspect.getfile(os) is:', inspect.getfile(os)

Retorna obedientemente el camino absoluto. Sin embargo, para encontrar la ruta del script que se está ejecutando actualmente, no vi una forma de usarlo.


Me gustaría contribuir con un escenario común (en Python 3) y explorar algunos enfoques.

La función incorporada open() acepta una ruta relativa o absoluta como su primer argumento. La ruta relativa se trata como relativa al directorio de trabajo actual, por lo que se recomienda pasar la ruta absoluta al archivo.

En pocas palabras, si ejecuta un archivo de script con el siguiente código, no se garantiza que el archivo example.txt se creará en el mismo directorio donde se encuentra el archivo de script:

with open('example.txt', 'w'):
    pass

Para arreglar este código necesitamos obtener la ruta al script y hacerlo absoluto. Para garantizar que la ruta sea absoluta, simplemente usamos la función os.path.realpath() . Para obtener la ruta al script hay varias funciones comunes que devuelven varios resultados de ruta:

  • os.getcwd()
  • os.path.realpath('example.txt')
  • sys.argv[0]
  • __file__

Ambas funciones, os.getcwd() y os.path.realpath() devuelven los resultados de la ruta en función del directorio de trabajo actual . Generalmente no es lo que queremos. El primer elemento de la lista sys.argv es la ruta del script raíz (el script que ejecuta) independientemente de si llama a la lista en el propio script raíz o en cualquiera de sus módulos. Puede ser útil en algunas situaciones. La variable __file__ contiene la ruta del módulo desde el que se ha llamado.

El siguiente código crea correctamente un archivo example.txt en el mismo directorio donde se encuentra el script:

filedir = os.path.dirname(os.path.realpath(__file__))
filepath = os.path.join(filedir, 'example.txt')

with open(filepath, 'w'):
    pass

Si desea conocer la ruta absoluta desde su script, puede usar el objeto Path :

from pathlib import Path

print(Path().absolute())
print(Path().resolve('.'))
print(Path().cwd())

método cwd ()

Devuelve un nuevo objeto de ruta que representa el directorio actual (como lo devuelve os.getcwd ())

método resolver ()

Hacer el camino absoluto, resolviendo cualquier enlace simbólico. Se devuelve un nuevo objeto de ruta:


Si desea hacer esto dinámicamente en un "programa" intente este código:
Mi punto es que puede que no sepa el nombre exacto del módulo para "codificarlo". Puede seleccionarse de una lista o puede no estar ejecutándose actualmente para usar __file__.

(Lo sé, no funcionará en Python 3)

global modpath
modname = 'os' #This can be any module name on the fly
#Create a file called "modname.py"
f=open("modname.py","w")
f.write("import "+modname+"\n")
f.write("modpath = "+modname+"\n")
f.close()
#Call the file with execfile()
execfile('modname.py')
print modpath
<module 'os' from 'C:\Python27\lib\os.pyc'>

Traté de deshacerme del problema "global" pero encontré casos en los que no funcionó, creo que "execfile ()" se puede emular en Python 3. Ya que está en un programa, se puede poner fácilmente en un método o módulo para reutilizar.


simplemente puede importar su módulo y luego golpear su nombre y obtendrá su ruta completa

>>> import os
>>> os
<module 'os' from 'C:\\Users\\Hassan Ashraf\\AppData\\Local\\Programs\\Python\\Python36-32\\lib\\os.py'>
>>>

import a_module
print a_module.__file__

En realidad, le dará la ruta al archivo .pyc que se cargó, al menos en Mac OS X. Así que supongo que puede hacer

import os
path = os.path.dirname(amodule.__file__)

También puedes probar

path = os.path.abspath(amodule.__file__)

Para obtener el directorio para buscar cambios.


import os
path = os.path.abspath(__file__)
dir_path = os.path.dirname(path)




inotify