আপেক্ষিক আমদানিতে শীর্ষ স্তরের প্যাকেজ ত্রুটি ছাড়িয়ে


315

মনে হচ্ছে অজগর 3 এ আপেক্ষিক আমদানি সম্পর্কে এখানে ইতিমধ্যে বেশ কয়েকটি প্রশ্ন রয়েছে তবে তাদের অনেকগুলি পরীক্ষার পরেও আমি এখনও আমার ইস্যুর উত্তর খুঁজে পাইনি। তাই এখানে প্রশ্ন.

আমার নীচে দেখানো একটি প্যাকেজ রয়েছে

package/
   __init__.py
   A/
      __init__.py
      foo.py
   test_A/
      __init__.py
      test.py

এবং আমার টেস্ট.পি-তে একটি লাইন রয়েছে:

from ..A import foo

এখন, আমি ফোল্ডারে আছি package, এবং আমি চালাচ্ছি

python -m test_A.test

আমি বার্তা পেয়েছি

"ValueError: attempted relative import beyond top-level package"

তবে আমি যদি প্যারেন্ট ফোল্ডারে থাকি তবে package, আমি চালাই:

cd ..
python -m package.test_A.test

সবকিছু ঠিক আছে.

এখন আমার প্রশ্নটি হ'ল: যখন আমি ফোল্ডারে থাকি packageএবং আমি test_A.testআমার বোঝার উপর ভিত্তি করে টেস্ট_এ সাব-প্যাকেজের ভিতরে মডিউলটি চালিত করি তবে এটি ..Aকেবলমাত্র একটি মাত্রায় চলে যায়, যা এখনও packageফোল্ডারের মধ্যে রয়েছে কেন এটি বার্তা বলছে beyond top-level package। ঠিক কী কারণে এই ত্রুটি বার্তার কারণ?


49
পোস্টটি আমার "শীর্ষ স্তরের প্যাকেজ ছাড়িয়ে" ত্রুটির ব্যাখ্যা দেয় না
শেল্পার

4
আমার এখানে একটি চিন্তা আছে, সুতরাং টেস্ট_এ.স্টেস্টটি মডিউল হিসাবে চালানোর সময়, '..' টেস্ট_এ এর উপরে চলে যায়, যা ইতিমধ্যে আমদানির পরীক্ষার সর্বোচ্চ স্তর_এস্টেস্ট, আমার মনে হয় প্যাকেজ স্তরটি ডিরেক্টরি স্তর নয়, তবে কতটি আপনি প্যাকেজ আমদানি স্তর।
শেল্পার

2
আমি প্রতিশ্রুতি দিচ্ছি আপনি এই উত্তর stackoverflow.com/a/14132912/8682868 দেখার পরে আপেক্ষিক আমদানি সম্পর্কে সমস্ত কিছু বুঝতে পারবেন ।
pzjzeason

দেখতে ValueError: টপ লেভেল প্যাকেজ পরলোক চেষ্টা আপেক্ষিক আমদানি এই সমস্যা সম্পর্কে বিস্তারিত ব্যাখ্যা জন্য।
নাপুজবা

আপেক্ষিক আমদানি এড়াতে কি উপায় আছে? যেমন- প্যাইডেভি একলাইসে যেভাবে সমস্ত প্যাকেজ <পিডাইভপ্রোজেক্ট / এসসিআর এর মধ্যে দেখেন?
Mushu909

উত্তর:


172

সম্পাদনা: অন্যান্য প্রশ্নের মধ্যে এই প্রশ্নের আরও ভাল / আরও সুসংগত উত্তর রয়েছে:


কেন এটি কাজ করে না? এর কারণ পাইথন কোথা থেকে কোনও প্যাকেজ লোড হয়েছিল তা রেকর্ড করে না। সুতরাং যখন আপনি এটি করেন python -m test_A.test, এটি মূলত কেবল যে জ্ঞানটি test_A.testপ্রকৃতপক্ষে সঞ্চিত হয় তা ত্যাগ করে package(অর্থাত packageপ্যাকেজ হিসাবে বিবেচিত হয় না)। চেষ্টা করার from ..A import fooচেষ্টা করছে তথ্যটি অ্যাক্সেস করার চেষ্টা করছে এর আর কোনও অস্তিত্ব নেই (অর্থাত্ লোড হওয়া জায়গার ভাইবোন ডিরেক্টরি)। এটি from ..os import pathকোনও ফাইলের মধ্যে অনুমতি দেওয়ার মতোই ধারণা math। এটি খারাপ হবে কারণ আপনি প্যাকেজগুলি পৃথক করতে চান। তাদের যদি অন্য কোনও প্যাকেজ থেকে কিছু ব্যবহার করার প্রয়োজন হয় তবে তাদের সাথে তাদের বিশ্বব্যাপী উল্লেখ করা উচিত from os import pathএবং পাইথনটি যেখানে রয়েছে $PATHএবং কোথায় রয়েছে তা কাজ করতে দেওয়া উচিত $PYTHONPATH

