Importations relatives dans Python 3

715

Je souhaite importer une fonction à partir d'un autre fichier dans le même répertoire.

Parfois, cela fonctionne pour moi, from .mymodule import myfunctionmais parfois je reçois un:

SystemError: Parent module '' not loaded, cannot perform relative import

Parfois ça marche avec from mymodule import myfunction, mais parfois j'obtiens aussi un:

SystemError: Parent module '' not loaded, cannot perform relative import

Je ne comprends pas la logique ici, et je n'ai trouvé aucune explication. Cela semble complètement aléatoire.

Quelqu'un pourrait-il m'expliquer quelle est la logique derrière tout cela?

John Smith facultatif
la source
76
Cela signifie que vous exécutez un module à l'intérieur du package en tant que script. Exécutez uniquement les scripts en dehors du package.
Martijn Pieters
3
Vous devriez probablement définir les conditions que vous avez celles que vous mentionnez «parfois». Je comprends que vous ne voulez pas dire que vous avez des erreurs aléatoires.
joaquin
15
@MartijnPieters: eh bien, malheureusement, ce module doit être à l'intérieur du package, et il doit également être exécutable en tant que script, parfois. Une idée comment je pourrais y arriver?
John Smith Facultatif
22
@JohnSmithOptional: Mélanger les scripts à l'intérieur des packages est délicat et devrait être évité si possible. Utilisez un script wrapper qui importe le package et exécute votre fonction "scripty" à la place.
Martijn Pieters
3
Semble malheureux. J'ai créé un module de base avec des classes / méthodes qui peuvent analyser / analyser un certain type de fichier, et j'ai également (principalement pour moi) des modules secondaires et des scripts séparés qui l'importent - ceux-ci peuvent masser / convertir ces fichiers. Mais j'aime aussi pouvoir remettre ce fichier core unique (pas un package complexe entier) à l'utilisateur final afin qu'il puisse facilement le placer à côté de son fichier et l'exécuter. Dans ce "mode script", il analyse et analyse le fichier et l'encodage, répertorie divers champs / valeurs / caractères spéciaux et fournit un rapport. Mais cela ne modifie pas réellement le fichier. Anti-motif?
Jon Coombs

Réponses:

529

malheureusement, ce module doit être à l'intérieur du package, et il doit également être exécutable en tant que script, parfois. Une idée comment je pourrais y arriver?

Il est assez courant d'avoir une disposition comme celle-ci ...

main.py
mypackage/
    __init__.py
    mymodule.py
    myothermodule.py

... avec un mymodule.pycomme ça ...

#!/usr/bin/env python3

# Exported function
def as_int(a):
    return int(a)

# Test function for module  
def _test():
    assert as_int('1') == 1

if __name__ == '__main__':
    _test()

... un myothermodule.pycomme ça ...

#!/usr/bin/env python3

from .mymodule import as_int

# Exported function
def add(a, b):
    return as_int(a) + as_int(b)

# Test function for module  
def _test():
    assert add('1', '1') == 2

if __name__ == '__main__':
    _test()

... et un main.pycomme ça ...

#!/usr/bin/env python3

from mypackage.myothermodule import add

def main():
    print(add('1', '1'))

if __name__ == '__main__':
    main()

... qui fonctionne bien lorsque vous exécutez main.pyou mypackage/mymodule.py, mais échoue avec mypackage/myothermodule.py, en raison de l'importation relative ...

from .mymodule import as_int

La façon dont vous êtes censé l'exécuter est ...

python3 -m mypackage.myothermodule

... mais c'est un peu verbeux, et ne se mélange pas bien avec une ligne de shebang comme #!/usr/bin/env python3.

La solution la plus simple pour ce cas, en supposant que le nom mymoduleest unique au monde, serait d'éviter d'utiliser des importations relatives et d'utiliser simplement ...

from mymodule import as_int

... bien que, s'il n'est pas unique ou que la structure de votre package soit plus complexe, vous devrez inclure le répertoire contenant le répertoire de votre package PYTHONPATHet le faire comme ceci ...

from mypackage.mymodule import as_int

... ou si vous voulez que cela fonctionne "out of the box", vous pouvez d'abord frober le PYTHONPATHcode in avec ceci ...

import sys
import os

