__Init__.py के साथ भी “नॉन-पैकेज में रिलेटेड रिलेटेड इम्पोर्ट” को कैसे ठीक करें


744

मैं निम्नलिखित निर्देशिका संरचना के साथ PEP 328 का अनुसरण करने की कोशिश कर रहा हूं :

pkg/
  __init__.py
  components/
    core.py
    __init__.py
  tests/
    core_test.py
    __init__.py

में core_test.pyमैं निम्नलिखित इंपोर्ट स्टेटमेंट है

from ..components.core import GameLoopEvents

हालाँकि, जब मैं दौड़ता हूँ, मुझे निम्न त्रुटि मिलती है:

tests$ python core_test.py 
Traceback (most recent call last):
  File "core_test.py", line 3, in <module>
    from ..components.core import GameLoopEvents
ValueError: Attempted relative import in non-package

आसपास खोज करने पर मैंने पाया कि " रिश्तेदार पथ __init__.py " और " किसी रिश्तेदार पथ से एक मॉड्यूल आयात करें " के साथ भी काम नहीं कर रहा है, लेकिन मैंने मदद नहीं की।

क्या मुझे यहाँ कुछ याद आ रहा है?


17
मैं ढांचागत unittestपरियोजनाओं के विभिन्न तरीकों से भी बहुत उलझन में था , इसलिए मैंने यह काफी संपूर्ण नमूना परियोजना लिखी , जिसमें मॉड्यूल, रिश्तेदार और निरपेक्ष आयात (जहां काम नहीं करते) और गहरी और घोंसले से मुक्त संदर्भ शामिल हैं पैकेज, साथ ही एकल, डबल, और कक्षाओं के पैकेज-स्तरीय आयात। मेरे लिए सही चीजों में मदद की !
cod3monk3y

1
मैं काम करने के लिए आपके परीक्षण नहीं कर सका। no module named myimports.fooजब मैं उन्हें चलाता हूं तो मिलते रहें ।
ब्लेयरग 2323 22'15

@ Blairg23 मेरा अनुमान है कि इरादा मंगलाचरण के लिए है cdमें PyImports, और रन python -m unittest tests.test_abs, उदाहरण के लिए।
डोज़्मो

7
मैं जीन से सहमत हूं। काश आयात प्रक्रिया को डीबग करने का एक तंत्र होता जो थोड़ा और मददगार होता। मेरे मामले में, मेरे पास एक ही निर्देशिका में दो फाइलें हैं। मैं एक फ़ाइल को दूसरी फ़ाइल में आयात करने का प्रयास कर रहा हूं। यदि मेरे पास उस निर्देशिका में init .py फ़ाइल है, तो मुझे एक ValueError मिलती है: गैर-पैकेज त्रुटि में संबंधित आयात का प्रयास किया गया। यदि मैं init .py फ़ाइल को निकालता हूं , तो मुझे 'NAME' त्रुटि नाम का कोई मॉड्यूल नहीं मिलता है।
user1928764

मेरे मामले में, मेरे पास एक ही निर्देशिका में दो फाइलें हैं। मैं एक फ़ाइल को दूसरी फ़ाइल में आयात करने का प्रयास कर रहा हूं। यदि मेरे पास उस निर्देशिका में init .py फ़ाइल है, तो मुझे एक ValueError मिलती है: गैर-पैकेज त्रुटि में संबंधित आयात का प्रयास किया गया। यदि मैं init .py फ़ाइल को निकालता हूं , तो मुझे 'NAME' त्रुटि नाम का कोई मॉड्यूल नहीं मिलता है। वास्तव में निराशा की बात यह है कि मेरे पास यह काम था, और फिर मैंने .bashrc फ़ाइल को हटाकर खुद को पैर में गोली मार ली, जिसने PYTHONPATH को कुछ सेट किया, और अब यह काम नहीं कर रहा है।
user1928764

जवाबों:


443

हाँ। आप इसे पैकेज के रूप में उपयोग नहीं कर रहे हैं।

python -m pkg.tests.core_test

51
एक गेटा: ध्यान दें कि अंत में कोई '.py' नहीं है!
विचारार्थ