আপনি যখন ব্যবহার করেন python -m package.test_A.test, তারপরে ব্যবহার করা from ..A import fooঠিক ঠিক হয়ে যায় কারণ এটি কী রয়েছে তার উপর নজর রাখে packageএবং আপনি কেবল বোঝা জায়গার একটি শিশু ডিরেক্টরিতে অ্যাক্সেস করছেন।

পাইথন বর্তমান ওয়ার্কিং ডিরেক্টরিটিকে প্যাকেজ হিসাবে বিবেচনা করে না কেন? কোন সত্য নেই , তবে গোগ এটি কার্যকর হবে।


2
আমি আমার প্রশ্নের উত্তরটি সম্পাদিত করেছি যে একই প্রশ্নের সাথে একটি প্রশ্নের উত্তম উত্তরের জন্য। এখানে কেবল কাজের সুযোগ রয়েছে। কেবলমাত্র আমি যা কাজটি দেখেছি তা হল ওপি কী করেছে যা -mপতাকা ব্যবহার করে এবং উপরের ডিরেক্টরি থেকে চালিত হয়।
মাল্টিহান্টার

1
এটি লক্ষ করা উচিত যে এই উত্তরটি , মাল্টিহান্টার দ্বারা প্রদত্ত লিঙ্কটি থেকে, sys.pathহ্যাক জড়িত নয় , তবে সেটআপটুলগুলির ব্যবহার , যা আমার মতে আরও আকর্ষণীয়।
অ্যাঞ্জেলো কার্ডেলিচিও

157
import sys
sys.path.append("..") # Adds higher directory to python modules path.

এটা চেষ্টা কর. আমার জন্য কাজ করেছেন।


10
উম্মে ... এই কাজটি কতটা ওয়াডল? প্রতি একক টেস্ট ফাইলের এই থাকবে?
জর্জ মাউয়ার

এখানে সমস্যা যদি, যেমন, হয় A/bar.pyবিদ্যমান এবং এ foo.pyআপনাকে যা করতে from .bar import X
ব্যবহারকারী 1834164

9
Sys.path.append ("..") যোগ করার পরে আমাকে "থেকে ..এ আমদানি ..." থেকে অপসারণ করতে হয়েছিল
জেক ওপজে

2
যদি স্ক্রিপ্টটি ডিরেক্টরিটি বাইরে থেকে কার্যকর করা হয় তবে এটি কার্যকর হবে না। পরিবর্তে, আপনাকে উল্লিখিত স্ক্রিপ্টের নিখুঁত পথ নির্দিষ্ট করতে এই উত্তরটি সাময়িক করতে হবে
মানাভালান গাজাপাতি

এটি সেরা, কমপক্ষে জটিল বিকল্প
অ্যালেক্স আর

43

অনুমান:
আপনি যদি packageডিরেক্টরিতে থাকেন Aএবং test_Aপৃথক প্যাকেজও হন।

উপসংহার:
..Aআমদানি কেবল প্যাকেজের মধ্যেই অনুমোদিত।

আরও নোট:
কেবল প্যাকেজগুলির মধ্যে আপেক্ষিক আমদানি উপলভ্য দরকারী যদি আপনি বাধ্য করতে চান যে প্যাকেজগুলি যে কোনও পথে অবস্থিত হতে পারে sys.path

সম্পাদনা করুন:

আমিই কি একাই মনে করি যে এই পাগল !? বর্তমান বিশ্বে বর্তমান ওয়ার্কিং ডিরেক্টরিটিকে প্যাকেজ হিসাবে বিবেচনা করা হয় না কেন? - মাল্টিহান্টার

