TL; DR:
Sur Python 3.3, vous n'avez rien à faire, n'en mettez tout simplement pas __init__.pydans les répertoires de vos packages d'espace de noms et cela fonctionnera. Sur la version antérieure à la version 3.3, choisissez la pkgutil.extend_path()solution plutôt que pkg_resources.declare_namespace()celle, car elle est à l'épreuve du temps et déjà compatible avec les packages d'espace de noms implicites.
Python 3.3 introduit les packages d'espace de noms implicites, voir PEP 420 .
Cela signifie qu'il existe désormais trois types d'objets qui peuvent être créés par un import foo:
- Un module représenté par un
foo.pyfichier
- Un package régulier, représenté par un répertoire
foocontenant un __init__.pyfichier
- Un package d'espace de noms, représenté par un ou plusieurs répertoires
foosans aucun __init__.pyfichier
Les packages sont aussi des modules, mais ici je veux dire "module non-package" quand je dis "module".
Il recherche sys.pathd'abord un module ou un package standard. S'il réussit, il arrête la recherche et crée et initialise le module ou le package. S'il n'a trouvé aucun module ou package normal, mais qu'il a trouvé au moins un répertoire, il crée et initialise un package d'espace de noms.
Les modules et les packages normaux sont __file__définis sur le .pyfichier à partir duquel ils ont été créés. Les packages standard et d'espace de noms sont __path__définis sur le ou les répertoires à partir desquels ils ont été créés.
Lorsque vous le faites import foo.bar, la recherche ci-dessus se produit d'abord pour foo, puis si un package a été trouvé, la recherche barest effectuée avec foo.__path__comme chemin de recherche au lieu de sys.path. Si foo.baron trouve, fooet foo.barsont créés et initialisés.
Alors, comment se mélangent les packages standards et les packages d'espace de noms? Normalement, ce n'est pas le cas, mais l'ancienne pkgutilméthode de package d'espace de noms explicite a été étendue pour inclure des packages d'espace de noms implicites.
Si vous avez un package régulier existant qui a un __init__.pycomme ceci:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
... le comportement hérité consiste à ajouter tous les autres packages réguliers sur le chemin recherché à son __path__. Mais dans Python 3.3, il ajoute également des packages d'espace de noms.
Vous pouvez donc avoir la structure de répertoires suivante:
├── path1
│ └── package
│ ├── __init__.py
│ └── foo.py
├── path2
│ └── package
│ └── bar.py
└── path3
└── package
├── __init__.py
└── baz.py
... et tant que les deux __init__.pyont les extend_pathlignes (et path1, path2et path3sont dans votre sys.path) import package.foo, import package.baret import package.baztout fonctionnera.
pkg_resources.declare_namespace(__name__) n'a pas été mis à jour pour inclure les packages d'espace de noms implicites.