पायथन पैकेज के अंदर से (स्टेटिक) फाइल कैसे पढ़ें?


106

क्या आप मुझे बता सकते हैं कि मैं अपने पायथन पैकेज के अंदर एक फ़ाइल कैसे पढ़ सकता हूं?

मेरी स्थिति

मेरे द्वारा लोड किए जाने वाले पैकेज में कई टेम्प्लेट होते हैं (स्ट्रिंग्स के रूप में उपयोग की जाने वाली टेक्स्ट फाइलें) जिन्हें मैं प्रोग्राम के भीतर से लोड करना चाहता हूं। लेकिन मैं ऐसी फ़ाइल का पथ कैसे निर्दिष्ट करूं?

कल्पना कीजिए कि मैं एक फ़ाइल पढ़ना चाहता हूं:

package\templates\temp_file

किसी तरह की राह में हेराफेरी? पैकेज आधार पथ ट्रैकिंग?



जवाबों:


-12

[२०१६-०६-१५ जोड़ा गया: जाहिरा तौर पर यह सभी स्थितियों में काम नहीं करता है। कृपया अन्य उत्तरों को देखें]


import os, mypackage
template = os.path.join(mypackage.__path__[0], 'templates', 'temp_file')

175

TLDR; मानक-लाइब्रेरी के importlib.resourcesमॉड्यूल का उपयोग करें, जैसा कि नीचे विधि 2 में नहीं दिया गया है।

पारंपरिक pkg_resourcesसेsetuptools अब और अनुशंसित नहीं है क्योंकि नई विधि:

  • यह काफी अधिक प्रदर्शन करने वाला है ;
  • संकुल के उपयोग के बाद से सुरक्षित है (पथ-डंक के बजाय) संकलन-समय त्रुटियों को उठाता है;
  • यह अधिक सहज है क्योंकि आपको "पथ" में शामिल होने की आवश्यकता नहीं है;
  • जब आप एक अतिरिक्त निर्भरता ( setuptools) की आवश्यकता नहीं है, तो यह तेजी से विकसित हो रहा है , लेकिन केवल पायथन के मानक-पुस्तकालय पर भरोसा करते हैं।

मैंने मौजूदा कोड को पोर्ट करते समय नई पद्धति के साथ अंतर को समझाने के लिए पहले पारंपरिक सूचीबद्ध रखा (पोर्टिंग को भी यहां समझाया गया है )।



मान लें कि आपके टेम्पलेट आपके मॉड्यूल के पैकेज के अंदर नेस्टेड फ़ोल्डर में स्थित हैं:

  <your-package>
    +--<module-asking-the-file>
    +--templates/
          +--temp_file                         <-- We want this file.

नोट 1: सुनिश्चित करने के लिए, हमें __file__विशेषता के साथ फ़ेल्ड नहीं करना चाहिए (जैसे ज़िप से सेवा करने पर कोड टूट जाएगा)।

नोट 2: यदि आप इस पैकेज का निर्माण कर रहे हैं, तो अपनी डेटा फ़ाइलों को package_dataयाdata_files अपने रूप में घोषित करना याद रखें setup.py

1) (धीमी गति pkg_resourcesसे ) का उपयोग करनाsetuptools

आप सेटटॉपूल वितरण pkg_resourcesसे पैकेज का उपयोग कर सकते हैं , लेकिन यह लागत, प्रदर्शन-वार के साथ आता है :

import pkg_resources

# Could be any dot-separated package/module name or a "Requirement"
resource_package = __name__
resource_path = '/'.join(('templates', 'temp_file'))  # Do not use os.path.join()
template = pkg_resources.resource_string(resource_package, resource_path)
# or for a file-like stream:
template = pkg_resources.resource_stream(resource_package, resource_path)