বর্তমান ওয়ার্কিং ডিরেক্টরিটি সাধারণত sys.path এ থাকে। সুতরাং, সমস্ত ফাইলগুলি আমদানিযোগ্য। এটি পাইথন 2 সাল থেকে প্যাকেজগুলির অস্তিত্বের পরে উপস্থিত না। চলমান ডিরেক্টরিটিকে একটি প্যাকেজ তৈরি করার ফলে "আমদানি .এ" এবং "আমদানি এ" হিসাবে মডিউলগুলি আমদানির অনুমতি দেয় যা তখন দুটি পৃথক মডিউল হবে। হতে পারে এটি বিবেচনা করার মতো একটি অসঙ্গতি।


85
আমিই কি একাই মনে করি যে এই পাগল !? বিশ্বে কেন চলমান ডিরেক্টরিটিকে প্যাকেজ হিসাবে বিবেচনা করা হয় না?
মাল্টিহান্টার

13
কেবল সেই পাগলই নয়, এটি অপ্রয়োজনীয় ... সুতরাং আপনি কীভাবে পরীক্ষা চালাবেন? স্পষ্টতই ওপি জিজ্ঞাসা করছে যে জিনিসটি এবং কেন আমি নিশ্চিত যে এখানেও অনেক লোক রয়েছেন।
জর্জ মাউয়ার

চলমান ডিরেক্টরিটি সাধারণত sys.path এ থাকে। সুতরাং, সমস্ত ফাইলগুলি আমদানিযোগ্য। এটি পাইথন 2 সাল থেকে প্যাকেজগুলির অস্তিত্বের পরে উপস্থিত না। - সম্পাদিত উত্তর
ব্যবহারকারী

আমি অসঙ্গতি অনুসরণ করি না। এর আচরণটি python -m package.test_A.testযা যা চাইছিল তা করে বলে মনে হয় এবং আমার যুক্তিটি হ'ল এটি ডিফল্ট হওয়া উচিত। তাহলে, আপনি কি আমাকে এই অসঙ্গতির উদাহরণ দিতে পারেন?
মাল্টিহান্টার

আমি আসলে ভাবছি, এর জন্য কি কোনও বৈশিষ্ট্য অনুরোধ রয়েছে? এটা আসলে উন্মাদ। সি / সি ++ শৈলী #includeখুব দরকারী হবে!
নিকোলাস হামফ্রে

29

এইগুলির কোনও সমাধান আমার জন্য 3.6-তে ফোল্ডারের কাঠামোর মতো কাজ করে নি:

package1/
    subpackage1/
        module1.py
package2/
    subpackage2/
        module2.py

আমার লক্ষ্যটি ছিল মডিউল 1 থেকে মডিউল 2 এ আমদানি করা। অবশেষে আমার পক্ষে যা কাজ করেছে তা ছিল অদ্ভুতভাবে যথেষ্ট:

import sys
sys.path.append(".")

এখন পর্যন্ত উল্লিখিত দ্বি-বিন্দু সমাধানগুলির বিপরীতে একক বিন্দুকে নোট করুন।


সম্পাদনা করুন: নিম্নলিখিতটি আমার পক্ষে এটি পরিষ্কার করতে সহায়তা করেছে:

import os
print (os.getcwd())

আমার ক্ষেত্রে, ওয়ার্কিং ডিরেক্টরিটি প্রকল্পের মূল ছিল (অপ্রত্যাশিতভাবে)।


2
এটি স্থানীয়ভাবে কাজ করছে কিন্তু aws ec2 উদাহরণে কাজ করছে না, এর কোনও অর্থ আছে?
thebeancounter

এটি আমার পক্ষেও কাজ করেছিল - আমার ক্ষেত্রে কার্যনির্বাহী ডিরেক্টরি একইভাবে প্রকল্পের মূল ছিল। আমি একটি প্রোগ্রামিং সম্পাদক (টেক্সটমেট)
জেরেমিডগ্লাস

টুইটার আমার ম্যাকটিতে স্থানীয়ভাবে কাজ করে তবে ইসি 2-তে কাজ করে না, তখন আমি বুঝতে পারি যে আমি ইসি 2 তে একটি সাবডিরে কমান্ডটি চালাচ্ছি এবং এটি স্থানীয়ভাবে রুটে চালাচ্ছি। একবার আমি এটি ইস্ট 2 থেকে মূল থেকে চালিত করি এটি কাজ করে।
লোগান ইয়াং

