2 votes

Importations dynamiques + importations relatives dans Python 3

J'ai un Python 3 dans lequel j'importe dynamiquement des modules à partir du disque, en utilisant imp.load_module . Mais j'ai rencontré un problème où les importations relatives échouent, lorsque l'importation relative se produit à l'intérieur d'un module importé dynamiquement.

D'après ce que j'ai lu, j'en suis arrivé à la conclusion que seuls les __file__ , __path__ , __package__ y __name__ ont été utilisées par l'importateur par défaut pour déterminer le chemin d'une importation. Pourtant, j'ai vérifié ces éléments dans le code ci-dessous, et il échoue toujours lorsqu'il est importé dynamiquement. (Il fonctionne lorsqu'il est importé dans l'interpréteur avec un fichier sys.path )

# File structure:
# [root]
#   __init__.py
#   board.py
#   test.py

# Contents of 'board.py':
import os, sys
import root  # Already imported... just need a reference

ROOT_DIR = os.path.dirname(root.__file__)
assert root is sys.modules['root']
assert root.__package__ is None
assert root.__name__ == 'root'
assert root.__file__ == os.path.join(ROOT_DIR, '__init__.py')
assert not hasattr(root, '__path__')

xx = object()
assert xx is sys.modules['root.board'].xx
assert __package__ is None
assert __name__ == 'root.board'
assert __file__ == os.path.join(ROOT_DIR, 'board.py')
assert not hasattr(sys.modules['root.board'], '__path__')

assert os.path.isfile(os.path.join(ROOT_DIR, 'test.py'))
from . import test  # ImportError('cannot import name test',)

Mais si je pirate sys.path et réimporter le paquet actuel juste avant l'échec de l'importation, cela fonctionne :

oldroot = root
del sys.modules['root']
sys.path.append(os.path.dirname(ROOT_DIR))
import root
from . import test  # No error here

De plus, les quatre attributs en or mentionnés ci-dessus sont les mêmes dans les nouveaux et les anciens paquets :

assert oldroot.__package__ == root.__package__
assert oldroot.__name__ == root.__name__
assert oldroot.__file__ == root.__file__
assert not hasattr(root, '__path__')

Ce qui signifie que __package__ , __name__ , __file__ y __path__ ne peut pas tout expliquer. Existe-t-il d'autres attributs que Python utilise pour localiser les importations ? Qu'est-ce que j'ai négligé qui pourrait faire échouer l'importation ?

1voto

ncoghlan Points 10779

L'absence de root.__path__ est suspecte (cela signifie que Python ne considère pas la valeur root pour être un paquet).

Le fait que les deux load_module() sont effectués avec une valeur de type 1 (un module) au lieu de la première ayant un type de 5 (un paquet) est également très douteux.

Utilisez-vous imp.find_module() pour déterminer les entrées correctes dans le imp.load_module() appeler ?

Pour un paquet, l'entrée dans imp.load_module() devrait ressembler à ceci :

# demo is a package in the current directory for this example
>>> info = imp.find_module('demo')
>>> info
(None, 'demo', ('', '', 5))
>>> demo = imp.load_module('demo', *info)
>>> demo.__path__
['demo']

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X