497
मैं या तो नीच का नहीं हूँ, लेकिन मुझे लगता है कि यह इस सवाल और जवाब की लोकप्रियता को देखते हुए काफी अधिक विस्तार का उपयोग कर सकता है । उपरोक्त शेल कमांड को निष्पादित करने के लिए क्या निर्देशिका से सामान की तरह, तथ्य यह है कि आप __init__.pyसभी तरह से नीचे की जरूरत है, और __package__-modifying छल (BrenBarn द्वारा नीचे वर्णित) निष्पादन योग्य लिपियों के लिए इन आयातों की अनुमति देने की जरूरत है (जैसे जब एक shebang और का उपयोग कर ./my_script.pyयूनिक्स खोल पर कर ) सभी उपयोगी होंगे। यह पूरा मसला मेरे लिए संक्षिप्त या समझने योग्य दस्तावेज़ीकरण का पता लगाने के लिए काफी पेचीदा था।
मार्क अमेरी

16
नोट: आपको pkgउस बिंदु पर निर्देशिका से बाहर होना चाहिए जहां आप CLI से इस लाइन को कहते हैं। फिर, यह अपेक्षित रूप से काम करना चाहिए। अगर आप अंदर हैं pkgऔर आप फोन करते हैं python -m tests.core_test, तो यह काम नहीं करेगा। कम से कम यह मेरे लिए नहीं था।
ब्लेयरग 2323

94
गंभीरता से, क्या आप बता सकते हैं कि आपके उत्तर में क्या चल रहा है?
पिनोचियो

18
@MarkAmery लगभग सभी काम करने की कोशिश में मेरा दिमाग खो गया, यह सब कैसे काम करता है, py फाइल के साथ सबडायरेक्ट्रीज़ के साथ एक प्रॉजेक्ट में रिलेटेड फाइल्स जिनके पास __init__.pyफाइल है फिर भी आपको एरर मिलती रहती है ValueError: Attempted relative import in non-package। मैं किसी के लिए वास्तव में अच्छे पैसे का भुगतान करूंगा, कहीं न कहीं, यह स्पष्ट रूप से अंग्रेजी में समझाऊंगा कि यह सब कैसे काम करता है।
एडजक्टप्रोफेसर फाल्कन

635

इग्नासियो वाज़केज़-अब्राम्स के जवाब पर विस्तार से जानने के लिए :

पायथन आयात तंत्र __name__वर्तमान फ़ाइल के सापेक्ष काम करता है । जब आप किसी फ़ाइल को सीधे निष्पादित करते हैं, तो उसका सामान्य नाम नहीं होता, बल्कि "__main__"उसके नाम के रूप में होता है। इसलिए रिश्तेदार आयात काम नहीं करते।

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

Http://www.python.org/dev/peps/pep-0366/ देखें जानकारी के लिए।


55
मुझे यह महसूस करने में थोड़ा समय लगा कि आप उपनिर्देशिका के python -m core_testभीतर से नहीं चल सकते हैं tests- यह माता-पिता से होना है, या आपको माता-पिता को रास्ते में जोड़ना होगा।
अराम कोचरन

3
@ डैनीस्टैपल: बिल्कुल नहीं। आप __package__निष्पादन योग्य स्क्रिप्ट फ़ाइलों को एक ही पैकेज के भीतर से अन्य मॉड्यूल को अपेक्षाकृत आयात करने के लिए उपयोग कर सकते हैं । "संपूर्ण सिस्टम" से अपेक्षाकृत आयात करने का कोई तरीका नहीं है। मुझे भी यकीन नहीं है कि आप ऐसा क्यों करना चाहेंगे।
ब्रेनबार

2
मेरा मतलब है कि अगर __package__प्रतीक "parent.child" पर सेट है, तो आप "parent.other_child" आयात करने में सक्षम होंगे। शायद मैंने इसे इतनी अच्छी तरह से वाक्यांश नहीं दिया।
डैनी स्टेपल