এটি আমার পক্ষে অনেক প্রশংসিত কাজ করেছে। এই
সিস্টেমে

sys.path.append(".")আপনি এটিকে পৈতৃক ডিরেক্টরিতে ডাকছেন বলে কাজ করেছেন, আপনি যে .পাইথন কমান্ডটি চালিত করেন সেই ডিরেক্টরিটি সর্বদা প্রতিনিধিত্ব করুন
কেভিনঝো

13

from package.A import foo

আমি মনে করি এটি এর চেয়ে পরিষ্কার

import sys
sys.path.append("..")

4
এটি নিশ্চিতভাবে আরও পঠনযোগ্য তবে এখনও প্রয়োজন sys.path.append("..")। অজগর 3.6
এমএফএ

পুরানো উত্তর হিসাবে একই
nrofis

12

সর্বাধিক জনপ্রিয় উত্তর হিসাবে বোঝা যায়, মূলত এটি কারণ আপনার PYTHONPATHবা আপনার প্যাকেজের আপনার পথ নয় তবে sys.pathঅন্তর্ভুক্ত .। এবং আপেক্ষিক আমদানি আপনার বর্তমান কার্যনির্বাহী ডিরেক্টরিটির সাথে সম্পর্কিত, যেখানে ফাইলটি আমদানি হয় তা নয়; অদ্ভুত।

আপনি প্রথমে আপনার আপেক্ষিক আমদানিকে নিখুঁতভাবে পরিবর্তন করে এবং তারপর এটি দিয়ে শুরু করে এটি ঠিক করতে পারেন:

PYTHONPATH=/path/to/package python -m test_A.test

বা অজগর পথটিকে বাধ্য করা হয় যখন এইভাবে বলা হয়, কারণ:

সঙ্গে python -m test_A.testআপনি নির্বাহ করছেন test_A/test.pyসঙ্গে __name__ == '__main__'এবং__file__ == '/absolute/path/to/test_A/test.py'

এর অর্থ হল যে test.pyআপনি নিজের নিখুঁত importঅর্ধ-সুরক্ষিত মূল কেস অবস্থায় ব্যবহার করতে পারেন এবং কিছু এককালীন পাইথন পাথ হেরফেরও করতে পারেন:

from os import path

def main():

if __name__ == '__main__':
    import sys
    sys.path.append(path.join(path.dirname(__file__), '..'))
    from A import foo

    exit(main())

বাহ কি অজগর দ্বারা একটি ভয়ানক নকশা। তথ্যের জন্য thx
javadba

8

সম্পাদনা: 2020-05-08: মনে হচ্ছে যে ওয়েবসাইটটি উদ্ধৃত করা হয়েছে সে পরামর্শটি যে ব্যক্তি লিখেছেন তার দ্বারা আর নিয়ন্ত্রণ করা হবে না, তাই আমি সাইটের লিঙ্কটি সরিয়ে দিচ্ছি। আমাকে বাক্সএক্স জানানোর জন্য ধন্যবাদ


ইতিমধ্যে সরবরাহিত দুর্দান্ত উত্তরগুলির পরে যদি কেউ এখনও কিছুটা লড়াই করে চলেছে তবে আমি একটি ওয়েবসাইটে পরামর্শ পেয়েছি যা আর উপলভ্য নয়।

আমি উল্লেখ করা সাইটটি থেকে প্রয়োজনীয় উক্তি:

"প্রোগ্রামটিমেটিকভাবে এটি একইভাবে নির্দিষ্ট করা যেতে পারে:

আমদানি sys

sys.path.append ( '..')

অবশ্যই অন্যান্য আমদানির বিবৃতি দেওয়ার আগে অবশ্যই উপরের কোডটি লিখতে হবে

এটি বেশ সুস্পষ্ট যে সত্যটি পরে এটি চিন্তা করা উচিত after আমি আমার পরীক্ষাগুলিতে sys.path.append ('..') ব্যবহার করার চেষ্টা করছিলাম, তবে ওপি পোস্ট করা ইস্যুতে ছুটে এসেছি। আমার অন্যান্য আমদানির আগে আমদানি এবং সিস.পাথ সংজ্ঞা যোগ করে আমি সমস্যাটি সমাধান করতে সক্ষম হয়েছি।


