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.
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
.