PACKAGE_PARENT = '..'
SCRIPT_DIR = os.path.dirname(os.path.realpath(os.path.join(os.getcwd(), os.path.expanduser(__file__))))
sys.path.append(os.path.normpath(os.path.join(SCRIPT_DIR, PACKAGE_PARENT)))

from mypackage.mymodule import as_int

C'est une sorte de douleur, mais il y a une idée de pourquoi dans un e-mail écrit par un certain Guido van Rossum ...

Je suis -1 sur ce point et sur tout autre twiddlings proposé de la __main__ machine. Le seul cas d'utilisation semble être l'exécution de scripts qui se trouvent à l'intérieur d'un répertoire de module, que j'ai toujours vu comme un contre-modèle. Pour me faire changer d'avis, il faudrait me convaincre que non.

Que l'exécution de scripts à l'intérieur d'un package soit un contre-modèle ou non est subjectif, mais personnellement je le trouve vraiment utile dans un package que je possède qui contient des widgets wxPython personnalisés, donc je peux exécuter le script pour n'importe lequel des fichiers source pour afficher un wx.Framecontenant uniquement ce widget à des fins de test.

Aya
la source
7
Une meilleure façon d'obtenir SCRIPTDIR est donnée dans un commentaire sur Importer un module à partir d'un chemin relatif, comme os.path.realpath(os.path.dirname(inspect.getfile(inspect.currentframe())))si vous fileêtes sûr que votre module a toujours un bon que vous pourriez également utiliser os.path.realpath(os.path.dirname(__file__)).
marcz
2
Vous pouvez étendre votre PYTHONPATH en appliquant un extrait de code plus court et plus lisible: sys.path.append( os.path.join( os.path.dirname(__file__), os.path.pardir ) )
Alex-Bogdanov
12
...which I've always seen as an antipattern.Je ne vois pas comment c'est un anti pattern ... Il semble qu'il serait super pratique de simplement faire fonctionner intuitivement les importations relatives. Je veux juste pouvoir importer des choses dont je sais qu'elles se trouvent dans le même répertoire. Je me demande quel était son raisonnement
YungGun
9
Guido frappe encore: nixer des trucs qui auraient pu être utiles. Eh bien, cela n'arrivera plus.
javadba
4
C'est la chose la plus triste que j'aie jamais vue à propos de Python.
AtilioA
265

Explication

À partir de PEP 328

Les importations relatives utilisent l'attribut __name__ d'un module pour déterminer la position de ce module dans la hiérarchie des packages. Si le nom du module ne contient aucune information sur le package (par exemple, il est défini sur '__main__'), les importations relatives sont résolues comme si le module était un module de niveau supérieur , quel que soit l'emplacement du module sur le système de fichiers.

À un moment donné, le PEP 338 est entré en conflit avec le PEP 328 :

... les importations relatives s'appuient sur __name__ pour déterminer la position actuelle du module dans la hiérarchie des packages. Dans un module principal, la valeur de __name__ est toujours '__main__' , donc les importations relatives explicites échoueront toujours (car elles ne fonctionnent que pour un module à l'intérieur d'un package)

et pour résoudre le problème, le PEP 366 a introduit la variable de niveau supérieur __package__:

