J'ai un projet python avec un fichier de configuration à la racine du projet. Le fichier de configuration doit être accessible dans quelques fichiers différents tout au long du projet.
Il semble donc quelque chose comme: <ROOT>/configuration.conf
<ROOT>/A/a.py
, <ROOT>/A/B/b.py
(quand b, accès a.py le fichier de configuration).
Quelle est la meilleure / la plus simple façon d'obtenir le chemin vers la racine du projet et le fichier de configuration sans dépendre du fichier dans le projet dans lequel je suis? c'est à dire sans utiliser ../../
? Il est normal de supposer que nous connaissons le nom de la racine du projet.
<ROOT>/__init__.py
n'existe?os.path.expanduser('~/.myproject/myproject.conf')
. Cela fonctionne sous Unix et Windows.Réponses:
Vous pouvez faire ceci comme Django le fait: définir une variable à la racine du projet à partir d'un fichier qui se trouve au niveau supérieur du projet. Par exemple, si voici à quoi ressemble la structure de votre projet:
Dans
definitions.py
vous pouvez définir (cela nécessiteimport os
):Ainsi, avec la racine du projet connue, vous pouvez créer une variable qui pointe vers l'emplacement de la configuration (cela peut être défini n'importe où, mais un endroit logique serait de le placer dans un emplacement où les constantes sont définies - par exemple
definitions.py
):, Vous pouvez facilement accéder ensuite la constante (dans l' un des autres fichiers) avec l'instruction d'importation (par exemple
utils.py
):from definitions import CONFIG_PATH
.la source
__init__.py
fichier au répertoire racine du projet? Cela devrait-il être correct? Je viens de commencer avec python et je ne suis pas sûr des meilleures pratiques. Merci.__init__.py
ne sera pas requis, car ce fichier n'est requis que lors de la définition des packages: Les__init__.py
fichiers sont nécessaires pour que Python traite les répertoires comme contenant des packages; ceci est fait pour empêcher les répertoires avec un nom commun, tel que string, de masquer involontairement les modules valides qui surviennent plus tard sur le chemin de recherche du module. Dans le cas le plus simple, il__init__.py
peut s'agir simplement d'un fichier vide, mais il peut également exécuter le code d'initialisation du package ou définir la__all__
variable, décrite plus loin. Voir: docs.python.org/3/tutorial/modules.html#packages__init.py__
paquet racine. Cela éviterait de créer un autre fichier et autoriserait la syntaxe plus agréable defrom root_pack import ROOT_DIR, CONFIG_PATH
.__init__.py
vide, mais ce n'est pas strictement vrai (c'est une convention après tout). Voir ceci pour plus: stackoverflow.com/questions/2361124/using-init-pyos.path.abspath
appelle une chaîne,'__file__'
. Rappelez-vous qu'il__file__
s'agit en fait d'un attribut d'importation défini pour les modules Python. Dans ce cas,__file__
retournera le chemin à partir duquel le module est chargé. En savoir plus ici (voir la section des modules): docs.python.org/3/reference/datamodel.htmlD'autres réponses conseillent d'utiliser un fichier au plus haut niveau du projet. Cela n'est pas nécessaire si vous utilisez
pathlib.Path
etparent
(Python 3.4 et plus). Considérez la structure de répertoires suivante où tous les fichiers saufREADME.md
etutils.py
ont été omis.Dans
utils.py
nous définissons la fonction suivante.Dans n'importe quel module du projet, nous pouvons maintenant obtenir la racine du projet comme suit.
Avantages : Tout module qui appelle
get_project_root
peut être déplacé sans changer le comportement du programme. Ce n'est que lorsque le moduleutils.py
est déplacé que nous devons mettre à jourget_project_root
et importer (des outils de refactoring peuvent être utilisés pour automatiser cela).la source
Toutes les solutions précédentes semblent être trop compliquées pour ce dont je pense que vous avez besoin, et souvent ne fonctionnaient pas pour moi. La commande en une ligne suivante fait ce que vous voulez:
la source
Pour obtenir le chemin du module "root", vous pouvez utiliser:
Mais plus intéressant encore, si vous avez un "objet" de configuration dans votre module le plus haut, vous pouvez le lire comme ceci:
la source
os
n'est pas disponible par défaut. Besoin d'importeros
. Donc, ajouter la ligneimport os
rendrait la réponse plus complète.python3 -m topmodule.submodule.script
il donnera/path/to/topmodule/submodule
au lieu de/path/to/topmodule
.Une manière standard d'y parvenir serait d'utiliser le
pkg_resources
module qui fait partie dusetuptools
package.setuptools
est utilisé pour créer un package python installable.Vous pouvez utiliser
pkg_resources
pour renvoyer le contenu de votre fichier souhaité sous forme de chaîne et vous pouvez utiliserpkg_resources
pour obtenir le chemin réel du fichier souhaité sur votre système.Disons que vous avez un package appelé
stackoverflow
.Supposons maintenant que vous souhaitiez accéder au fichier Rush à partir d'un module
app.run
. Utilisezpkg_resources.resouces_filename
pour obtenir le chemin vers Rush etpkg_resources.resource_string
pour obtenir le contenu de Rush; ainsi:Le résultat:
Cela fonctionne pour tous les packages de votre chemin python. Donc, si vous voulez savoir où
lxml.etree
existe sur votre système:production:
Le fait est que vous pouvez utiliser cette méthode standard pour accéder aux fichiers qui sont installés sur votre système (par exemple, pip install xxx ou yum -y install python-xxx) et aux fichiers qui se trouvent dans le module sur lequel vous travaillez actuellement.
la source
Essayer:
la source
Sous le code Renvoie le chemin jusqu'à la racine de votre projet
la source
J'ai également lutté avec ce problème jusqu'à ce que j'arrive à cette solution. C'est la solution la plus propre à mon avis.
Dans votre setup.py ajoutez "packages"
Dans votre python_script.py
la source
python3 setup.py install
celui-ci ne pointait plus vers le dossier du code source, mais vers l'œuf à l'intérieur~./virtualenv/..../app.egg
. J'ai donc dû inclure le fichier de configuration dans l'installation du package.Juste un exemple: je veux exécuter runio.py depuis helper1.py
Exemple d'arborescence de projet:
Obtenez la racine du projet:
Construire le chemin vers le script:
la source
Cela a fonctionné pour moi en utilisant un projet PyCharm standard avec mon environnement virtuel (venv) sous le répertoire racine du projet.
Le code ci-dessous n'est pas le plus joli, mais obtient systématiquement la racine du projet. Il renvoie le chemin complet du répertoire vers venv à partir de la
VIRTUAL_ENV
variable d'environnement par exemple/Users/NAME/documents/PROJECT/venv
Il divise ensuite le chemin en dernier
/
, donnant un tableau avec deux éléments. Le premier élément sera le chemin du projet, par exemple/Users/NAME/documents/PROJECT
la source
J'ai récemment essayé de faire quelque chose de similaire et j'ai trouvé ces réponses inadéquates pour mes cas d'utilisation (une bibliothèque distribuée qui doit détecter la racine du projet). J'ai principalement combattu différents environnements et plates-formes, et je n'ai toujours pas trouvé quelque chose de parfaitement universel.
Code local au projet
J'ai vu cet exemple mentionné et utilisé dans quelques endroits, Django, etc.
Aussi simple que cela soit, cela ne fonctionne que lorsque le fichier dans lequel se trouve l'extrait de code fait réellement partie du projet. Nous ne récupérons pas le répertoire du projet, mais plutôt le répertoire de l'extrait de code
De même, l' approche sys.modules tombe en panne lorsqu'elle est appelée depuis l'extérieur du point d'entrée de l'application, en particulier, j'ai observé qu'un thread enfant ne peut pas le déterminer sans rapport avec le module « principal ». J'ai explicitement mis l'importation dans une fonction pour démontrer une importation à partir d'un thread enfant, le déplacer vers le niveau supérieur de app.py le corrigerait.
app.py
settings.py
L'exécution de ce programme produit une erreur d'attribut:
... d'où une solution basée sur le threading
Indépendant de l'emplacement
Utilisation de la même structure d'application qu'avant mais modification de settings.py
Décomposer ceci: Nous voulons d'abord trouver avec précision l'ID de thread du thread principal. Dans Python3.4 +, la bibliothèque de threads a
threading.main_thread()
cependant, tout le monde n'utilise pas 3.4+ donc nous recherchons dans tous les threads à la recherche du thread principal, sauf son ID. Si le thread principal est déjà terminé, il ne sera pas répertorié dans lethreading.enumerate()
. Nous soulevons unRuntimeError()
dans ce cas jusqu'à ce que je trouve une meilleure solution.Ensuite, nous trouvons le tout premier cadre de pile du thread principal. En utilisant la fonction spécifique cPython,
sys._current_frames()
nous obtenons un dictionnaire de la trame de pile actuelle de chaque thread. Ensuite, en utilisant,inspect.getouterframes()
nous pouvons récupérer la pile entière pour le thread principal et la toute première image. current_main_frame = sys._current_frames () [main_id] base_frame = inspect.getouterframes (current_main_frame) [- 1] Enfin, les différences entre les implémentations Windows et Linuxinspect.getouterframes()
doivent être gérées. Utilisez le nom de fichier nettoyéos.path.abspath()
etos.path.dirname()
nettoyez les choses.Jusqu'à présent, j'ai testé cela sur Python2.7 et 3.6 sur Windows ainsi que sur Python3.4 sur WSL
la source
Si vous travaillez avec anaconda-project, vous pouvez interroger le PROJECT_ROOT à partir de la variable d'environnement -> os.getenv ('PROJECT_ROOT'). Cela ne fonctionne que si le script est exécuté via l'exécution d'un projet anaconda.
Si vous ne voulez pas que votre script soit exécuté par anaconda-project, vous pouvez interroger le chemin absolu du binaire exécutable de l'interpréteur Python que vous utilisez et extraire la chaîne de chemin jusqu'au répertoire envs exclusiv. Par exemple: L'interpréteur python de mon conda env est situé à:
Cela ne fonctionne qu'avec conda-project avec une structure de projet fixe d'un anaconda-project
la source
J'ai utilisé la méthode ../ pour récupérer le chemin actuel du projet.
Exemple: Project1 - D: \ projects
src
Fichiers de configuration
Configuration.cfg
Chemin = "../ src / ConfigurationFiles / Configuration.cfg"
la source
Au moment de la rédaction de cet article, aucune des autres solutions n'est vraiment autonome. Ils dépendent soit d'une variable d'environnement, soit de la position du module dans la structure du package. La première réponse avec la solution 'Django' est victime de cette dernière en exigeant une importation relative. Il présente également l'inconvénient de devoir modifier un module au niveau supérieur.
Cela devrait être la bonne approche pour trouver le chemin du répertoire du package de niveau supérieur:
Il fonctionne en prenant le premier composant de la chaîne en pointillé contenue dans
__name__
et en l'utilisant comme clé danssys.modules
laquelle renvoie l'objet module du package de niveau supérieur. Son__file__
attribut contient le chemin que nous voulons après le découpage en/__init__.py
utilisantos.path.dirname()
.Cette solution est autonome. Il fonctionne n'importe où dans n'importe quel module du package, y compris dans le
__init__.py
fichier de niveau supérieur .la source
J'ai dû implémenter une solution personnalisée car ce n'est pas aussi simple que vous pourriez le penser. Ma solution est basée sur l'inspection de trace de pile (
inspect.stack()
) +sys.path
et fonctionne très bien quel que soit l'emplacement du module python dans lequel la fonction est invoquée ni l'interpréteur (j'ai essayé en l'exécutant dans PyCharm, dans un shell de poésie et autres ... ). Ceci est la mise en œuvre complète avec des commentaires:la source
Il y a beaucoup de réponses ici mais je n'ai pas trouvé quelque chose de simple qui couvre tous les cas alors permettez-moi de suggérer ma solution aussi:
la source