web-dev-qa-db-fra.com

Tentative d'importation relative au-delà du paquetage toplevel

Voici la structure de mon dossier:

Mopy/ # no init.py !
   bash/
     __init__.py
     bash.py # <--- Edit: yep there is such a module too
     bass.py
     bosh/
       __init__.py # contains from .. import bass
       bsa_files.py
     ...
   test_bash\
     __init__.py # code below
     test_bosh\
       __init__.py
       test_bsa_files.py

Dans test_bash\__init__.py J'ai:

import sys
from os.path import dirname, abspath, join, sep
mopy = dirname(dirname(abspath(__file__)))
assert mopy.split(sep)[-1].lower() == 'mopy'
sys.path.append(mopy)
print 'Mopy folder appended to path: ', mopy

en test_bsa_files.py:

import unittest
from unittest import TestCase

import bosh

class TestBSAHeader(TestCase):
    def test_read_header(self):
        bosh.bsa_files.Header.read_header()

if __name__ == '__main__':
    unittest.main()

Maintenant, quand je publie:

python.exe "C:\_\JetBrains\PyCharm 2016.2.2\helpers\pycharm\utrunner.py" C:\path\to\Mopy\test_bash\test_bosh\test_bsa_files.py true

Je reçois:

Traceback (most recent call last):
  File "C:\_\JetBrains\PyCharm 2016.2.2\helpers\pycharm\utrunner.py", line 124, in <module>
    modules = [loadSource(a[0])]
  File "C:\_\JetBrains\PyCharm 2016.2.2\helpers\pycharm\utrunner.py", line 43, in loadSource
    module = imp.load_source(moduleName, fileName)
  File "C:\Dropbox\Eclipse_workspaces\python\wrye-bash\Mopy\test_bash\test_bosh\test_bsa_files.py", line 4, in <module>
    import bosh
  File "C:\Dropbox\Eclipse_workspaces\python\wrye-bash\Mopy\bash\bosh\__init__.py", line 50, in <module>
    from .. import bass
ValueError: Attempted relative import beyond toplevel package

Depuis 'Mopy "est dans le sys.path et bosh\__init__.py est correctement résolu, pourquoi se plaint-il de l'importation relative au-dessus du package de niveau supérieur? Quel est le package de niveau supérieur ?

Incidemment, c’est ma tentative d’ajouter des tests à un projet hérité - l’avait demandé dans présentation du package de test Python mais elle était fermée comme une copie de Où est-ce que Python = les tests unitaires vont? . Les commentaires sur la disposition actuelle de mon ensemble de tests sont très appréciés!


Eh bien le réponse ci-dessous ne fonctionne pas dans mon cas:

Le module bash.py est le point d'entrée de l'application contenant:

if __name__ == '__main__':
    main()

Quand j'utilise import bash.bosh ou from bash import bosh Je reçois:

C:\_\Python27\python.exe "C:\_\JetBrains\PyCharm 2016.2.2\helpers\pycharm\utrunner.py" C:\Dropbox\Eclipse_workspaces\python\wrye-bash\Mopy\test_bash\test_bosh\test_bsa_files.py true
Testing started at 3:45 PM ...
usage: utrunner.py [-h] [-o OBLIVIONPATH] [-p PERSONALPATH] [-u USERPATH]
                   [-l LOCALAPPDATAPATH] [-b] [-r] [-f FILENAME] [-q] [-i]
                   [-I] [-g GAMENAME] [-d] [-C] [-P] [--no-uac] [--uac]
                   [--bashmon] [-L LANGUAGE]
utrunner.py: error: unrecognized arguments: C:\Dropbox\Eclipse_workspaces\python\wrye-bash\Mopy\test_bash\test_bosh\test_bsa_files.py true

Process finished with exit code 2

Ce message d'utilisation provient de la main () de bash.

21
Mr_and_Mrs_D

TLDR: faire

import bash.bosh

ou

from bash import bosh

Si vous avez également une construction comme bash.bash, vous devez vous assurer que votre paquet prime sur son contenu. Au lieu de l'ajouter, ajoutez-le au début de l'ordre de recherche:

# test_bash\__init__.py
sys.path.insert(0, mopy)

Quand tu fais

import bosh

il importera le module bosh. Ça signifie Mopy/bash est dans votre sys.path, python y trouve le fichier bosh et l’importe. Le module est maintenant connu dans le monde entier sous le nom bosh. Si bosh est lui-même un module ou un paquet n'a pas d'importance pour cela, cela change seulement si bosh.py ou bosh/__init__.py est utilisé.

Maintenant, quand bosh essaie de le faire

from .. import bass

il ne s’agit pas d’une opération de système de fichiers ("un répertoire en place, fichier grave"), mais d’une opération de nom de module. Cela signifie "un paquet de niveau, module de basse". bosh n'a pas été importé de son paquet, mais seul. Donc, monter d'un paquet n'est pas possible - vous vous retrouvez au paquet '', qui n'est pas valide.

Regardons ce qui se passe quand tu fais

import bash.bosh

au lieu. Tout d'abord, le package bash est importé. Ensuite, bosh est importé en tant que module de ce package - il est globalement connu sous le nom de bash.bosh, même si vous avez utilisé from bash import bosh.

Quand bosh fait

from .. import bass

ça marche maintenant: monter d'un niveau à partir de bash.bosh vous amène à bash. De là, bass est importé sous le nom bash.bass.

Voir aussi cette réponse associée pour exécuter un module à partir d'un package sans modifier sys.path.

26
MisterMiyagi