पायथन - रूट प्रोजेक्ट संरचना का पथ प्राप्त करें


127

मुझे प्रोजेक्ट रूट में कॉन्फ़िगरेशन फ़ाइल के साथ अजगर परियोजना मिली है। कॉन्फ़िगरेशन फ़ाइल को प्रोजेक्ट में कुछ अलग फ़ाइलों में एक्सेस करने की आवश्यकता होती है।

तो यह तरह दिखता है: <ROOT>/configuration.conf <ROOT>/A/a.py,<ROOT>/A/B/b.py (जब ख, a.py पहुँच विन्यास फाइल)।

प्रोजेक्ट रूट और कॉन्फ़िगरेशन फ़ाइल का पथ प्राप्त करने का सबसे अच्छा / आसान तरीका क्या है, इस पर निर्भर किए बिना कि मैं किस प्रोजेक्ट के अंदर फ़ाइल पर निर्भर हूं? बिना उपयोग के ../../? यह मान लेना ठीक है कि हम प्रोजेक्ट रूट का नाम जानते हैं।


करता <ROOT>/__init__.pyमौजूद हैं?
mgilson

या तो आपकी कॉन्फ़िगरेशन फ़ाइल एक अजगर मॉड्यूल है, और आप आसानी से इसे सिर्फ एक आयात विवरण के साथ एक्सेस कर सकते हैं, या तो यह एक अजगर मॉड्यूल नहीं है और आपको इसे एक प्रसिद्ध स्थान पर रखना चाहिए। उदाहरण के लिए $ HOME / .my_project / my_project.conf।
जॉन स्मिथ वैकल्पिक

@ जोहानस्मिथऑशनल - यह एक JSON फाइल है। मुझे पथ का उपयोग करके इसे एक्सेस करने में सक्षम होना चाहिए। हाँ। सभी फ़ोल्डरों में यह शामिल है।
शॉकी

_ यह मान लेना ठीक है कि हमें प्रोजेक्ट रूट का नाम पता है। क्या इसका मतलब है कि आप प्रोजेक्ट का रास्ता जानते हैं? क्या यह केवल os.path.join (ज्ञात_रोत_नाम, "कॉन्फ़िगरेशन.कॉन्फ़") नहीं है?
tdelaney

यदि यह एक उपयोगकर्ता कॉन्फ़िगरेशन है, तो मैं आमतौर पर कुछ का उपयोग करता हूं os.path.expanduser('~/.myproject/myproject.conf')। यह यूनिक्स और विंडोज पर काम करता है।
जॉन स्मिथ वैकल्पिक

जवाबों:


157

आप यह कर सकते हैं कि Django यह कैसे करता है: प्रोजेक्ट रूट के शीर्ष-स्तर में मौजूद फ़ाइल से प्रोजेक्ट रूट के लिए एक चर को परिभाषित करें। उदाहरण के लिए, यदि यह आपकी परियोजना संरचना जैसा दिखता है:

project/
    configuration.conf
    definitions.py
    main.py
    utils.py

में definitions.pyआप को परिभाषित कर सकते हैं (इस की आवश्यकता है import os):

ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) # This is your Project Root

इस प्रकार, ज्ञात प्रोजेक्ट रूट के साथ , आप एक चर बना सकते हैं जो कॉन्फ़िगरेशन के स्थान को इंगित करता है (इसे कहीं भी परिभाषित किया जा सकता है, लेकिन एक तार्किक स्थान इसे उस स्थान पर रखा जाएगा जहां स्थिरांक परिभाषित किए गए हैं - जैसे definitions.py):

CONFIG_PATH = os.path.join(ROOT_DIR, 'configuration.conf')  # requires `import os`

उसके बाद, आप आसानी से इंपोर्ट स्टेटमेंट (जैसे में साथ लगातार (अन्य फ़ाइलों में से किसी में) का उपयोग कर सकते utils.py): from definitions import CONFIG_PATH


1
परिभाषाएँ फ़ाइल को इस तरह शामिल करने के लिए, क्या __init__.pyरूट प्रोजेक्ट निर्देशिका में भी फ़ाइल जोड़ना आवश्यक होगा ? क्या यह सही होना चाहिए? मैंने अभी-अभी अजगर से शुरुआत की है और सर्वोत्तम प्रथाओं पर यकीन नहीं है। धन्यवाद।
अक्सकप ३०'१६ को ks:

3
@akskap: नहीं, एक __init__.pyकी आवश्यकता नहीं होगी, क्योंकि पैकेज को परिभाषित करते समय केवल उस फाइल की आवश्यकता होती है: पायथन को निर्देशिका युक्त पैकेज के रूप में मानने के लिए __init__.pyफाइलों की आवश्यकता होती है; यह सामान्य नाम से निर्देशिकाओं को रोकने के लिए किया जाता है, जैसे कि स्ट्रिंग, अनजाने में वैध मॉड्यूल छिपाते हैं जो बाद में मॉड्यूल खोज पथ पर होते हैं। सबसे सरल मामले में, __init__.pyबस एक खाली फ़ाइल हो सकती है, लेकिन यह पैकेज के लिए इनिशियलाइज़ेशन कोड को निष्पादित कर सकता है या __all__चर सेट कर सकता है, जिसे बाद में वर्णित किया गया है। देखें: docs.python.org/3/tutorial/modules.html#packages
jrd1

मैं जिज्ञासु हूं, शैली समझदार, चाहे वह इन परिभाषाओं को __init.py__मूल पैकेज में जोड़ने के लिए स्वीकार्य हो या फिर पराजित हो । यह एक और फ़ाइल बनाने से बचाएगा, साथ ही इसके अच्छे सिंटैक्स की भी अनुमति देगा from root_pack import ROOT_DIR, CONFIG_PATH
जॉन्ड्ट

@ जॉन्ड्ट 6: सम्मेलन को __init__.pyखाली रखना है, लेकिन यह कड़ाई से सच नहीं है (यह सभी के बाद एक सम्मेलन है)। इसे और देखें: stackoverflow.com/questions/2361124/use-init-py
jrd1

1
@JavNoor: कोई - उदाहरण आप उद्धृत में, os.path.abspathएक स्ट्रिंग, बुला रहा है '__file__'। याद है कि __file__वास्तव में एक आयात विशेषता है जिसे पायथन मॉड्यूल के लिए परिभाषित किया गया है। इस स्थिति में, __file__वह पथनाम वापस कर देगा जिसमें से मॉड्यूल लोड किया गया है। यहां और पढ़ें (मॉड्यूल अनुभाग देखें): docs.python.org/3/reference/datamodel.html
jrd1

61

अन्य उत्तर परियोजना के शीर्ष-स्तर में एक फ़ाइल का उपयोग करने की सलाह देते हैं। यदि आप उपयोग करते हैं pathlib.Pathऔर parent(पायथन 3.4 और ऊपर) यह आवश्यक नहीं है । निम्नलिखित निर्देशिका संरचना जहां को छोड़कर सभी फाइलों पर विचार करें README.mdऔर utils.pyछोड़ दिए गए हैं।

project
   README.md
|
└───src
      utils.py
|   |   ...
|   ...

में utils.pyहम निम्नलिखित समारोह परिभाषित करते हैं।

from pathlib import Path

def get_project_root() -> Path:
    return Path(__file__).parent.parent

परियोजना में किसी भी मॉड्यूल में अब हम परियोजना रूट को निम्नानुसार प्राप्त कर सकते हैं।

from src.utils import get_project_root

root = get_project_root()

लाभ : कोई भी मॉड्यूल जो कॉल get_project_rootको प्रोग्राम के व्यवहार को बदले बिना ले जाया जा सकता है। केवल जब मॉड्यूल utils.pyको स्थानांतरित किया जाता है तो हमें अपडेट करना होता है get_project_rootऔर आयात (रिफैक्टरिंग टूल का उपयोग इसे स्वचालित करने के लिए किया जा सकता है)।


2
जड़ में कोई भी मॉड्यूल। रूट के बाहर से src.utils को कॉल करने से काम नहीं होना चाहिए। क्या मै गलत हु?
एरिजमैन

नाम ' फ़ाइल ' परिभाषित नहीं है, क्यों?
लुक एरन

26

पिछले सभी समाधान मुझे क्या चाहिए, और अक्सर मेरे लिए काम नहीं करते हैं के लिए अत्यधिक जटिल प्रतीत होते हैं। निम्नलिखित एक-लाइन कमांड आपको क्या चाहिए:

import os
ROOT_DIR = os.path.abspath(os.curdir)

3
निर्देशिका के मूल में config.py में रखो, .. bamn! यूट खुद को एक सिंगलटन मिला।
स्वदेव

2
यह विधि मानती है कि आप एप्लिकेशन को उस पथ के भीतर से चलाते हैं जो मौजूद है। कई "उपयोगकर्ताओं" के पास एक आइकन है जो वे डेस्कटॉप से ​​क्लिक करते हैं या पूरी तरह से किसी अन्य निर्देशिका से ऐप चला सकते हैं।
DevPlayer

23

"रूट" मॉड्यूल का पथ प्राप्त करने के लिए, आप इसका उपयोग कर सकते हैं:

import os
import sys
os.path.dirname(sys.modules['__main__'].__file__)

लेकिन अधिक दिलचस्प बात यह है कि यदि आपके पास आपके टॉप-मोस्ट मॉड्यूल में एक "ऑब्जेक्ट" कॉन्फिग है, तो आप उसे इस तरह से फैला सकते हैं- जैसे:

app = sys.modules['__main__']
stuff = app.config.somefunc()

1
यहां osडिफ़ॉल्ट रूप से उपलब्ध नहीं है। आयात करने की आवश्यकता है os। तो लाइन जोड़ने से import osउत्तर अधिक पूर्ण हो जाएगा।
एमडी अबू नफी इब्ना जाहिद

5
यह वह निर्देशिका देता है जिसमें वह स्क्रिप्ट होती है जिसे निष्पादित किया गया था। उदाहरण के लिए, जब python3 -m topmodule.submodule.scriptइसे चलाने के /path/to/topmodule/submoduleबजाय दे देंगे /path/to/topmodule
दानीजार

14

इसे प्राप्त करने का एक मानक तरीका pkg_resourcesमॉड्यूल का उपयोग करना होगा जो इसका हिस्सा हैsetuptools पैकेज । setuptoolsएक स्थापित-सक्षम अजगर पैकेज बनाने के लिए उपयोग किया जाता है।

आप pkg_resourcesअपनी इच्छित फ़ाइल की सामग्री को एक स्ट्रिंग के रूप में वापस करने के लिए उपयोग कर सकते हैं और आप उपयोग कर सकते हैंpkg_resources करने के लिए और अपने सिस्टम पर वांछित फ़ाइल का वास्तविक पथ प्राप्त करने के लिए ।

मान लीजिए कि आपके पास एक पैकेज है जिसे कहा जाता है stackoverflow

stackoverflow/
|-- app
|   `-- __init__.py
`-- resources
    |-- bands
    |   |-- Dream\ Theater
    |   |-- __init__.py
    |   |-- King's\ X
    |   |-- Megadeth
    |   `-- Rush
    `-- __init__.py

3 directories, 7 files

अब मान लेते हैं कि आप किसी मॉड्यूल से फ़ाइल रश को एक्सेस करना चाहते हैं app.runpkg_resources.resouces_filenameरश की राह पाने के लिए और रश pkg_resources.resource_stringकी सामग्री प्राप्त करने के लिए उपयोग करें ; thusly:

import pkg_resources

if __name__ == "__main__":
    print pkg_resources.resource_filename('resources.bands', 'Rush')
    print pkg_resources.resource_string('resources.bands', 'Rush')

उत्पादन:

/home/sri/workspace/stackoverflow/resources/bands/Rush
Base: Geddy Lee
Vocals: Geddy Lee
Guitar: Alex Lifeson
Drums: Neil Peart

यह आपके अजगर पथ के सभी पैकेजों के लिए काम करता है। इसलिए यदि आप जानना चाहते हैं कि lxml.etreeआपके सिस्टम में कहां मौजूद है:

import pkg_resources

if __name__ == "__main__":
    print pkg_resources.resource_filename('lxml', 'etree')

उत्पादन:

/usr/lib64/python2.7/site-packages/lxml/etree