আপনার পোস্ট করা লিঙ্কটি মারা গেছে।
বাক্সেক্স

আমাকে জানতে দেওয়ার জন্য ধন্যবাদ। দেখে মনে হচ্ছে ডোমেন নামটি আর একই ব্যক্তি দ্বারা নিয়ন্ত্রিত নেই। আমি লিঙ্কটি সরিয়েছি।
মিয়ারপো

5

যদি আপনার __init__.pyএকটি উচ্চতর ফোল্ডারে থাকে তবে আপনি import file/path as aliasসেই আরম্ভের ফাইলের মতোই আমদানিটি শুরু করতে পারেন । তারপরে আপনি এটি নিম্ন স্ক্রিপ্টগুলিতে ব্যবহার করতে পারেন:

import alias

0

আমার বিনীত মতে, আমি এই প্রশ্নটি এইভাবে বুঝতে পারি:

[CASE 1] আপনি যখন পরম-আমদানি শুরু করেন

python -m test_A.test

অথবা

import test_A.test

অথবা

from test_A import test

আপনি আসলে সেটিং করছি আমদানি-নোঙ্গর করা test_A, অন্যান্য শব্দ, টপ লেভেল প্যাকেজ test_A। সুতরাং, যখন আমাদের টেস্ট.পি রয়েছে from ..A import xxx, আপনি অ্যাঙ্কর থেকে পালাচ্ছেন, এবং পাইথন এটির অনুমতি দেয় না।

[CASE 2] আপনি যখন করবেন

python -m package.test_A.test

অথবা

from package.test_A import test

আপনার নোঙ্গর হয়ে যায় package, তাই package/test_A/test.pyকরছেfrom ..A import xxx নোঙ্গর (এখনও ভিতরে অব্যাহতি না packageফোল্ডারের), এবং পাইথন সুখে এই স্বীকার করে।

সংক্ষেপে:

  • পরম-আমদানি বর্তমান অ্যাঙ্কর পরিবর্তন করে (= শীর্ষ-স্তরের প্যাকেজ কী তা পুনরায় সংজ্ঞা দেয়);
  • আপেক্ষিক-আমদানি অ্যাঙ্কর পরিবর্তন করে না তবে এটিতে সীমাবদ্ধ।

তদ্ব্যতীত, আমরা পূর্ণ-যোগ্যতাসম্পন্ন মডিউল নাম ব্যবহার করতে পারি এই সমস্যাটি পরিদর্শন (এফকিউএমএন) ।

প্রতিটি ক্ষেত্রে FQMN পরীক্ষা করুন:

  • [CASE2] test.__name__=package.test_A.test
  • [CASE1] test.__name__=test_A.test

সুতরাং, CASE2 এর জন্য, from .. import xxxএফকিউএমএন = দিয়ে একটি নতুন মডিউল তৈরি হবেpackage.xxx , , যা গ্রহণযোগ্য।

CASE1 এর জন্য, এর ..মধ্য থেকে প্রারম্ভিক নোড (অ্যাঙ্কর) থেকেfrom .. import xxx ঝাঁপিয়ে পড়বে , এবং পাইথন দ্বারা এটি অনুমোদিত নয়।test_A


2
এটি যতটা প্রয়োজন তার চেয়ে জটিল। পাইথনের জেনের পক্ষে অনেক কিছুই।
এটিলিওএ

0

পাইথন ২.x তে নিশ্চিত নয় তবে পাইথন ৩.6-তে, ধরে নিই যে আপনি পুরো স্যুটটি চালানোর চেষ্টা করছেন, আপনাকে কেবল ব্যবহার করতে হবে -t

-t, - টপ-স্তর-ডিরেক্টরি ডিরেক্টরি প্রকল্পের শীর্ষ স্তরের ডিরেক্টরি (ডিরেক্টরি শুরু করতে ডিফল্ট)

সুতরাং, মত একটি কাঠামো উপর

project_root
  |
  |----- my_module
  |          \
  |           \_____ my_class.py
  |
  \ tests
      \___ test_my_func.py

একটি উদাহরণস্বরূপ ব্যবহার করতে পারে:

python3 unittest discover -s /full_path/project_root/tests -t /full_path/project_root/

এবং এখনও my_module.my_classবড় নাটক ছাড়া আমদানি করুন ।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.