5
@ डैनीस्टैपल: ठीक है, यह कैसे काम करता है यह लिंक किए गए दस्तावेज़ में वर्णित है। यदि आपके पास script.pyपैकेज में कोई स्क्रिप्ट है pack.subpack, तो इसे सेट करना आपको कुछ से आयात __package__करने pack.subpackकी अनुमति देगा । ध्यान दें, जैसा कि प्रलेखन कहता है, आपके पास अभी भी सिस्टम पथ पर शीर्ष-स्तरीय पैकेज होना चाहिए। यह पहले से ही आयातित मॉड्यूल के लिए काम करने का तरीका है। केवल एक चीज आपको सीधे-निष्पादित स्क्रिप्ट्स के लिए उस व्यवहार का उपयोग करने देती है। from ..module import somethingpack.module__package__
BrenBarn

3
मैं __package__उस स्क्रिप्ट का उपयोग करता हूं जिसे सीधे निष्पादित किया जाता है लेकिन दुर्भाग्य से, मुझे निम्न त्रुटि मिलती है: "पैरेंट मॉड्यूल 'xxx' लोड नहीं हुआ, सापेक्ष आयात नहीं कर सकता"
मोनोनोक

202

import components.coreयदि आप वर्तमान निर्देशिका को संलग्न करते हैं तो आप सीधे उपयोग कर सकते हैं sys.path:

if __name__ == '__main__' and __package__ is None:
    from os import sys, path
    sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))

35
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))यह भी काम करेगा
अजय

26
from os import sysधोखा देने जैसा लगता है :)
उड़ती हुई भेड़

3
@Prrr: इसे बेहतर माना जा सकता है क्योंकि यह थोड़ा और अधिक स्पष्ट रूप से दिखाता है कि इसमें क्या जोड़ा जा रहा है sys.path- निर्देशिका का मूल फ़ाइल वर्तमान फ़ाइल में है।
Martineau

8
@flyingsheep: सहमत हैं, मैं बस एक नियमित उपयोग करूँगा import sys, os.path as path
मार्टिउ

10
FYI करें, एक ipython नोटबुक में इसका उपयोग करने के लिए, मैंने इस उत्तर को इसके लिए अनुकूलित किया import os; os.sys.path.append(os.path.dirname(os.path.abspath('.')))। फिर import components.coreमेरे लिए एक सीधा काम करता है, नोटबुक की मूल निर्देशिका से वांछित के रूप में आयात करना।
रेसिंग टैडपोल

195

यह इस बात पर निर्भर करता है कि आप अपनी स्क्रिप्ट को कैसे लॉन्च करना चाहते हैं।

यदि आप अपने यूनिटटेस्ट को कमांड लाइन से क्लासिक तरीके से लॉन्च करना चाहते हैं , तो यह है:

python tests/core_test.py

फिर, के बाद से इस मामले में 'घटकों' और 'परीक्षण' भाई बहन फ़ोल्डर हैं, तो आप रिश्तेदार मॉड्यूल या तो का उपयोग कर आयात कर सकते हैं डालने या संलग्न करने की विधि sys.path मॉड्यूल। कुछ इस तरह:

import sys
from os import path
sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
from components.core import GameLoopEvents

अन्यथा, आप अपनी स्क्रिप्ट को '-m' तर्क के साथ लॉन्च कर सकते हैं (ध्यान दें कि इस मामले में, हम एक पैकेज के बारे में बात कर रहे हैं, और इस तरह आपको '.py' एक्सटेंशन नहीं देना चाहिए )।

python -m pkg.tests.core_test

ऐसे मामले में, आप बस रिश्तेदार आयात का उपयोग कर सकते हैं जैसा कि आप कर रहे थे:

from ..components.core import GameLoopEvents

आप अंत में दोनों दृष्टिकोणों को मिला सकते हैं, ताकि आपकी स्क्रिप्ट काम करे चाहे इसे कैसे भी कहा जाए। उदाहरण के लिए:

if __name__ == '__main__':
    if __package__ is None:
        import sys
        from os import path
        sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
        from components.core import GameLoopEvents
    else:
        from ..components.core import GameLoopEvents

3
अगर मैं डीबगिंग के लिए पीडीबी का उपयोग करने की कोशिश कर रहा हूं तो मुझे क्या करना चाहिए? चूंकि आप python -m pdb myscript.pyडिबगिंग सत्र को लॉन्च करने के लिए उपयोग करते हैं।
danny