मुद्दा यह है कि आप इस मानक विधि का उपयोग उन फाइलों तक पहुंचने के लिए कर सकते हैं जो आपके सिस्टम पर स्थापित हैं (जैसे कि पाइप स्थापित xxx या yum -y स्थापित python-xxx) और फ़ाइलें जो उस मॉड्यूल के भीतर हैं जो आप वर्तमान में काम कर रहे हैं।


1
मुझे तुम्हारी बैंड पसंद है!
dylan_fan

3

प्रयत्न:

ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

1
मुझे ठीक इसी की आवश्यकता थी। सरल समाधान, मेरे लिए काम करता है क्योंकि मेरी संरचना रूट थी-> config-> conf.py मैं प्रोजेक्ट रूट को conf.py में परिभाषित करना चाहता था और रूट उस फ़ाइल से ठीक दो स्तर ऊपर था।
दनियाल अरशद

3

नीचे कोड आपकी परियोजना के रूट तक पथ लौटाता है

import sys
print(sys.path[1])

अच्छी टिप! मुझे आश्चर्य है कि किसी ने आपके उत्तर को क्यों नहीं
हटाया

धन्यवाद डेवन वास्तव में सराहना करते हैं कि !!
अर्पण सैनी

दुर्भाग्य से यह सरल नहीं है: P ... मेरे पूर्ण समाधान पर एक नज़र डालें: stackoverflow.com/a/62510836/267719
daveoncode

2

मैं इस समस्या से तब तक जूझता रहा जब तक मैं इस समाधान के लिए नहीं आया। यह मेरी राय में सबसे साफ समाधान है।

अपने setup.py में "संकुल" जोड़ें

setup(
name='package_name'
version='0.0.1'
.
.
.
packages=['package_name']
.
.
.
)

आपके python_script.py में

import pkg_resources
import os

resource_package = pkg_resources.get_distribution(
    'package_name').location
config_path = os.path.join(resource_package,'configuration.conf')

एक आभासी वातावरण का उपयोग करना और python3 setup.py installइसके साथ पैकेज स्थापित करना स्रोत कोड फ़ोल्डर को इंगित नहीं कर रहा था, लेकिन अंदर अंडे को ~./virtualenv/..../app.egg। इसलिए मुझे पैकेज की स्थापना में कॉन्फ़िगरेशन फ़ाइल को शामिल करना पड़ा।
loxosceles

2

सिर्फ एक उदाहरण: मैं चलाना चाहते हैं runio.py के भीतर से helper1.py

प्रोजेक्ट ट्री उदाहरण:

myproject_root
- modules_dir/helpers_dir/helper1.py
- tools_dir/runio.py

प्रोजेक्ट रूट प्राप्त करें:

import os
rootdir = os.path.dirname(os.path.realpath(__file__)).rsplit(os.sep, 2)[0]

स्क्रिप्ट के लिए पथ बनाएँ:

runme = os.path.join(rootdir, "tools_dir", "runio.py")
execfile(runme)

1

यह मेरे लिए परियोजना रूट डायरेक्टरी के तहत अपने आभासी वातावरण (वेनव) के साथ एक मानक PyCharm परियोजना का उपयोग करने के लिए काम किया।

नीचे दिया गया कोड सबसे सुंदर है, लेकिन लगातार परियोजना को प्राप्त करता है। यह VIRTUAL_ENVपर्यावरण चर से उदाहरण के लिए पूरी निर्देशिका पथ देता है उदा/Users/NAME/documents/PROJECT/venv

यह फिर /दो तत्वों के साथ एक सरणी देते हुए, आखिरी में पथ को विभाजित करता है । पहला तत्व प्रोजेक्ट पथ उदा होगा/Users/NAME/documents/PROJECT

import os

print(os.path.split(os.environ['VIRTUAL_ENV'])[0])

3
यह एनाकोंडा या पिपेनव जैसे सेटअप के साथ काम नहीं करेगा, क्योंकि वर्चुअल वातावरण उन मामलों में परियोजना के भीतर समाहित नहीं है।
Gripp

1

मैं हाल ही में कुछ ऐसा ही करने की कोशिश कर रहा हूं और मुझे ये जवाब मेरे उपयोग के मामलों (एक वितरित पुस्तकालय जिसे मूल रूट का पता लगाने की आवश्यकता है) के लिए अपर्याप्त पाया गया है। मुख्य रूप से मैं विभिन्न वातावरणों और प्लेटफार्मों से जूझ रहा हूं, और अभी भी कुछ पूरी तरह से सार्वभौमिक नहीं मिला है।

