2025, Oct 04 21:33
mypy की Source file found twice त्रुटि समझें: वजह, उदाहरण और तीन आसान समाधान
mypy की Source file found twice त्रुटि कब और क्यों आती है, और इसे कैसे ठीक करें: इम्पोर्ट पाथ संरेखित करें, __init__.py जोड़ें, या -p फ्लैग का उपयोग भी करें।
जब mypy “Source file found twice under different module names” रिपोर्ट करता है, तो इसका मतलब है कि वही Python फ़ाइल दो अलग-अलग इम्पोर्ट पाथ के तहत इंडेक्स हो रही है। यह अक्सर उन प्रोजेक्ट्स में होता है जहाँ testing जैसी डायरेक्टरी असल में पैकेज नहीं होती, लेकिन कोड को ऐसे इम्पोर्ट किया जाता है जैसे वह पैकेज हो। नतीजा यह होता है कि मॉड्यूल की दोहरी पहचान बन जाती है और टाइप चेकर आगे बढ़ने से रोक देता है।
समस्या को दोहराने वाला न्यूनतम उदाहरण
नीचे दिया गया परिदृश्य समस्या के स्वरूप को दिखाता है। testing डायरेक्टरी को रिकर्सिव तौर पर खोजा जाता है, इसमें पैकेज की एक सबट्री है, लेकिन testing खुद पैकेज नहीं है।
mkdir -p testing/pkgcore
touch testing/pkgcore/{__init__,modutil}.py  # testing/__init__.py जानबूझकर अनुपस्थित है
echo "from testing.pkgcore import modutil" > testing/test_modutil.py
mypy testing
mypy डुप्लिकेट सोर्स त्रुटि के साथ प्रतिक्रिया देता है:
testing/pkgcore/modutil.py: error: Source file found twice under different module names: "modutil" and "testing.pkgcore.modutil"
testing/pkgcore/modutil.py: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#mapping-file-paths-to-modules for more info
testing/pkgcore/modutil.py: note: Common resolutions include: a) adding `__init__.py` somewhere, b) using `--explicit-package-bases` or adjusting MYPYPATH
Found 1 error in 1 file (errors prevented further checking)
असल में हो क्या रहा है
mypy testing चलाने पर mypy को testing फ़ोल्डर क्रॉल करने और __init__.py फ़ाइलों की मौजूदगी से पैकेज का अनुमान लगाने के लिए कहा जाता है। जिस पहले डायरेक्टरी में उसे __init__.py मिलती है, उसे रूट पैकेज माना जाता है। इसके नीचे की हर चीज़ उसी रूट के सापेक्ष नामित होती है। हमारे उदाहरण में testing/pkgcore में __init__.py है, इसलिए mypy testing/pkgcore/modutil.py को pkgcore.modutil मॉड्यूल नाम से मैप करता है।
समस्या यह है कि test_modutil.py में इम्पोर्ट from testing.pkgcore import modutil का उपयोग करता है। यह स्टेटमेंट मानता है कि testing स्वयं एक पैकेज है, जो उस तरीके से टकराता है जिससे mypy ने मॉड्यूल खोजा। तब mypy उसी फ़ाइल को दो बार देखता है: एक बार pkgcore.modutil के रूप में और एक बार testing.pkgcore.modutil के रूप में। यही असंगति डुप्लिकेट सोर्स त्रुटि को ट्रिगर करती है।
यही पैटर्न वास्तविक मामले में भी दिखा: testing/example_scripts/rewrite/tests/test_main.py ने testing.example_scripts.rewrite.src.main import func से इम्पोर्ट किया, जबकि mypy की डिस्कवरी ने testing/example_scripts/rewrite/src/main.py को किसी अलग रूट का हिस्सा माना, इसलिए फ़ाइल दो अलग पहचान के साथ नज़र आई।
इसे कैसे ठीक करें
इम्पोर्ट पाथ और mypy की मॉड्यूल डिस्कवरी को एक मत में लाने के तीन सीधे तरीके हैं। अपने प्रोजेक्ट के लेआउट और टूलिंग की अपेक्षाओं के अनुरूप एक विकल्प चुनें।
पहला, इम्पोर्ट्स को उस नामकरण के साथ संरेखित करें जैसा mypy खोजे गए मॉड्यूल को देता है। अगर mypy testing/pkgcore/modutil.py को pkgcore.modutil मानता है, तो testing के जरिए इम्पोर्ट करना ही डुप्लीकेशन पैदा करता है। इम्पोर्ट को खोजे गए नाम पर स्विच करना टकराव दूर कर देता है।
echo "from pkgcore import modutil" > testing/test_modutil.py
mypy testing
# सफलता: 3 स्रोत फ़ाइलों में कोई समस्या नहीं मिली
यह विकल्प रेखांकित करता है कि testing सोर्स लेआउट का हिस्सा है, कोई पैकेज नहीं। यह टेस्ट्स को अलग रखता है, जबकि कोड को उसके वास्तविक पैकेज नाम से इम्पोर्ट करता है। अन्य टूल्स को अपने रन के दौरान testing को मॉड्यूल सर्च पाथ में रखने के लिए sys.path में हल्का बदलाव चाहिए हो सकता है।
दूसरा, mypy को पैकेज-सचेत जांच के रूप में चलाएँ। -p फ्लैग का उपयोग mypy को स्पष्ट रूप से बताता है कि testing एक पैकेज नेमस्पेस है। इस संकेत के साथ, mypy testing/pkgcore/modutil.py को testing.pkgcore.modutil पर मैप करता है, जो आपके इम्पोर्ट्स से मेल खाता है।
mypy -p testing
# सफलता: 4 स्रोत फ़ाइलों में कोई समस्या नहीं मिली
तीसरा, रूट पर __init__.py जोड़कर testing को एक पैकेज बना दें। एक बार testing पैकेज हो गया तो mypy मॉड्यूल नाम testing से शुरू करेगा, और from testing.pkgcore import modutil जैसे इम्पोर्ट्स से फिर मेल बैठेगा।
touch testing/__init__.py
mypy testing
# सफलता: 4 स्रोत फ़ाइलों में कोई समस्या नहीं मिली
यह क्यों मायने रखता है
सुसंगत मॉड्यूल पहचान स्थिर विश्लेषण की बुनियाद है। अगर वही फ़ाइल अलग-अलग इम्पोर्ट पाथों से पहुँची जा सकती है, तो टाइप चेकर उसे समान सामग्री वाले दो असंबंधित मॉड्यूलों की तरह देखता है। इससे इन्क्रीमेंटल विश्लेषण टूटता है, कैश अमान्य होते हैं, और असली त्रुटियाँ डुप्लिकेट-सोर्स विफलताओं की बाढ़ में छिप सकती हैं। mypy से आगे बढ़कर, यही असंगति रनटाइम में भी रिस सकती है और टेस्ट्स व टूल्स में चौंकाने वाले इम्पोर्ट व्यवहार पैदा कर सकती है।
निष्कर्ष
जब किसी डायरेक्टरी ट्री पर mypy चलाएँ, तो समझें कि वह फ़ाइल पाथ को मॉड्यूल नामों से कैसे मैप करता है। या तो कोड को उन्हीं नामों से इम्पोर्ट करें जिन्हें mypy निरूपित करता है, या mypy को इस तरह चलाएँ कि वह आपके पैकेज बॉन्ड्रीज़ को घोषित करे, या पैकेज औपचारिक करने के लिए गायब __init__.py जोड़ें। अगर आपको डुप्लिकेट-सोर्स संदेश मिलता है, तो mypy का आउटपुट मददगार दिशाएँ दिखाता है—जिसमें path-to-module मैपिंग पर प्रलेखन और सुझाव जैसे __init__.py जोड़ना, --explicit-package-bases का उपयोग करना, या MYPYPATH को समायोजित करना शामिल हैं। अपने इम्पोर्ट ग्राफ़ को पैकेज लेआउट के साथ संरेखित रखने से ये टकराव नहीं होंगे और टाइप चेकिंग पूर्वानुमेय बनेगी।