1
@dannynjust - यह एक अच्छा सवाल है क्योंकि आपके पास 2 मुख्य मॉड्यूल नहीं हो सकते हैं। आमतौर पर डिबगिंग करते समय, मैं पहली बार मैन्युअल रूप से डीबगर में ड्रॉप करना पसंद करता हूं, जहां मैं डिबगिंग शुरू करना चाहता हूं। आप ऐसा import pdb; pdb.set_trace()कोड (इनलाइन) में डालकर कर सकते हैं ।
mgilson

3
insertइसके बजाय उपयोग करना बेहतर है append? वह है,sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
स्पार्कएंडशाइन

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

1
आपको यह भी उल्लेख करना चाहिए कि जब आप मॉड्यूल के रूप में चलते हैं तो आप core_test वाली निर्देशिका में नहीं हो सकते हैं (जो कि बहुत आसान होगा)
Joseph Garvin


10

यदि आपका उपयोग मामला रनिंग टेस्ट के लिए है, और यह सीम करता है कि यह है, तो आप निम्न कार्य कर सकते हैं। अपनी परीक्षण स्क्रिप्ट को चलाने के बजाय python core_test.pyपरीक्षण फ्रेमवर्क का उपयोग करें जैसे कि pytest। फिर कमांड लाइन पर आप प्रवेश कर सकते हैं

$$ py.test

यह आपकी निर्देशिका में परीक्षण चलाएगा। इस की समस्या के समाधान हो जाता है __name__किया जा रहा है __main__कि @BrenBarn द्वारा बताया गया। अगला, __init__.pyअपनी परीक्षण निर्देशिका में एक खाली फ़ाइल डालें , इससे परीक्षण निर्देशिका आपके पैकेज का हिस्सा बन जाएगी। तब आप कर पाएंगे

from ..components.core import GameLoopEvents

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


9

मेरा त्वरित-निर्धारण निर्देशिका को पथ में जोड़ने के लिए है:

import sys
sys.path.insert(0, '../components/')

6
आपका दृष्टिकोण सभी मामलों में काम नहीं करेगा क्योंकि '../' भाग को उस निर्देशिका से हल किया जाता है जहाँ से आप अपनी स्क्रिप्ट चलाते हैं (core_test.py)। अपने दृष्टिकोण के साथ आपको core_test.py scritp चलाने से पहले 'परीक्षण' के लिए cd के लिए मजबूर किया जाता है।
१०:१६ पर xyman

7

समस्या आपके परीक्षण विधि के साथ है,

आपने कोशिश की python core_test.py

तब आपको यह त्रुटि मिलेगी ValueError: गैर-पैकेज में संबंधित आयात का प्रयास किया गया

कारण: आप गैर-पैकेज स्रोत से अपनी पैकेजिंग का परीक्षण कर रहे हैं।

इसलिए पैकेज स्रोत से अपने मॉड्यूल का परीक्षण करें।

यदि यह आपकी परियोजना संरचना है,

pkg/
  __init__.py
  components/
    core.py
    __init__.py
  tests/
    core_test.py
    __init__.py

सीडी pkg

python -m tests.core_test # dont use .py

या बाहर से pkg /

python -m pkg.tests.core_test

एकल .यदि आप उसी निर्देशिका में फ़ोल्डर से आयात करना चाहते हैं। प्रत्येक चरण के लिए एक और जोड़ें।

hi/
  hello.py
how.py

में how.py

from .hi import hello

अगर आप hello.py से आयात करना चाहते हैं तो incase करें

from .. import how

1
स्वीकार किए गए उत्तर से बेहतर है
गेब्रियलबी

उदाहरण में from .. import how, आप 'कैसे' फ़ाइल से एक विशिष्ट वर्ग / विधि का आयात करते हैं। जब मैं बराबर करता हूं from ..how import fooतब मुझे "शीर्ष स्तर के पैकेज से परे रिश्तेदार आयात का प्रयास" मिलता है
जेम्स हुल्स

3

पुराना धागा। मुझे पता चला कि __init__.py फ़ाइल __all__= ['submodule', ...]को जोड़ना और फिर लक्ष्य का उपयोग करना ठीक काम करता है।from <CURRENT_MODULE> import *


3