परियोजना के लिए स्थानीय कोड

मैंने इस उदाहरण का उल्लेख किया है और कुछ स्थानों, Django, आदि में उपयोग किया है।

import os
print(os.path.dirname(os.path.abspath(__file__)))

यह सरल है, यह केवल तभी काम करता है जब स्निपेट जिस फ़ाइल में है वह वास्तव में परियोजना का हिस्सा है। हम परियोजना निर्देशिका को पुनः प्राप्त नहीं करते हैं, बल्कि स्निपेट की निर्देशिका को छोड़ देते हैं

इसी तरह, sys.modules जब नीचे टूटता दृष्टिकोण बुलाया आवेदन की entrypoint बाहर से, विशेष रूप से मैं एक बच्चा धागे 'के संबंध वापस बिना इस निर्धारित नहीं कर सकता' पाया है मुख्य 'मॉड्यूल। मैंने स्पष्ट रूप से एक आयात को एक बच्चे के धागे से आयात प्रदर्शित करने के लिए एक फ़ंक्शन के अंदर रखा है, इसे शीर्ष स्तर पर ले जाकर app.py इसे ठीक कर देगा।

app/
|-- config
|   `-- __init__.py
|   `-- settings.py
`-- app.py

app.py

#!/usr/bin/env python
import threading


def background_setup():
    # Explicitly importing this from the context of the child thread
    from config import settings
    print(settings.ROOT_DIR)


# Spawn a thread to background preparation tasks
t = threading.Thread(target=background_setup)
t.start()

# Do other things during initialization

t.join()

# Ready to take traffic

settings.py

import os
import sys


ROOT_DIR = None


def setup():
    global ROOT_DIR
    ROOT_DIR = os.path.dirname(sys.modules['__main__'].__file__)
    # Do something slow

इस कार्यक्रम को चलाने से विशेषता त्रुटि उत्पन्न होती है:

>>> import main
>>> Exception in thread Thread-1:
Traceback (most recent call last):
  File "C:\Python2714\lib\threading.py", line 801, in __bootstrap_inner
    self.run()
  File "C:\Python2714\lib\threading.py", line 754, in run
    self.__target(*self.__args, **self.__kwargs)
  File "main.py", line 6, in background_setup
    from config import settings
  File "config\settings.py", line 34, in <module>
    ROOT_DIR = get_root()
  File "config\settings.py", line 31, in get_root
    return os.path.dirname(sys.modules['__main__'].__file__)
AttributeError: 'module' object has no attribute '__file__'

... इसलिए थ्रेडिंग आधारित समाधान

स्थान स्वतंत्र

पहले की तरह ही एप्लिकेशन संरचना का उपयोग करना लेकिन सेटिंग्स को संशोधित करना

import os
import sys
import inspect
import platform
import threading


ROOT_DIR = None


def setup():
    main_id = None
    for t in threading.enumerate():
        if t.name == 'MainThread':
            main_id = t.ident
            break

    if not main_id:
        raise RuntimeError("Main thread exited before execution")

    current_main_frame = sys._current_frames()[main_id]
    base_frame = inspect.getouterframes(current_main_frame)[-1]

    if platform.system() == 'Windows':
        filename = base_frame.filename
    else:
        filename = base_frame[0].f_code.co_filename

    global ROOT_DIR
    ROOT_DIR = os.path.dirname(os.path.abspath(filename))

इसे तोड़ना: पहले हम मुख्य धागे की थ्रेड आईडी को सही ढंग से ढूंढना चाहते हैं। Python3.4 + में थ्रेडिंग लाइब्रेरी में threading.main_thread()हालांकि, हर कोई 3.4+ का उपयोग नहीं करता है, इसलिए हम सभी थ्रेड्स के माध्यम से खोज करते हैं जो मुख्य थ्रेड को ढूंढते हैं , यह आईडी है। यदि मुख्य धागा पहले ही निकल चुका है, तो इसे सूचीबद्ध नहीं किया जाएगा threading.enumerate()। हम RuntimeError()इस मामले में तब तक बढ़ाते हैं जब तक कि मुझे बेहतर समाधान नहीं मिल जाता।

main_id = None
for t in threading.enumerate():
    if t.name == 'MainThread':
        main_id = t.ident
        break

if not main_id:
    raise RuntimeError("Main thread exited before execution")

अगला हम मुख्य धागे का पहला स्टैक फ्रेम पाते हैं। CPython विशिष्ट फ़ंक्शन का उपयोग करके sys._current_frames() हमें हर थ्रेड के वर्तमान स्टैक फ्रेम का एक शब्दकोश मिलता है। तब inspect.getouterframes()हम मुख्य धागे और बहुत पहले फ्रेम के लिए पूरे स्टैक को पुनः प्राप्त कर सकते हैं। current_main_frame = sys._current_frames () [main_id] base_frame = inspect.getouterframes (current_main_frame) [- 1] अंत में, विंडोज और लिनक्स कार्यान्वयन के बीच के अंतर inspect.getouterframes()को संभालने की आवश्यकता है। साफ किए गए फ़ाइल नाम का उपयोग करना os.path.abspath()और os.path.dirname()चीजों को साफ करना।

if platform.system() == 'Windows':
    filename = base_frame.filename
else:
    filename = base_frame[0].f_code.co_filename

global ROOT_DIR
ROOT_DIR = os.path.dirname(os.path.abspath(filename))

अब तक मैंने इसे Python2.7 और 3.6 पर विंडोज के साथ-साथ WSL पर Python3.4 पर टेस्ट किया है


0

यदि आप एनाकोंडा-प्रोजेक्ट के साथ काम कर रहे हैं, तो आप PROJECT_ROOT को पर्यावरण चर -> os.getenv ('PROJECT_ROOT') से क्वेरी कर सकते हैं। यह तभी काम करता है जब स्क्रिप्ट को एनाकोंडा-प्रोजेक्ट रन के माध्यम से निष्पादित किया जाता है।

यदि आप अपनी स्क्रिप्ट को एनाकोंडा-प्रोजेक्ट द्वारा नहीं चलाना चाहते हैं, तो आप पायथन दुभाषिया के निष्पादन योग्य बाइनरी के निरपेक्ष पथ को क्वेरी कर सकते हैं जो आप उपयोग कर रहे हैं और एनवीएस डायरेक्टरी एक्सक्लूसिव तक पथ स्ट्रिंग को निकाल सकते हैं। उदाहरण के लिए: मेरे कोंडा एनवी का अजगर इंटरप्रेटर यहां स्थित है:

/ घर / उपयोगकर्ता / project_root / envs / डिफ़ॉल्ट / bin / अजगर

# You can first retrieve the env variable PROJECT_DIR.
# If not set, get the python interpreter location and strip off the string till envs inclusiv...

if os.getenv('PROJECT_DIR'):
    PROJECT_DIR = os.getenv('PROJECT_DIR')
else:
    PYTHON_PATH = sys.executable
    path_rem = os.path.join('envs', 'default', 'bin', 'python')
    PROJECT_DIR = py_path.split(path_rem)[0]

यह केवल एनाकोंडा-प्रोजेक्ट की निश्चित परियोजना संरचना के साथ कोंडा-प्रोजेक्ट के साथ काम करता है


0

मैंने वर्तमान परियोजना पथ लाने के लिए ../ विधि का उपयोग किया।

उदाहरण: Project1 - D: \ Projects

src

ConfigurationFiles

Configuration.cfg

पथ = "../ src / ConfigurationFiles / Configuration.cfg"


0

लेखन के समय, अन्य समाधानों में से कोई भी बहुत आत्म-निहित नहीं है। वे या तो एक पर्यावरण चर या पैकेज संरचना में मॉड्यूल की स्थिति पर निर्भर करते हैं। 'Django' समाधान के साथ शीर्ष उत्तर बाद में एक रिश्तेदार आयात की आवश्यकता से पीड़ित हो जाता है। इसमें शीर्ष स्तर पर एक मॉड्यूल को संशोधित करने का नुकसान भी है।

शीर्ष-स्तरीय पैकेज की निर्देशिका पथ खोजने के लिए यह सही तरीका होना चाहिए:

import sys
import os

root_name, _, _ = __name__.partition('.')
root_module = sys.modules[root_name]
root_dir = os.path.dirname(root_module.__file__)

config_path = os.path.join(root_dir, 'configuration.conf')

यह डॉटेड स्ट्रिंग में पहले घटक को शामिल __name__करके और इसे एक कुंजी के रूप में उपयोग करके काम करता है sys.modulesजिसमें शीर्ष-स्तरीय पैकेज के मॉड्यूल ऑब्जेक्ट को लौटाता है। इसकी __file__विशेषता में वह मार्ग शामिल है जिसे हम ट्रिमिंग के बाद /__init__.pyउपयोग करना चाहते हैं os.path.dirname()

यह समाधान स्वयं निहित है। यह पैकेज के किसी भी मॉड्यूल में कहीं भी काम करता है, जिसमें शीर्ष-स्तरीय __init__.pyफ़ाइल शामिल है।


क्या आप अपने समाधान के बारे में एक संक्षिप्त विवरण जोड़ सकते हैं और वे इसे अपने समाधान के रूप में कैसे उपयोग कर सकते हैं?
LuRsT

0

मुझे एक कस्टम समाधान लागू करना पड़ा क्योंकि यह उतना आसान नहीं है जितना आप सोच सकते हैं। मेरा समाधान स्टैक ट्रेस इंस्पेक्शन ( inspect.stack()) + पर आधारित है sys.pathऔर यह ठीक काम कर रहा है कि पायथन मॉड्यूल के स्थान में कोई फर्क नहीं पड़ता है जिसमें फ़ंक्शन को न तो इंटरप्रेटर किया जाता है (मैंने इसे PyCharm में चलाने की कोशिश की है, एक कविता शेल और अन्य में ... )। यह टिप्पणियों के साथ पूर्ण कार्यान्वयन है:

def get_project_root_dir() -> str:
    """
    Returns the name of the project root directory.

    :return: Project root directory name
    """

    # stack trace history related to the call of this function
    frame_stack: [FrameInfo] = inspect.stack()

    # get info about the module that has invoked this function
    # (index=0 is always this very module, index=1 is fine as long this function is not called by some other
    # function in this module)
    frame_info: FrameInfo = frame_stack[1]

    # if there are multiple calls in the stacktrace of this very module, we have to skip those and take the first
    # one which comes from another module
    if frame_info.filename == __file__:
        for frame in frame_stack:
            if frame.filename != __file__:
                frame_info = frame
                break

    # path of the module that has invoked this function
    caller_path: str = frame_info.filename

    # absolute path of the of the module that has invoked this function
    caller_absolute_path: str = os.path.abspath(caller_path)

    # get the top most directory path which contains the invoker module
    paths: [str] = [p for p in sys.path if p in caller_absolute_path]
    paths.sort(key=lambda p: len(p))
    caller_root_path: str = paths[0]

    if not os.path.isabs(caller_path):
        # file name of the invoker module (eg: "mymodule.py")
        caller_module_name: str = Path(caller_path).name

        # this piece represents a subpath in the project directory
        # (eg. if the root folder is "myproject" and this function has ben called from myproject/foo/bar/mymodule.py
        # this will be "foo/bar")
        project_related_folders: str = caller_path.replace(os.sep + caller_module_name, '')

        # fix root path by removing the undesired subpath
        caller_root_path = caller_root_path.replace(project_related_folders, '')

    dir_name: str = Path(caller_root_path).name

    return dir_name

-1

यहाँ कई उत्तर हैं, लेकिन मुझे कुछ सरल नहीं मिला है जो सभी मामलों को कवर करता है इसलिए मुझे अपना समाधान भी सुझाने की अनुमति देता है:

import pathlib
import os

def get_project_root():
    """
    There is no way in python to get project root. This function uses a trick.
    We know that the function that is currently running is in the project.
    We know that the root project path is in the list of PYTHONPATH
    look for any path in PYTHONPATH list that is contained in this function's path
    Lastly we filter and take the shortest path because we are looking for the root.
    :return: path to project root
    """
    apth = str(pathlib.Path().absolute())
    ppth = os.environ['PYTHONPATH'].split(':')
    matches = [x for x in ppth if x in apth]
    project_root = min(matches, key=len)
    return project_root

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.