यदि किसी पैकेज के अंदर की कोई पायथन फ़ाइल सीधे चलाने पर ImportError: attempted relative import with no known parent package उत्पन्न करती है, तो इसे पैकेज के ऊपर वाली डायरेक्टरी से एक मॉड्यूल के रूप में शुरू करें। macOS पर, टर्मिनल में प्रोजेक्ट रूट पर जाएँ, फिर python3 -m package.module चलाएँ। यह पायथन को वह पैकेज संदर्भ (context) देता है जो एक सीधा फ़ाइल पथ प्रदान नहीं करता है।
जब मैं किसी फ़ाइल को सीधे चलाता हूँ तो रिलेटिव इम्पोर्ट विफल क्यों हो जाता है?
एक रिलेटिव इम्पोर्ट जैसे from .helpers import format_result मॉड्यूल के पैकेज नाम पर निर्भर करता है। पायथन वर्तमान पैकेज और उसके पैरेंट्स की पहचान करने के लिए शुरुआती डॉट्स (leading dots) का उपयोग करता है। जब आप python3 path/to/file.py के साथ कोई फ़ाइल चलाते हैं, तो पायथन उस फ़ाइल को शीर्ष-स्तरीय (top-level) __main__ मॉड्यूल के रूप में चलाता है; यह इसे डॉट को रीसॉल्व करने के लिए आवश्यक पैकेज मेटाडेटा नहीं देता है। इसलिए, भले ही helpers.py फ़ाइल के बगल में हो, फिर भी इम्पोर्ट विफल हो सकता है। पायथन का इम्पोर्ट संदर्भ रिलेटिव इम्पोर्ट और __main__ के विशेष संचालन का वर्णन करता है।
उदाहरण के लिए, मान लें कि आपका प्रोजेक्ट इस प्रकार व्यवस्थित है:
project/
└── myapp/
├── __init__.py
├── cli.py
└── helpers.py
यदि cli.py में from .helpers import format_result शामिल है, तो project से python3 myapp/cli.py चलाना गलत तरीका (invocation) है। समस्या यह है कि पायथन से फ़ाइल को कैसे चलाने के लिए कहा गया था, न कि यह कि रिलेटिव इम्पोर्ट या फ़ाइल का स्थान गलत है।
macOS पर प्रोजेक्ट रूट से मॉड्यूल चलाएँ
टर्मिनल खोलें और उस डायरेक्टरी में जाएँ जिसमें myapp शामिल है। उदाहरण पथ को अपने प्रोजेक्ट के वास्तविक स्थान से बदलें। पथ को कोट्स (quotes) में रखें ताकि शेल द्वारा रिक्त स्थान (spaces) को संभाला जा सके; macOS टर्मिनल का डिफ़ॉल्ट शेल zsh है। एप्पल की टर्मिनल गाइड उस डिफ़ॉल्ट का दस्तावेजीकरण करती है।
cd "/Users/yourname/Projects/project"
python3 -m myapp.cli
-m विकल्प पायथन से मॉड्यूल को उसके डॉटेड पैकेज नाम से खोजने और चलाने के लिए कहता है। कमांड में पैकेज का नाम रखें और .py तथा फ़ाइल सिस्टम स्लैश छोड़ दें। -m के साथ शुरू किए जाने पर पायथन का मॉड्यूल सर्च पाथ वर्तमान डायरेक्टरी से शुरू होता है, यही कारण है कि प्रोजेक्ट रूट से चलाना महत्वपूर्ण है। पायथन का sys.path दस्तावेज़ इस शुरुआती पथ की व्याख्या करता है।
यदि कमांड गलत पायथन इंस्टॉलेशन का उपयोग करता है, तो पहले प्रोजेक्ट के मौजूदा वर्चुअल एनवायरनमेंट को सक्रिय करें, फिर उसी python -m पैटर्न का उपयोग करें। प्रोजेक्ट रूट में एक सामान्य .venv के लिए:
cd "/Users/yourname/Projects/project"
source .venv/bin/activate
python -m myapp.cli
सक्रियण के बाद python का उपयोग करने से उस एनवायरनमेंट का इंटरप्रेटर चुना जाता है। यदि आपके एनवायरनमेंट का नाम या स्थान अलग है, तो सक्रियण पथ को समायोजित करें; यह मान न लें कि .venv मौजूद ही है। आप python -c 'import sys; print(sys.executable)' के साथ चयनित इंटरप्रेटर की जाँच कर सकते हैं।
यदि आप पैकेज को ही चलाना चाहते हैं
पैकेज को लॉन्च करने के उद्देश्य से बनाई गई कमांड के लिए, पैकेज के अंदर __main__.py जोड़ें और एंट्री पॉइंट को छोटा रखें:
myapp/
├── __init__.py
├── __main__.py
├── cli.py
└── helpers.py
myapp/__main__.py में, पैकेज के एंट्री फ़ंक्शन को इम्पोर्ट करें और कॉल करें। फिर प्रोजेक्ट रूट से python3 -m myapp चलाएँ। पायथन -m के इस रूप के लिए पैकेज के __main__.py को निष्पादित करता है, और वह फ़ाइल पैकेज-रिलेटिव इम्पोर्ट का उपयोग कर सकती है। पायथन __main__ दस्तावेज़ इस पैकेज एंट्री-पॉइंट पैटर्न की व्याख्या करता है।
यदि त्रुटि बनी रहती है तो इन विवरणों की जाँच करें
- अपनी वर्किंग डायरेक्टरी की पुष्टि करें। टर्मिनल में
pwdचलाएँ और सुनिश्चित करें कि यह प्रोजेक्ट रूट प्रिंट करता है, वह डायरेक्टरी जिसमेंmyappहै। उदाहरण के लिए, यदि पैकेजsrcके तहत नेस्टेड है, तो इम्पोर्ट करने योग्य पैकेज नाम का उपयोग करें और सुनिश्चित करें कि प्रोजेक्ट का कॉन्फ़िगर किया गया एनवायरनमेंट इसे उपलब्ध कराता है; केवल गलत पैरेंट फ़ोल्डर में जाने से मॉड्यूल डिस्कवरी ठीक नहीं होगी। - वास्तविक पैकेज नाम का उपयोग करें।
python3 -m myapp.cliमें,myappपैकेज डायरेक्टरी का नाम (या इसका इम्पोर्ट नाम) होना चाहिए, औरcliबिना.pyके मॉड्यूल फ़ाइल नाम होना चाहिए। - ट्रेसबैक लाइन की जाँच करें। यदि रिलेटिव इम्पोर्ट रीसॉल्व हो जाता है लेकिन बाद का इम्पोर्ट विफल हो जाता है, तो वह एक अलग गुम मॉड्यूल या डिपेंडेंसी हो सकती है। लॉन्च संदर्भ को ठीक करने से केवल पैकेज-संदर्भ विफलता का समाधान होता है।
- पहले समाधान के रूप में
PYTHONPATHसे बचें। यह पायथन के इम्पोर्ट सर्च पाथ को बदलता है, लेकिन यह अपने आप में सीधे निष्पादित फ़ाइल को ठीक से नामित पैकेज मॉड्यूल में नहीं बदलता है। पायथन यह चेतावनी भी देता है किPYTHONPATHकई पायथन वर्ज़न और एनवायरनमेंट को प्रभावित कर सकता है। पायथन का पाथ इनिशियलाइज़ेशन संदर्भ इसके दायरे का वर्णन करता है। - यदि फ़ाइल का सीधा निष्पादन एक आवश्यकता है, तो उचित एब्सोल्यूट इम्पोर्ट का उपयोग करने के लिए कोड को बदलने पर विचार करें और सुनिश्चित करें कि पैकेज उस एनवायरनमेंट में स्थापित है या अन्यथा इम्पोर्ट करने योग्य है। यह एक अलग सेटअप विकल्प है; पैकेज-रिलेटिव इम्पोर्ट को इस उम्मीद के साथ न मिलाएँ कि फ़ाइल एक स्टैंडअलोन स्क्रिप्ट की तरह व्यवहार करेगी।
व्यावहारिक नियम कमांड को इम्पोर्ट शैली से मिलाना है: पैकेज-रिलेटिव इम्पोर्ट के लिए, पैकेज की पैरेंट डायरेक्टरी से python -m के साथ मॉड्यूल चलाएँ। पैकेज कमांड के लिए, __main__.py प्रदान करें और पैकेज को -m के साथ चलाएँ।
स्रोत
- 5. The import system — Python Software Foundation
- The initialization of the sys.path module search path — Python Software Foundation
- main — Top-level code environment — Python Software Foundation
- Change the default shell in Terminal on Mac — Apple