आप उपयोग कर सकते हैं from pkg.components.core import GameLoopEvents, उदाहरण के लिए मैं pycharm का उपयोग करता हूं, नीचे मेरी परियोजना संरचना छवि है, मैं बस रूट पैकेज से आयात करता हूं, फिर यह काम करता है:

यहां छवि विवरण दर्ज करें


3
इसने मेरे लिए काम नहीं किया। क्या आपको अपने कॉन्फ़िगरेशन में पथ सेट करना था?
मोहम्मद महजब

3

जैसा कि पाओलो ने कहा, हमारे पास 2 आमंत्रण विधियां हैं:

1) python -m tests.core_test
2) python tests/core_test.py

उनके बीच एक अंतर sys.path [0] स्ट्रिंग है। चूंकि आयात करते समय व्याख्या sys.path की खोज करेगी , हम इसके साथ कर सकते हैं tests/core_test.py:

if __name__ == '__main__':
    import sys
    from pathlib import Path
    sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
    from components import core
    <other stuff>

और इसके बाद, हम अन्य तरीकों से core_test.py चला सकते हैं:

cd tests
python core_test.py
python -m core_test
...

ध्यान दें, py36 केवल परीक्षण किया गया।


3

इस दृष्टिकोण ने मेरे लिए काम किया और कुछ समाधानों की तुलना में कम बरबाद किया है:

try:
  from ..components.core import GameLoopEvents
except ValueError:
  from components.core import GameLoopEvents

मूल निर्देशिका मेरे PYTHONPATH में है, और हैं __init__.py मूल निर्देशिका और इस निर्देशिका में फाइलें ।

उपरोक्त ने हमेशा अजगर 2 में काम किया, लेकिन पायथन 3 कभी-कभी एक आयातError या ModuleNotFoundError (बाद वाला अजगर 3.6 में नया और ImportError का एक उपवर्ग) से टकराया, इसलिए निम्न ट्विट मेरे लिए अजगर 2 और 3 दोनों में काम करता है:

try:
  from ..components.core import GameLoopEvents
except ( ValueError, ImportError):
  from components.core import GameLoopEvents


1

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

if __name__ == "__main__":

यह हमेशा सापेक्ष आयात की शिकायत करता है। मैंने उपरोक्त समाधानों को लागू करने की कोशिश की, लेकिन काम करने में विफल रहा, क्योंकि कई नेस्टेड फाइलें थीं, जिनमें से प्रत्येक में कई आयात थे।

यहाँ मैंने क्या किया है। मैंने सिर्फ एक लांचर बनाया, एक बाहरी कार्यक्रम जो आवश्यक तरीकों को आयात करेगा और उन्हें कॉल करेगा। हालांकि, एक महान समाधान नहीं है, यह काम करता है।


0

यहाँ एक तरीका है जो सभी को पेशाब करेगा लेकिन बहुत अच्छी तरह से काम करेगा। चलाए गए परीक्षणों में:

ln -s ../components components

तो बस आप जैसे घटक सामान्य रूप से आयात करेंगे।


0

यह बहुत भ्रामक है, और यदि आप pycharm की तरह आईडीई का उपयोग कर रहे हैं, तो यह थोड़ा और भ्रामक है। मेरे लिए क्या काम किया है: 1. pycharm परियोजना सेटिंग्स बनाओ (यदि आप एक VE या अजगर निर्देशिका से अजगर चला रहे हैं) 2. कोई गलत तरीका नहीं है जिसे आपने परिभाषित किया है। कभी-कभी यह folder1.file1 आयात वर्ग से काम करता है

यदि यह काम नहीं करता है, तो आयात folder1.file1 का उपयोग करें। आपके पर्यावरण चर को सिस्टम में सही ढंग से उल्लेख किया जाना चाहिए या इसे आपके कमांड लाइन तर्क में प्रदान करना चाहिए।


-2

क्योंकि आपके कोड में if __name__ == "__main__"पैकेज के रूप में आयात नहीं किया गया है, आप sys.path.append()समस्या को हल करने के लिए बेहतर उपयोग करेंगे।


मुझे नहीं लगता कि if __name__ == "__main__"आपकी फ़ाइल में आयात करने से संबंधित किसी भी चीज़ से फर्क पड़ता है।
user48956
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.