web-dev-qa-db-fra.com

Comment accomplir une importation relative en python

stuff/
    __init__.py
    mylib.py
    Foo/
        __init__.py
        main.py
        foo/
            __init__.py
            script.py

script.py veut importer mylib.py

Ceci est juste un exemple, mais je veux vraiment faire une importation relative d'un module dans un répertoire parent. J'ai essayé diverses choses et j'ai cette erreur ...

Attempted relative import beyond toplevel package

J'ai lu quelque part que le script à partir duquel le programme démarre ne devrait pas figurer dans le package, et j'ai essayé de modifier la structure pour cela, alors ...

stuff/
    mylib.py
    foo.py // equivalent of main.py in above
    foo/
        __init__.py
        script.py

mais a la même erreur.

Comment puis-je accomplir cela? Est-ce même une approche adéquate?

Edit: En Python 2

23
random

Après avoir un peu plus joué avec cela, j'ai compris comment le configurer, et par souci de spécificité, je n'utiliserai pas les noms de barres de foo. Le répertoire de mon projet est configuré comme ...

tools/
    core/
        object_editor/
            # files that need to use ntlib.py
            editor.py # see example at bottom
            __init__.py
        state_editor/
            # files that need to use ntlib.py
            __init__.py
        ntlib.py
        __init__.py # core is the top level package
    LICENSE
    state_editor.py # equivalent to main.py for the state editor
    object_editor.py # equivalent to main.py for the object editor

Une ligne dans object_editor.py ressemble à ...

from core.object_editor import editor

Une ligne dans editor.py ressemble à ...

from .. import ntlib

ou bien

from core import ntlib

La clé est que dans l'exemple que j'ai donné dans la question, le script "principal" était exécuté à partir du package. Une fois que je l'ai déplacé, j'ai créé un paquet spécifique (core) et déplacé la bibliothèque que je voulais que les éditeurs partagent (ntlib) dans ce paquet, tout était simplifié.

28
random

bien que tant que "choses" ne soit pas dans votre PATH python, vous n'avez pas d'autre choix que d'ajouter le chemin.

Si vous connaissez le niveau de votre script.py à partir de choses que vous pouvez faire par exemple:

import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
11
Torsten Engelbrecht

J'exécute Python 3.4.2 sur Windows 7 et me suis déchiré les cheveux.

Lors de l'exécution de l'un de ces:

python -m unittest python -m unittest découvrir

... j'obtiendrais l'erreur «Tentative d'importation relative au-delà du paquet de niveau supérieur».

Pour moi, la solution laissait tomber le ".." dans mon [test_stock.py] . La ligne était la suivante: de stock ..stock import

Changé pour: de stock import Stock

.. et il fonctionne.

Structure du dossier:

C:\
  |
  +-- stock_alerter
             |
             +-- __init__.py
             +-- stock.py
             |
             \-- tests
                   |
                   +-- __init__.py
                   \-- test_stock.py
7
Allen May

D'après PEP , il apparaît que vous ne pouvez pas utiliser une importation relative pour importer un fichier qui n'est pas empaqueté.

Donc, vous auriez besoin d'ajouter un __init__.py pour charger et modifier vos importations en quelque chose comme from .mylib import *

Cependant, le PEP ne semble pas tenir compte de la conservation de mylib dans un module. Vous devrez donc peut-être changer la façon dont vous appelez les fonctions de votre bibliothèque.

Une autre alternative consiste à déplacer mylib dans un sous-package et à l'importer en tant que from .libpackage import mylib

1
Dunes

import ..foo..stuff.mylib devrait être ok

EDIT a décollé l'extension

1
tekknolagi

Si vous êtes sous Linux ou si vous utilisez un * nix similaire, vous pouvez le pirater avec des liens symboliques.

stuff/
    mylib.py
    foo.py // equivalent of main.py in above
    foo/
        script.py
        mylib.py  ->  ../mylib.py
    foo2/
        script2.py
        mylib.py  ->  ../mylib.py

Ce n'est probablement pas un bon modèle à suivre.

Dans mon cas, j'ai opté pour cette solution car plusieurs exécutables dépendaient de la même bibliothèque et devaient être placés dans des répertoires distincts.

L'implémentation de nouveaux tests exécutables ne doit pas obliger l'écrivain de tests à bien comprendre les importations Python.

tests/
    common/
        commonlib.py
    test1/
        executable1.py
        executable2.py
        commonlib.py -> ../common/commonlib.py
    test2/
        executable1.py
        executable2.py
        commonlib.py -> ../common/commonlib.py


0