सुझाव:

  • यदि आपका वितरण ज़िपित है, तो भी यह डेटा पढ़ेगा, इसलिए आप zip_safe=Trueअपने में सेट कर सकते हैं setup.py, और / या स्व-निहित वितरण बनाने के लिए अजगर-3.5 से लंबे समय से प्रतीक्षित zipappपैकर का उपयोग कर सकते हैं ।

  • setuptoolsअपनी रन-टाइम आवश्यकताओं (जैसे install_requires` में) को जोड़ना याद रखें ।

... और ध्यान दें कि Setuptools / pkg_resourcesडॉक्स के अनुसार , आपको उपयोग नहीं करना चाहिए os.path.join:

बेसिक रिसोर्स एक्सेस

ध्यान दें कि संसाधन नामों को /-separated पथ होना चाहिए और पूर्ण नहीं हो सकता है (अर्थात कोई अग्रणी नहीं /) या " .." जैसे सापेक्ष नाम हों । करो नहीं का उपयोग os.pathदिनचर्या संसाधन पथ हेरफेर करने के लिए, के रूप में वे कर रहे हैं नहीं फाइल सिस्टम पथ।

2) पायथन> = 3.7, या बैकपोर्ट importlib_resourcesलाइब्रेरी का उपयोग करना

मानक पुस्तकालय के importlib.resourcesमॉड्यूल का उपयोग करें जो setuptoolsऊपर की तुलना में अधिक कुशल है :

try:
    import importlib.resources as pkg_resources
except ImportError:
    # Try backported to PY<37 `importlib_resources`.
    import importlib_resources as pkg_resources

from . import templates  # relative-import the *package* containing the templates

template = pkg_resources.read_text(templates, 'temp_file')
# or for a file-like stream:
template = pkg_resources.open_text(templates, 'temp_file')

ध्यान:

समारोह के बारे में read_text(package, resource):

  • packageया तो एक स्ट्रिंग या एक मॉड्यूल हो सकता है।
  • resourceअब एक रास्ता है, लेकिन अभी खुला करने के लिए संसाधन, एक मौजूदा पैकेज के भीतर के फ़ाइल नाम नहीं है; इसमें पथ विभाजक नहीं हो सकते हैं और इसमें उप-संसाधन नहीं हो सकते हैं (अर्थात यह एक निर्देशिका नहीं हो सकती है)।

प्रश्न में पूछे गए उदाहरण के लिए, हमें अभी:

  • इसमें <your_package>/templates/ एक खाली __init__.pyफ़ाइल बनाकर, एक उचित पैकेज में बनाएँ,
  • इसलिए अब हम एक सरल (संभवतः सापेक्ष) importकथन (कोई अधिक पार्सिंग पैकेज / मॉड्यूल नाम) का उपयोग कर सकते हैं ।
  • और बस resource_name = "temp_file"(कोई रास्ता नहीं) के लिए पूछना ।

सुझाव:

  • वर्तमान मॉड्यूल के अंदर एक फ़ाइल तक पहुंचने के लिए __package__, पैकेज तर्क को , उदाहरण के लिए pkg_resources.read_text(__package__, 'temp_file')(@ बेन-मार्स के लिए) सेट करें।
  • हालात दिलचस्प हो जाते हैं जब एक वास्तविक फ़ाइल नाम के साथ कहा जाता है path(), के बाद से अब संदर्भ प्रबंधकों अस्थायी रूप से-बनाई गई फ़ाइलों (पढ़ने के लिए उपयोग किया जाता है इस )।
  • पुराने Pythons के लिए सशर्त रूप से, बैकपोर्ट की गई लाइब्रेरी जोड़ें, install_requires=[" importlib_resources ; python_version<'3.7'"]( यह जाँचें कि क्या आप अपने प्रोजेक्ट को पैकेज करते हैं setuptools<36.2.1)।
  • यदि आप पारंपरिक विधि से माइग्रेट हुए हैं, तो setuptoolsअपने रनटाइम-रिक्वायरमेंट से लाइब्रेरी को हटाना न भूलें ।
  • अनुकूलित करने के लिए याद रखें setup.pyया MANIFESTकरने के लिए किसी भी स्थिर फ़ाइलों में शामिल हैं
  • आप zip_safe=Trueअपने में भी सेट कर सकते हैं setup.py

1
str.join सीक्वेंस रिसोर्स_पैथ = '/'.जॉइन (( नोटेम्प्ट्स', 'टेम्पप_फाइल'))
लेता है

मुझे NotImplementedError: Can't perform this operation for loaders without 'get_data()'कोई विचार मिल रहा है ?
leoschet

ध्यान दें कि importlib.resourcesऔर आवश्यक रूप से संगत नहींpkg_resources हैं । zipfiles के साथ काम करता है , setuptools और अंडे फ़ाइलों के साथ काम करने के लिए, जो zipfiles एक निर्देशिका है कि खुद को जोड़ा जाता है में संग्रहीत हैं । जैसे , अंडे अंदर जाते हैं , लेकिन इसमें पैकेज भी आयात किए जा सकते हैं। आप पैकेज से डेटा निकालने के लिए उपयोग नहीं कर सकते । अगर अंडे के साथ काम करने के लिए आवश्यक लोडर पंजीकृत करता है तो मैंने जाँच नहीं की है । importlib.resourcessys.pathpkg_resourcessys.pathsys.path = [..., '.../foo', '.../bar.zip'].../foobar.zippkg_resourcesbar.zipimportlib.resources
मार्टिन पीटर्स

यदि त्रुटि Package has no locationदिखाई देती है, तो अतिरिक्त setup.py कॉन्फ़िगरेशन की आवश्यकता है?
जिग्मेंटस

1
यदि आप वर्तमान मॉड्यूल के अंदर एक फ़ाइल का उपयोग करना चाहते हैं (और templatesउदाहरण के अनुसार एक सबमॉड्यूल नहीं ), तो आप packageतर्क को सेट कर सकते हैं __package__, जैसेpkg_resources.read_text(__package__, 'temp_file')
बेन मार्स

42

एक पैकेजिंग प्रस्तावना:

इससे पहले कि आप संसाधन फ़ाइलों को पढ़ने के बारे में भी चिंता कर सकते हैं, पहला कदम यह सुनिश्चित करना है कि डेटा फ़ाइलों को पहली बार आपके वितरण में पैक किया जा रहा है - उन्हें सीधे स्रोत के पेड़ से पढ़ना आसान है, लेकिन महत्वपूर्ण हिस्सा बना रहा है सुनिश्चित करें कि ये संसाधन फ़ाइलें एक संस्थापित पैकेज में कोड से सुलभ हैं ।

अपनी परियोजना को इस तरह से संरचित करें, डेटा फ़ाइलों को पैकेज के भीतर एक उपनिर्देशिका में डालें :

.
├── package
   ├── __init__.py
   ├── templates
      └── temp_file
   ├── mymodule1.py
   └── mymodule2.py
├── README.rst
├── MANIFEST.in
└── setup.py

आपको कॉल include_package_data=Trueमें पास होना चाहिए setup()। मैनिफ़ेस्ट फ़ाइल की केवल तभी आवश्यकता होती है जब आप सेटपूल / डिस्टिलिल का उपयोग करना चाहते हैं और स्रोत वितरण का निर्माण करते हैं। यह सुनिश्चित करने के लिए कि templates/temp_fileइस उदाहरण प्रोजेक्ट संरचना के लिए पैक किया गया है, इस तरह की लाइन को प्रकट फ़ाइल में जोड़ें:

recursive-include package *

ऐतिहासिक क्रॉफ़्ट नोट: आधुनिक बिल्ड बैकेंड जैसे फ्लिट, कविता के लिए एक मैनिफ़ेस्ट फ़ाइल का उपयोग करने की आवश्यकता नहीं है , जिसमें डिफ़ॉल्ट रूप से पैकेज डेटा फ़ाइलें शामिल होंगी। इसलिए, यदि आप उपयोग कर रहे हैं pyproject.tomlऔर आपके पास कोई setup.pyफ़ाइल नहीं है, तो आप इसके बारे में सभी सामग्री को अनदेखा कर सकते हैं MANIFEST.in

अब, पैकेजिंग के साथ, पठन भाग पर ...

सिफ़ारिश करना:

मानक लाइब्रेरी pkgutilAPIs का उपयोग करें । यह पुस्तकालय कोड में इस तरह दिखने वाला है:

# within package/mymodule1.py, for example
import pkgutil

data = pkgutil.get_data(__name__, "templates/temp_file")
print("data:", repr(data))
text = pkgutil.get_data(__name__, "templates/temp_file").decode()
print("text:", repr(text))

यह zips में काम करता है। यह पायथन 2 और पायथन 3 पर काम करता है। इसे थर्ड-पार्टी निर्भरता की आवश्यकता नहीं है। मुझे वास्तव में किसी भी डाउनसाइड्स के बारे में पता नहीं है (यदि आप हैं, तो कृपया उत्तर पर टिप्पणी करें)।

बचने के बुरे तरीके:

खराब रास्ता # 1: स्रोत फ़ाइल से सापेक्ष पथ का उपयोग करना

यह वर्तमान में स्वीकृत उत्तर है। सबसे अच्छा, यह कुछ इस तरह दिखता है:

from pathlib import Path

resource_path = Path(__file__).parent / "templates"
data = resource_path.joinpath("temp_file").read_bytes()
print("data", repr(data))

इसमें गलत क्या है? आपके पास उपलब्ध फ़ाइलों और उपनिर्देशिकाओं की धारणा सही नहीं है। यह तरीका काम नहीं करता है अगर कोड को ज़िप या व्हील में पैक किया जाता है, और यह पूरी तरह से उपयोगकर्ता के नियंत्रण से बाहर हो सकता है कि क्या आपका पैकेज फाइल सिस्टम पर बिल्कुल भी नहीं निकाला जाता है।

खराब तरीका # 2: pkg_resources API का उपयोग करना

यह शीर्ष मतदान के उत्तर में वर्णित है। यह कुछ इस तरह दिखता है:

from pkg_resources import resource_string

data = resource_string(__name__, "templates/temp_file")
print("data", repr(data))

इसमें गलत क्या है? यह एक कहते हैं क्रम पर निर्भरता setuptools , जो अधिमानतः एक होना चाहिए स्थापित केवल समय निर्भरता। आयात करना और उपयोग करना pkg_resourcesवास्तव में धीमा हो सकता है, क्योंकि कोड सभी स्थापित पैकेजों का एक कार्य सेट बनाता है, भले ही आप केवल अपने स्वयं के पैकेज संसाधनों में रुचि रखते थे । यह स्थापित समय पर एक बड़ी बात नहीं है (क्योंकि स्थापना एक बार बंद है), लेकिन यह रनटाइम पर बदसूरत है।

खराब तरीका # 3: importlib.resources API का उपयोग करना

यह वर्तमान में शीर्ष-मतदान जवाब में सिफारिश है। यह हाल ही में एक मानक पुस्तकालय परिवर्धन ( पायथन 3.7 में नया ) है, लेकिन एक बैकपोर्ट भी उपलब्ध है। यह इस तरह दिख रहा है:

try:
    from importlib.resources import read_binary
    from importlib.resources import read_text
except ImportError:
    # Python 2.x backport
    from importlib_resources import read_binary
    from importlib_resources import read_text

data = read_binary("package.templates", "temp_file")
print("data", repr(data))
text = read_text("package.templates", "temp_file")
print("text", repr(text))

इसमें गलत क्या है? खैर, दुर्भाग्य से, यह काम नहीं करता ... अभी तक। यह अभी भी एक अधूरा एपीआई है, इसका उपयोग करके importlib.resourcesआपको एक खाली फ़ाइल जोड़ने की आवश्यकता होगी templates/__init__.pyताकि डेटा फाइलें एक उप-पैकेज के बजाय एक उप-पैकेज के भीतर रहेंगी। यह package/templatesसबडायरेक्ट को package.templatesअपने आप में एक आयात योग्य उप-पैकेज के रूप में भी उजागर करेगा । यदि यह कोई बड़ी बात नहीं है और यह आपको परेशान नहीं करता है, तो आप आगे बढ़ सकते हैं और __init__.pyवहां फ़ाइल जोड़ सकते हैं और संसाधनों तक पहुंचने के लिए आयात प्रणाली का उपयोग कर सकते हैं। हालाँकि, जब आप इस पर होते हैं, तो आप इसे my_resources.pyइसके बजाय एक फ़ाइल में बना सकते हैं , और बस मॉड्यूल में कुछ बाइट्स या स्ट्रिंग चर को परिभाषित करते हैं, फिर उन्हें पायथन कोड में आयात करते हैं। यह आयात प्रणाली यहाँ भारी भारोत्तोलन कर रही है।

उदाहरण परियोजना:

मैंने github पर एक उदाहरण परियोजना बनाई है और PyPI पर अपलोड की गई है , जो ऊपर चर्चा किए गए सभी चार दृष्टिकोणों को प्रदर्शित करता है। इसके साथ आज़माएँ:

$ pip install resources-example
$ resources-example

अधिक जानकारी के लिए https://github.com/wimglenn/resources-example देखें ।


1
इसे पिछले मई में संपादित किया गया है। लेकिन मुझे लगता है कि इंट्रो में स्पष्टीकरण को याद रखना आसान है। फिर भी, आप लोगों को मानक के खिलाफ सलाह देते हैं - कि काटने के लिए एक कठिन गोली है :-)
18

1
@ankostis मुझे इसके बजाय प्रश्न को चालू करने दें, आप importlib.resourcesइन सभी कमियों के बावजूद एक अधूरे एपीआई के साथ अनुशंसा क्यों करेंगे जो पहले से ही लंबित है ? जरूरी नहीं कि नया बेहतर हो। मुझे बताओ कि यह वास्तव में stdlib pkgutil पर क्या लाभ प्रदान करता है , जो आपके उत्तर के बारे में कोई उल्लेख नहीं करता है?
विम

1
प्रिय @wim, ब्रेट कैनन की अंतिम प्रतिक्रिया की pkgutil.get_data()पुष्टि के उपयोग पर मेरी आंत की भावना - यह एक अविकसित, टू-डिप्रेस्ड एपीआई है। उस ने कहा, मैं आपसे सहमत हूं, importlib.resourcesज्यादा बेहतर विकल्प नहीं है, लेकिन जब तक PY3.10 इसे हल नहीं करता है, तब तक मैं इस विकल्प से खड़ा हूं, हेविंग ने सीखा कि यह डॉक्स द्वारा अनुशंसित एक और "मानक" नहीं है।
एकॉस्टिसिस

1
@ankostis मैं ब्रेट की टिप्पणियों को नमक के दाने के साथ ले जाऊंगा। पीईपी 594pkgutil के अपग्रेडेशन शेड्यूल पर बिल्कुल भी उल्लेख नहीं किया गया है - मानक पुस्तकालय से मृत बैटरियों को हटाना , और एक अच्छे कारण के बिना हटाए जाने की संभावना नहीं है। यह Python 2.3 के बाद से आसपास रहा है और PEP 302 में लोडर प्रोटोकॉल के हिस्से के रूप में निर्दिष्ट किया गया है । "अंडर-डिफाइंड एपीआई" का उपयोग करना एक बहुत ही ठोस उत्तर नहीं है, जो कि बहुसंख्यक पायथन मानक पुस्तकालय का वर्णन कर सकता है!
विम

2
मुझे जोड़ने दें: मैं importlib संसाधनों को सफल होते देखना चाहता हूं! मैं सभी कठोरता से परिभाषित एपीआई के लिए हूँ। यह सिर्फ अपनी वर्तमान स्थिति में है, यह वास्तव में अनुशंसित नहीं किया जा सकता है। एपीआई अभी भी परिवर्तन के दौर से गुजर रहा है, यह कई मौजूदा पैकेजों के लिए अनुपयोगी है, और केवल अपेक्षाकृत हाल के पायथन रिलीज में उपलब्ध है। व्यवहार में यह pkgutilहर तरह से बदतर है । आपकी "आंत की भावना" और अधिकार के लिए अपील मेरे लिए व्यर्थ है, अगर get_dataलोडर के साथ समस्याएं हैं तो सबूत और व्यावहारिक उदाहरण दिखाएं।
विम

15

यदि आपके पास यह संरचना है

lidtk
├── bin
   └── lidtk
├── lidtk
   ├── analysis
      ├── char_distribution.py
      └── create_cm.py
   ├── classifiers
      ├── char_dist_metric_train_test.py
      ├── char_features.py
      ├── cld2
         ├── cld2_preds.txt
         └── cld2wili.py
      ├── get_cld2.py
      ├── text_cat
         ├── __init__.py
         ├── README.md   <---------- say you want to get this
         └── textcat_ngram.py
      └── tfidf_features.py
   ├── data
      ├── __init__.py
      ├── create_ml_dataset.py
      ├── download_documents.py
      ├── language_utils.py
      ├── pickle_to_txt.py
      └── wili.py
   ├── __init__.py
   ├── get_predictions.py
   ├── languages.csv
   └── utils.py
├── README.md
├── setup.cfg
└── setup.py

आपको इस कोड की आवश्यकता है:

import pkg_resources

# __name__ in case you're within the package
# - otherwise it would be 'lidtk' in this example as it is the package name
path = 'classifiers/text_cat/README.md'  # always use slash
filepath = pkg_resources.resource_filename(__name__, path)

अजीब "हमेशा स्लैश का उपयोग करें" हिस्सा setuptoolsएपीआई से आता है

यह भी ध्यान दें कि यदि आप पथों का उपयोग करते हैं, तो आपको पथ विभाजक के रूप में आगे स्लैश (/) का उपयोग करना होगा, भले ही आप विंडोज पर हों। Setuptools स्वचालित रूप से निर्माण समय पर उपयुक्त प्लेटफ़ॉर्म-विशिष्ट विभाजकों में स्लैश को कनवर्ट करता है

मामले में आपको आश्चर्य है कि प्रलेखन कहाँ है:


आपके संक्षिप्त उत्तर के लिए धन्यवाद
पाओलो

8

पाइथन कुकबुक के "10.8। रीडिंग डेटाफाइल्स इन ए पैकेज" की सामग्री, डेविड बेज़ले द्वारा तीसरा संस्करण और ब्रायन के। जोन्स जवाब दे रहे हैं।

मैं इसे यहाँ ले आता हूँ:

मान लें कि आपके पास निम्नानुसार व्यवस्थित फ़ाइलों के साथ एक पैकेज है:

mypackage/
    __init__.py
    somedata.dat
    spam.py

अब मान लें कि फ़ाइल स्पैमहोम फ़ाइल की सामग्री को किसी दिन पढ़ना चाहता है। ऐसा करने के लिए, निम्नलिखित कोड का उपयोग करें:

import pkgutil
data = pkgutil.get_data(__package__, 'somedata.dat')

परिणामी चर डेटा एक बाइट स्ट्रिंग होगी जिसमें फ़ाइल की कच्ची सामग्री होगी।

Get_data () के लिए पहला तर्क एक स्ट्रिंग है जिसमें पैकेज नाम है। आप या तो इसे सीधे आपूर्ति कर सकते हैं या एक विशेष चर का उपयोग कर सकते हैं, जैसे कि __package__। दूसरा तर्क पैकेज के भीतर फाइल का सापेक्षिक नाम है। यदि आवश्यक हो, तो आप मानक यूनिक्स फ़ाइल नाम सम्मेलनों का उपयोग करके विभिन्न निर्देशिकाओं में नेविगेट कर सकते हैं जब तक कि अंतिम निर्देशिका अभी भी पैकेज के भीतर स्थित है।

इस तरह, पैकेज निर्देशिका, .zip या .egg के रूप में स्थापित किया जा सकता है।


0

आपके पैकेज के हर अजगर मॉड्यूल में एक __file__विशेषता है

आप इसका उपयोग इस प्रकार कर सकते हैं:

import os 
from mypackage

templates_dir = os.path.join(os.path.dirname(mypackage.__file__), 'templates')
template_file = os.path.join(templates_dir, 'template.txt')

अंडा संसाधनों के लिए देखें: http://peak.telecommunity.com/DevCenter/PythonEggs#accessing-package-resource


-2

यह मानते हुए कि आप एक अंडा फ़ाइल का उपयोग कर रहे हैं; नहीं निकाला गया:

मैं एक हालिया परियोजना में इसे "हल" कर रहा हूं, एक बाद की स्क्रिप्ट का उपयोग करके, जो मेरे टेम्पलेट को अंडे (ज़िप फ़ाइल) से फाइल सिस्टम में उचित निर्देशिका में निकालता है। यह मेरे द्वारा पाया गया सबसे तेज, सबसे विश्वसनीय समाधान था, क्योंकि __path__[0]कभी-कभी काम करना गलत हो सकता है (मुझे नाम याद नहीं है, लेकिन मैं कम से कम एक पुस्तकालय में काम करता हूं, जिससे उस सूची के सामने कुछ जुड़ गया!)।

इसके अलावा, अंडे की फाइलें आमतौर पर "अंडे कैश" नामक अस्थायी स्थान पर मक्खी पर निकाली जाती हैं। आप पर्यावरण स्क्रिप्ट का उपयोग करके उस स्थान को बदल सकते हैं, या तो अपनी स्क्रिप्ट शुरू करने से पहले या बाद में भी, जैसे।

os.environ['PYTHON_EGG_CACHE'] = path

हालांकि वहाँ pkg_resources है जो ठीक से काम कर सकता है।

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