En ajoutant un nouvel attribut au niveau du module, ce PEP permet aux importations relatives de fonctionner automatiquement si le module est exécuté à l'aide du commutateur -m . Une petite quantité de passe-partout dans le module lui-même permettra aux importations relatives de fonctionner lorsque le fichier sera exécuté par son nom. [...] Lorsqu'il [l'attribut] est présent, les importations relatives seront basées sur cet attribut plutôt que sur l' attribut module __name__ . [...] Lorsque le module principal est spécifié par son nom de fichier, l' attribut __package__ sera défini sur Aucun . [...] Lorsque le système d'importation rencontre une importation relative explicite dans un module sans __package__ défini (ou avec défini sur Aucun), il calcule et stocke la valeur correcte (__name __. rpartition ('.') [0] pour les modules normaux et __name__ pour les modules d'initialisation de paquet)

(c'est moi qui souligne)

Si __name__est '__main__', __name__.rpartition('.')[0]renvoie une chaîne vide. C'est pourquoi il y a un littéral de chaîne vide dans la description de l'erreur:

SystemError: Parent module '' not loaded, cannot perform relative import

La partie pertinente de la PyImport_ImportModuleLevelObjectfonction de CPython :

if (PyDict_GetItem(interp->modules, package) == NULL) {
    PyErr_Format(PyExc_SystemError,
            "Parent module %R not loaded, cannot perform relative "
            "import", package);
    goto error;
}

CPython lève cette exception s'il n'a pas pu trouver package(le nom du package) dans interp->modules(accessible en tant que sys.modules). Puisqu'il sys.moduless'agit d' un "dictionnaire qui mappe les noms des modules aux modules qui ont déjà été chargés" , il est désormais clair que le module parent doit être explicitement importé en absolu avant d'effectuer une importation relative .

Remarque: Le correctif du problème 18018 a ajouté un autre ifbloc , qui sera exécuté avant le code ci-dessus:

if (PyUnicode_CompareWithASCIIString(package, "") == 0) {
    PyErr_SetString(PyExc_ImportError,
            "attempted relative import with no known parent package");
    goto error;
} /* else if (PyDict_GetItem(interp->modules, package) == NULL) {
    ...
*/

Si package(comme ci-dessus) est une chaîne vide, le message d'erreur sera

ImportError: attempted relative import with no known parent package

Cependant, vous ne verrez cela qu'en Python 3.6 ou plus récent.

Solution n ° 1: exécutez votre script à l'aide de -m

Considérez un répertoire (qui est un package Python ):

.
├── package
│   ├── __init__.py
│   ├── module.py
│   └── standalone.py

Tous les fichiers du package commencent par les 2 mêmes lignes de code:

from pathlib import Path
print('Running' if __name__ == '__main__' else 'Importing', Path(__file__).resolve())

J'inclus ces deux lignes uniquement pour rendre l'ordre des opérations évident. Nous pouvons les ignorer complètement, car ils n'affectent pas l'exécution.

__init__.py et module.py ne contiennent que ces deux lignes (c'est-à-dire qu'elles sont effectivement vides).

standalone.py tente en outre d'importer module.py via l'importation relative:

from . import module  # explicit relative import

Nous savons bien que /path/to/python/interpreter package/standalone.pycela échouera. Cependant, nous pouvons exécuter le module avec l' -moption de ligne de commande qui "recherchera sys.pathle module nommé et exécutera son contenu en tant que __main__module" :

vaultah@base:~$ python3 -i -m package.standalone
Importing /home/vaultah/package/__init__.py
Running /home/vaultah/package/standalone.py
Importing /home/vaultah/package/module.py
>>> __file__
'/home/vaultah/package/standalone.py'
>>> __package__
'package'
>>> # The __package__ has been correctly set and module.py has been imported.
... # What's inside sys.modules?
... import sys
>>> sys.modules['__main__']
<module 'package.standalone' from '/home/vaultah/package/standalone.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/package/module.py'>
>>> sys.modules['package']
<module 'package' from '/home/vaultah/package/__init__.py'>

-meffectue toutes les opérations d'importation pour vous et définit automatiquement __package__, mais vous pouvez le faire vous-même dans le

Solution n ° 2: définissez __package__ manuellement

Veuillez le considérer comme une preuve de concept plutôt qu'une solution réelle. Il n'est pas bien adapté à une utilisation dans le code du monde réel.

PEP 366 a une solution de contournement à ce problème, cependant, il est incomplet, car le réglage __package__seul n'est pas suffisant. Vous allez devoir importer au moins N packages précédents dans la hiérarchie des modules, où N est le nombre de répertoires parents (par rapport au répertoire du script) qui sera recherché pour le module importé.

Donc,

  1. Ajoutez le répertoire parent du Nème prédécesseur du module actuel àsys.path

  2. Supprimer le répertoire du fichier actuel de sys.path

  3. Importez le module parent du module actuel en utilisant son nom complet

  4. Définissez __package__le nom complet de 2

  5. Effectuer l'importation relative

J'emprunterai des fichiers à la Solution # 1 et ajouterai d'autres sous-packages:

package
├── __init__.py
├── module.py
└── subpackage
    ├── __init__.py
    └── subsubpackage
        ├── __init__.py
        └── standalone.py

Cette fois, standalone.py importera module.py à partir du package de package à l'aide de l'importation relative suivante

from ... import module  # N = 3

Nous devrons faire précéder cette ligne du code passe-partout pour que cela fonctionne.

import sys
from pathlib import Path

if __name__ == '__main__' and __package__ is None:
    file = Path(__file__).resolve()
    parent, top = file.parent, file.parents[3]

    sys.path.append(str(top))
    try:
        sys.path.remove(str(parent))
    except ValueError: # Already removed
        pass

    import package.subpackage.subsubpackage
    __package__ = 'package.subpackage.subsubpackage'

from ... import module # N = 3

Il nous permet d'exécuter standalone.py par nom de fichier:

vaultah@base:~$ python3 package/subpackage/subsubpackage/standalone.py
Running /home/vaultah/package/subpackage/subsubpackage/standalone.py
Importing /home/vaultah/package/__init__.py
Importing /home/vaultah/package/subpackage/__init__.py
Importing /home/vaultah/package/subpackage/subsubpackage/__init__.py
Importing /home/vaultah/package/module.py

Une solution plus générale enveloppée dans une fonction peut être trouvée ici . Exemple d'utilisation:

if __name__ == '__main__' and __package__ is None:
    import_parents(level=3) # N = 3

from ... import module
from ...module.submodule import thing

Solution n ° 3: utilisez les importations absolues et les setuptools

Les étapes sont -

  1. Remplacer les importations relatives explicites par des importations absolues équivalentes

  2. Installer packagepour le rendre importable

Par exemple, la structure du répertoire peut être la suivante

.
├── project
│   ├── package
│   │   ├── __init__.py
│   │   ├── module.py
│   │   └── standalone.py
│   └── setup.py

setup.py est

from setuptools import setup, find_packages
setup(
    name = 'your_package_name',
    packages = find_packages(),
)

Les autres fichiers ont été empruntés à la solution n ° 1 .

L'installation vous permettra d'importer le package quel que soit votre répertoire de travail (en supposant qu'il n'y aura aucun problème de dénomination).

Nous pouvons modifier standalone.py pour utiliser cet avantage (étape 1):

from package import module  # absolute import

Modifiez votre répertoire de travail projectet exécutez /path/to/python/interpreter setup.py install --user( --userinstalle le package dans votre répertoire site-packages ) (étape 2):

vaultah@base:~$ cd project
vaultah@base:~/project$ python3 setup.py install --user

Vérifions qu'il est désormais possible d'exécuter standalone.py en tant que script:

vaultah@base:~/project$ python3 -i package/standalone.py
Running /home/vaultah/project/package/standalone.py
Importing /home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/__init__.py
Importing /home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py
>>> module
<module 'package.module' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py'>
>>> import sys
>>> sys.modules['package']
<module 'package' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/__init__.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py'>

Remarque : Si vous décidez de suivre cette voie, il serait préférable d'utiliser des environnements virtuels pour installer les packages de manière isolée.

Solution n ° 4: utilisez des importations absolues et du code standard

Franchement, l'installation n'est pas nécessaire - vous pouvez ajouter du code passe-partout à votre script pour faire fonctionner les importations absolues.

Je vais emprunter des fichiers à la Solution # 1 et changer standalone.py :

  1. Ajoutez le répertoire parent du package à sys.path avant d' essayer d'importer quoi que ce soit du package à l' aide d'importations absolues:

    import sys
    from pathlib import Path # if you haven't already done so
    file = Path(__file__).resolve()
    parent, root = file.parent, file.parents[1]
    sys.path.append(str(root))
    
    # Additionally remove the current file's directory from sys.path
    try:
        sys.path.remove(str(parent))
    except ValueError: # Already removed
        pass
  2. Remplacez l'importation relative par l'importation absolue:

    from package import module  # absolute import

standalone.py s'exécute sans problème:

vaultah@base:~$ python3 -i package/standalone.py
Running /home/vaultah/package/standalone.py
Importing /home/vaultah/package/__init__.py
Importing /home/vaultah/package/module.py
>>> module
<module 'package.module' from '/home/vaultah/package/module.py'>
>>> import sys
>>> sys.modules['package']
<module 'package' from '/home/vaultah/package/__init__.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/package/module.py'>

Je pense que je dois vous avertir: essayez de ne pas le faire, surtout si votre projet a une structure complexe.


En guise de note complémentaire , le PEP 8 recommande l'utilisation d'importations absolues, mais déclare que dans certains scénarios, les importations relatives explicites sont acceptables:

Les importations absolues sont recommandées, car elles sont généralement plus lisibles et ont tendance à mieux se comporter (ou au moins à donner de meilleurs messages d'erreur). [...] Cependant, les importations relatives explicites sont une alternative acceptable aux importations absolues, en particulier lorsqu'il s'agit de présentations de colis complexes où l'utilisation d'importations absolues serait inutilement verbeuse.

vaultah
la source
3
Est-il possible de définir __package__manuellement si le nom est __main__pour résoudre le problème?
Paulo Scardine
Merci, belles réponses! J'ai pu charger le module à l'aide du impmodule et le régler en __package__conséquence, mais le résultat est clairement un anti-modèle.
Paulo Scardine
Je reçois l'erreur AttributeError: 'PosixPath' object has no attribute 'path'.
utilisateur
Merci pour la réponse rapide. J'utilise le package nltk, j'obtiens une erreur: `File" /usr/local/lib/python3.5/dist-packages/nltk/__init__.py ", ligne 115, dans <module> depuis nltk.decorators importation du décorateur, mémorisation du fichier "/usr/local/lib/python3.5/dist-packages/nltk/decorators.py", ligne 23, dans <module> sys.path = [p pour p dans sys.path si "nltk "not in p] File" /usr/local/lib/python3.5/dist-packages/nltk/decorators.py ", ligne 23, dans <listcomp> sys.path = [p pour p dans sys.path si" nltk "pas dans p] TypeError: l'argument de type 'PosixPath' n'est pas itérable`
utilisateur
1
Vous pouvez également importer un fichier par chemin de fichier (relatif aussi): docs.python.org/3/library/…
Ctrl-C
87

Mettez ceci dans le fichier __init__.py de votre paquet :

# For relative imports to work in Python 3.6
import os, sys; sys.path.append(os.path.dirname(os.path.realpath(__file__)))

En supposant que votre colis est comme ceci:

├── project
   ├── package
      ├── __init__.py
      ├── module1.py
      └── module2.py
   └── setup.py

Utilisez maintenant des importations régulières dans votre package, comme:

# in module2.py
from module1 import class1

Cela fonctionne à la fois en python 2 et 3.

am5
la source
1
fonctionne-t-il si nous le conditionnons en tant que weel
Alex Punnen
1
Je pense également que cela mérite plus de votes. Mettre cela dans chaque __init__.pysolution résoudra essentiellement toutes les erreurs d'importation relatives.
frankliuao
3
Je ne peux pas parler pour les autres, mais j'ai tendance à éviter de modifier sys.pathcar je crains que cela n'affecte un autre code. (En partie parce que je ne connais pas les subtilités de son fonctionnement.)
pianoJames
@pianoJames Je sais ce que vous voulez dire, cette solution magique (apparemment, après beaucoup de boulot) semble un peu trop facile. Mais ça marche. Serait intéressé de ne pas savoir de ceux qui savent si cela a des effets secondaires négatifs.
Jon
J'utilise ceci maintenant: et jusqu'ici tout va bien.
javadba
38

J'ai rencontré ce problème. Une solution de contournement est importée via un bloc if / else comme suit:

#!/usr/bin/env python3
#myothermodule

if __name__ == '__main__':
    from mymodule import as_int
else:
    from .mymodule import as_int


# Exported function
def add(a, b):
    return as_int(a) + as_int(b)

# Test function for module  
def _test():
    assert add('1', '1') == 2

if __name__ == '__main__':
    _test()
coursier
la source
29
ce n'est pas une très bonne solution. aussi, nu except:est mauvais. utilisez except ImportError:plutôt!
ThiefMaster
6
C'est SystemErrorici. (Py 3.4)
Avi
8
Ce n'est pas une idée terrible, mais il serait préférable de détecter l'importation à utiliser plutôt que d'essayer / sauf. Quelque chose comme if __name__ == '__main__': from mymod import as_int; else: from .mymod import as_int.
Perkins
@Perkins Eh bien ... dans la plupart des cas, ce ne serait pas le cas . Je pense que les importations relatives peuvent être l'exception cependant.
wizzwizz4
8

J'espère que cela sera utile à quelqu'un là-bas - j'ai parcouru une demi-douzaine de messages stackoverflow essayant de comprendre les importations relatives similaires à ce qui est affiché ci-dessus ici. J'ai tout configuré comme suggéré mais je frappais toujoursModuleNotFoundError: No module named 'my_module_name'

Comme je ne faisais que développer localement et jouer, je n'avais pas créé / exécuté de setup.pyfichier. Je n'avais pas non plus apparemment réglé mon PYTHONPATH.

J'ai réalisé que lorsque j'ai exécuté mon code comme je l'avais été lorsque les tests étaient dans le même répertoire que le module, je n'ai pas pu trouver mon module:

$ python3 test/my_module/module_test.py                                                                                                               2.4.0
Traceback (most recent call last):
  File "test/my_module/module_test.py", line 6, in <module>
    from my_module.module import *
ModuleNotFoundError: No module named 'my_module'

Cependant, lorsque j'ai spécifié explicitement le chemin, les choses ont commencé à fonctionner:

$ PYTHONPATH=. python3 test/my_module/module_test.py                                                                                                  2.4.0
...........
----------------------------------------------------------------------
Ran 11 tests in 0.001s

OK

Donc, si quelqu'un a essayé quelques suggestions, pense que son code est correctement structuré et se trouve toujours dans une situation similaire à la mienne, essayez l'une des opérations suivantes si vous n'exportez pas le répertoire en cours vers votre PYTHONPATH:

  1. Exécutez votre code et incluez explicitement le chemin comme ceci: $ PYTHONPATH=. python3 test/my_module/module_test.py
  2. Pour éviter d'appeler PYTHONPATH=., créez un setup.pyfichier avec un contenu comme celui-ci et exécutez python setup.py developmentpour ajouter des packages au chemin:
# setup.py
from setuptools import setup, find_packages

setup(
    name='sample',
    packages=find_packages()
)
LaCroixed
la source
6

J'avais besoin d'exécuter python3 à partir du répertoire principal du projet pour le faire fonctionner.

Par exemple, si le projet a la structure suivante:

project_demo/
├── main.py
├── some_package/
   ├── __init__.py
   └── project_configs.py
└── test/
    └── test_project_configs.py

Solution

Je voudrais exécuter python3 dans le dossier project_demo / puis effectuer un

from some_package import project_configs
Árthur
la source
4

Pour éviter ce problème, j'ai imaginé une solution avec le package de reconditionnement , qui fonctionne pour moi depuis un certain temps. Il ajoute le répertoire supérieur au chemin lib:

import repackage
repackage.up()
from mypackage.mymodule import myfunction

Le reconditionnement peut effectuer des importations relatives qui fonctionnent dans un large éventail de cas, en utilisant une stratégie intelligente (inspection de la pile d'appels).

fralau
la source
De loin la solution la plus simple! Je vous remercie!
CodingInCircles
1
Merci! Au lieu d'essayer de donner la meilleure réponse, j'ai essayé de donner une réponse utilisable :-)
fralau
3

si les deux packages se trouvent dans votre chemin d'importation (sys.path) et que le module / classe que vous voulez est dans example / example.py, alors pour accéder à la classe sans importation relative, essayez:

from example.example import fkt
Salt999
la source
1

Je pense que la meilleure solution est de créer un package pour votre module: Voici plus d'informations sur la façon de le faire.

Une fois que vous avez un package dont vous n'avez pas à vous soucier de l'importation relative, vous pouvez simplement effectuer des importations absolues.

Taras Kucherenko
la source
0

J'ai eu un problème similaire: j'avais besoin d'un service Linux et d'un plugin cgi qui utilisent des constantes communes pour coopérer. La façon «naturelle» de le faire est de les placer dans le fichier init .py du paquet, mais je ne peux pas démarrer le plugin cgi avec le paramètre -m.

Ma solution finale était similaire à la solution n ° 2 ci-dessus:

import sys
import pathlib as p
import importlib

pp = p.Path(sys.argv[0])
pack = pp.resolve().parent

pkg = importlib.import_module('__init__', package=str(pack))

L'inconvénient est que vous devez préfixer les constantes (ou fonctions communes) avec pkg:

print(pkg.Glob)
Thomas Heckmann
la source