Setuptools setup.py ফাইলে ইনস্টল_কিওয়ার্স কোয়ার্গের জন্য রেফারেন্স প্রয়োজনীয়তা.টিএসটিএসটি


279

আমার একটি requirements.txtফাইল রয়েছে যা আমি ট্র্যাভিস-সিআইয়ের সাথে ব্যবহার করছি। এটি উভয় requirements.txtএবং মধ্যে প্রয়োজনীয়তা সদৃশ বোকামি মনে হয়setup.py তাই আমি install_requiresকোয়ার্গে একটি ফাইল হ্যান্ডেলটি পাস করার আশা করছিলাম setuptools.setup

এটা কি সম্ভব? যদি তা হয় তবে আমার কীভাবে এটি করা উচিত?

আমার requirements.txtফাইলটি এখানে :

guessit>=0.5.2
tvdb_api>=1.8.2
hachoir-metadata>=1.3.3
hachoir-core>=1.3.3
hachoir-parser>=1.3.4

4
install_requiresপ্যাকেজটি কাজ করতে প্রয়োজনীয় এবং প্যাকেজের বিকাশকারী দ্বারা ব্যবহৃত প্যাকেজের উপর নির্ভরতা ঘোষণা করতে ব্যবহৃত হয়, যখন requirements.txtপরিবেশের ইনস্টলমেন্ট স্বয়ংক্রিয় করতে ব্যবহৃত হয়, যা অতিরিক্ত সফ্টওয়্যার ইনস্টল করতে এবং সংস্করণটি পিন করার অনুমতি দেয় এবং সিসাদমিনগুলি ব্যবহার করে ব্যবহৃত হয় প্যাকেজ। তাদের ভূমিকা এবং লক্ষ্য দর্শকদের উল্লেখযোগ্যভাবে পার্থক্য রয়েছে, সুতরাং ওপি শুভেচ্ছার মতো তাদের একত্রিত করার চেষ্টা করা একটি আসল নকশা ভুল ho
জার্ট

7
আমার 2 সেন্ট। আপনার সেটআপ.পিতে প্রয়োজনীয়তা.এসটিএসটি ব্যবহার করবেন না। উদ্দেশ্যগুলি আলাদা, ared caremad.io/2013/07/setup-vs-requirement
ফিলিপ ওম্ব্রেডনে

3
আমি অনেক জটিল উত্তর দেখতে পাচ্ছি। পুরানো পুরানো সমস্যা [line.strip() for line in open("requirements.txt").readlines()]কি?
ফিলিপ এসএস স্নাইডার

এটি করার পরামর্শ দেওয়া হয় না। কিন্তু যদি সত্যিই তারপর প্রয়োজন এটা সহজবোধ্য হল: setuptools নিজেই ইতিমধ্যে সবকিছু প্রয়োজনীয় হয়েছেpkg_resources.parse_requirements()
sinoroc

উত্তর:


246

আপনি এটিকে চারপাশে ফ্লিপ করতে পারেন এবং এর মধ্যে নির্ভরতাগুলি তালিকাভুক্ত করতে setup.pyপারেন .এবং requirements.txtপরিবর্তে একটি একক অক্ষর - একটি বিন্দু থাকতে পারেন ।


বিকল্পভাবে, এমনকি যদি পরামর্শ না দেওয়া হয়, তবুও requirements.txtনিম্নলিখিত হ্যাকের সাথে পরীক্ষিত pip 9.0.1) ফাইলটি (এটি যদি ইউআরএল দ্বারা কোনও বাহ্যিক প্রয়োজনীয়তা উল্লেখ না করে) পার্স করা সম্ভব :

install_reqs = parse_requirements('requirements.txt', session='hack')

এটি যদিও পরিবেশের চিহ্নিতকারীগুলিকে ফিল্টার করে না ।


পাইপের পুরানো সংস্করণগুলিতে, 6.0 এরও বেশি পুরানো সংস্করণগুলিতে একটি সর্বজনীন এপিআই রয়েছে যা এটি অর্জন করতে ব্যবহার করা যেতে পারে। একটি প্রয়োজনীয় ফাইলটিতে মন্তব্য থাকতে পারে ( #) এবং এতে কিছু অন্যান্য ফাইল ( --requirementবা -r) অন্তর্ভুক্ত থাকতে পারে । সুতরাং, আপনি যদি সত্যিই কোনটিকে বিশ্লেষণ করতে চান তবে আপনি requirements.txtপাইপ পার্সারটি ব্যবহার করতে পারেন:

from pip.req import parse_requirements

# parse_requirements() returns generator of pip.req.InstallRequirement objects
install_reqs = parse_requirements(<requirements_path>)

# reqs is a list of requirement
# e.g. ['django==1.5.1', 'mezzanine==1.4.6']
reqs = [str(ir.req) for ir in install_reqs]

setup(
    ...
    install_requires=reqs
)

26
যদি ব্যবহারকারী পিপ ইনস্টল না করে থাকে? কা-গম্ভীর গর্জন?
গ্রিঙ্গো সুভেভ

82
@ গ্রিংসুয়াভ যদি ব্যবহারকারীর পাইপ ইনস্টল না থাকে তবে তার প্রথমে এটি ইনস্টল করা দরকার।
গেটল্লি

7
নন-পিপিআই প্যাকেজগুলিকে নির্দেশ করে যে কোনও -e বা -f ("সম্পাদনাযোগ্য" গিট রেপো) লাইন রয়েছে সে ক্ষেত্রে আপনাকেও আপনার প্রয়োজনীয় ফাইলগুলিতে ইউআরএল সরবরাহ করতে হবে। এটি ব্যবহার করুন:setup(..., dependency_links=[str(req_line.url) for req_line in parse_requirements(<requirements_path>)], ...)
hobs

91
আপনি সত্যিই এটি করতে চান না। পাইপ রক্ষণাবেক্ষণকারী পাইপ হিসাবে কথা বলা এ জাতীয় এপিআই হিসাবে বলা মোটেই সমর্থন করে না। আসলে পাইপ 1.6 (এই সময়ে পরবর্তী সংস্করণ) এই ফাংশনটিকে সরায়।
ডোনাল্ড স্টাফ্ট

26
এটির আর হওয়া উচিত থাকলে এটি আর গ্রহণযোগ্য উত্তর হওয়া উচিত নয়। একেবারে নষ্ট হয়ে গেছে। এমনকি যখন এটি কাজ করেছিল, এটি অত্যন্ত অপ্রয়োজনীয়। যেহেতু অনুপস্থিতিতে pipনির্ভরশীলতাগুলি পার্সিংয়ের ক্ষেত্রে খেলাপি হয়, তাই নীচে টোবু দ্বারা চূড়ান্তভাবে উল্লেখ করা সহজ উত্তর হ'ল সমস্ত নির্ভরতা তালিকাভুক্ত এবং অপসারণ করা উভয় প্রয়োজন অ্যাপ্লিকেশনের জন্য, কেবলমাত্র নির্ভরতা তালিকা কমাতে নিছক থেকে অক্ষর। সম্পন্ন. setup.pyrequirements.txtsetup.pyrequirements.txtrequirements.txt.
সিসিল কারি

194

এটির চেহারায়, এটি মনে হয় requirements.txtএবং setup.pyনিরীহ সদৃশ, তবে এটি বোঝা গুরুত্বপূর্ণ যে ফর্মটি সাদৃশ্য থাকা সত্ত্বেও, উদ্দেশ্যযুক্ত ফাংশনটি খুব আলাদা।

প্যাকেজ লেখকের লক্ষ্য, নির্ভরতা নির্দিষ্ট করার সময়, "এই প্যাকেজটি কাজ করার জন্য আপনি যেখানেই এই প্যাকেজটি ইনস্টল করবেন না কেন এটি আপনার প্রয়োজন অন্যান্য প্যাকেজগুলি" "

বিপরীতে, মোতায়েন লেখক (যা ভিন্ন সময়ে একই ব্যক্তি হতে পারে) এর একটি আলাদা কাজ রয়েছে, তারা বলে যে "এখানে আমরা যে প্যাকেজগুলি একত্রিত করেছি এবং পরীক্ষা করেছি এবং এখনই আমাকে ইনস্টল করতে হবে" তার তালিকা এখানে রয়েছে।

প্যাকেজ লেখক বিবিধ দৃশ্যের জন্য লিখেছেন, কারণ তারা তাদের কাজটি এমনভাবে ব্যবহার করছেন যাতে তারা জানেন না এবং তাদের প্যাকেজের পাশাপাশি কী কী প্যাকেজ ইনস্টল করা হবে তা জানার উপায় নেই। একজন ভাল প্রতিবেশী হতে এবং অন্যান্য প্যাকেজগুলির সাথে নির্ভরতা সংস্করণগুলির দ্বন্দ্ব এড়ানোর জন্য তাদের সম্ভবত নির্ভরযোগ্য সংস্করণগুলির বিস্তৃত বিস্তৃতি নির্দিষ্ট করা দরকার। এই কি install_requiresমধ্যে setup.pyআছে।

স্থাপনার লেখক একটি খুব পৃথক, খুব নির্দিষ্ট লক্ষের জন্য লিখেছেন: একটি ইনস্টলড অ্যাপ্লিকেশন বা পরিষেবার একক উদাহরণ, একটি নির্দিষ্ট কম্পিউটারে ইনস্টল করা। কোনও স্থাপনা সঠিকভাবে নিয়ন্ত্রণ করতে এবং সঠিক প্যাকেজগুলি পরীক্ষা করা এবং স্থাপন করা হয়েছে তা নিশ্চিত করার জন্য, নিয়োগের লেখককে অবশ্যই নির্ভরযোগ্যতা এবং নির্ভরতার নির্ভরতা সহ ইনস্টল করার জন্য প্রতিটি প্যাকেজের সঠিক সংস্করণ এবং উত্স-অবস্থান নির্দিষ্ট করতে হবে। এই অনুমানের সাহায্যে, একটি স্থাপনা পুনরাবৃত্তভাবে বেশ কয়েকটি মেশিনে প্রয়োগ করা যেতে পারে, বা একটি পরীক্ষা মেশিনে পরীক্ষা করা যেতে পারে, এবং প্রতিস্থাপন লেখক প্রতিবার একই প্যাকেজ মোতায়েন করা যায় এমন বিষয়ে আস্থা রাখতে পারেন। এটি কি requirements.txtকরে।

সুতরাং আপনি এটি দেখতে পাচ্ছেন, যদিও তারা উভয়ই প্যাকেজ এবং সংস্করণগুলির একটি বৃহত তালিকার মতো দেখায়, এই দুটি জিনিসের খুব আলাদা কাজ রয়েছে। এবং এটি মিশ্রিত করা এবং এটি ভুল হওয়া অবশ্যই সহজ! তবে এটি সম্পর্কে চিন্তা করার সঠিক উপায়টি হ'ল requirements.txtসমস্ত setup.pyপ্যাকেজ ফাইলগুলিতে প্রয়োজনীয়তার দ্বারা উত্থিত "প্রশ্নের" একটি "উত্তর" । হাত দিয়ে লেখার পরিবর্তে এটি প্রায়শই setup.pyপছন্দসই প্যাকেজগুলির সেটগুলিতে সমস্ত ফাইলগুলি দেখার জন্য পিপ বলার মাধ্যমে উত্পন্ন হয় , প্যাকেজের এমন একটি সেট সন্ধান করুন যা এটি মনে করে যে সমস্ত প্রয়োজনীয়তা ফিট করে এবং তারপরে, ইনস্টল হওয়ার পরে, "হিমশীতল "পাঠ্য ফাইলে প্যাকেজগুলির তালিকা ( pip freezeনামটি এখান থেকে আসে)।

সুতরাং গ্রহণযোগ্য:

  • setup.pyস্বল্পতম সম্ভাব্য নির্ভরতা সংস্করণগুলি ঘোষণা করা উচিত যা এখনও কার্যক্ষম। কোনও নির্দিষ্ট প্যাকেজ কী দিয়ে কাজ করতে পারে তা বলা তার কাজ।
  • requirements.txtএকটি স্থাপনা ম্যানিফেস্ট যা পুরো ইনস্টলেশন কাজটি সংজ্ঞায়িত করে এবং কোনও একটি প্যাকেজের সাথে জড়িত বলে মনে করা উচিত নয়। এর কাজটি মোতায়েনের কাজ করার জন্য প্রয়োজনীয় সমস্ত প্যাকেজগুলির একটি সম্পূর্ণ তালিকা ঘোষণা করা।
  • যেহেতু এই দুটি জিনিসের বিদ্যমান উপাদানগুলির জন্য পৃথক পৃথক সামগ্রী এবং কারণ রয়েছে, কেবল একটিতে অন্যটিতে অনুলিপি করা সম্ভব নয়।

তথ্যসূত্র:


10
এটি সর্বোত্তম ব্যাখ্যার মধ্যে একটি যা আমাকে সেই গণ্ডগোলের মধ্যে কিছু অর্ডার দেয় যাকে বলে প্যাকেজ ইনস্টলেশন! :)
কাউনাভি

6
এটি এখনও আমার কাছে পরিষ্কার নয় যে কেন কোনও বিকাশকারী requirements.txtপ্যাকেজটির উত্সের সাথে একটি সংস্করণ-নিয়ন্ত্রিত রাখবেন যাতে ইনস্টলেশন বা পরীক্ষার জন্য কংক্রিট / হিমায়িত প্রয়োজনীয়তা রয়েছে। অবশ্যই setup.pyপ্রকল্পের মধ্যেই এই উদ্দেশ্যে ব্যবহার করা যেতে পারে? আমি প্রকল্পটি পরিচালনার জন্য ব্যবহৃত সরঞ্জামগুলির জন্য (যেমন রিফ্যাক্টরিং, রিলিজ করা ইত্যাদি) কেবল এই জাতীয় ফাইল ব্যবহার করার কল্পনা করতে পারি ।
স্যাম ব্রাইটম্যান

2
@ স্যামব্রেটম্যান আমি সম্পূর্ণরূপে একমত, আমার মনে হয় না যে লাইব্রেরি প্যাকেজ বা অ্যাপ্লিকেশন প্যাকেজগুলির প্রয়োজনীয়তাগুলি করা উচিত t কোড সহ সংগ্রহস্থলের কাছে টেক্সট ফাইল। আমি মনে করি এটি বিল্ড টেস্টিংয়ের সময় উত্পন্ন একটি শৈল্পিক হওয়া উচিত, এবং তারপরে একটি বিল্ড ম্যানিফেস্ট ডকুমেন্ট করার জন্য এবং শেষ পর্যন্ত একটি স্থাপনা শিল্পকলা তৈরির জন্য ব্যবহৃত হত।
জোনাথন হ্যানসন

6
সুতরাং আপনি বলছেন requirements.txtযে বিশ্বের রাষ্ট্রের জন্য আরও একটি ডকুমেন্টেশন যা একটি প্রদত্ত বিল্ড উত্পাদন করে, যদিও এটি সাধারণত বিল্ড প্রক্রিয়াতে নিজেই ব্যবহৃত হয় না? এটা বোধগম্য. যাইহোক, দেখে মনে হচ্ছে বেশ কয়েকটি সিস্টেমগুলি সদৃশটির উপর নির্ভর করে: ট্র্যাভিস আপনার ভার্চুয়ালেনভে কিছু ডিফল্ট (পুরানো) প্যাকেজ ইনস্টল করে এবং ব্যবহার করতে বলে requirements.txt। আমি যদি সর্বশেষতম ব্যবহারে নির্ভরতাগুলি কীভাবে নিশ্চিত করা যায় তা জিজ্ঞাসা করি setup.py, লোকেরা জোর দেয় যে আমার ব্যবহার করা উচিত requirements.txt
স্যাম ব্রাইটম্যান

2
আপনি এর যে কোনও একটি থেকে বেরিয়ে আসতে পারেন সর্বোত্তম পরামর্শ হ'ল আপনার পক্ষে কাজ করে এমন একটি মডেল সন্ধান করা, এটি ভালভাবে নথিভুক্ত করা, এবং নিশ্চিত হয়ে নিন যে আপনি যার সাথে কাজ করেছেন সবাই এটি বুঝতে পেরেছেন। আপনি কেন প্রতিটি বিট করছেন এবং এটি আপনার ব্যবহারের ক্ষেত্রে সত্যিকার অর্থে আসে কিনা তা ভেবে দেখুন। আর পাইথনে বিল্ডিং, প্যাকেজিং এবং প্রকাশের বর্তমান অবস্থা সম্পর্কে আপনি যতটা পারেন ততটা পঠিত থাকার চেষ্টা করুন, যদি পরিস্থিতি আরও ভাল হয়ে যায়। তবে দম ধরবেন না।
জোনাথন হ্যানসন

89

এটি কোনও ফাইল হ্যান্ডেল নিতে পারে না। install_requiresযুক্তিটি কেবল একটি স্ট্রিং বা স্ট্রিংয়ের তালিকা হতে পারে

আপনি অবশ্যই সেটআপ স্ক্রিপ্টে আপনার ফাইলটি পড়তে এবং স্ট্রিংয়ের তালিকা হিসাবে এটি পাস করতে পারেন install_requires

import os
from setuptools import setup

with open('requirements.txt') as f:
    required = f.read().splitlines()

setup(...
install_requires=required,
...)

5
যদিও এটি কার্যকর তা প্রয়োজনীয়তার বিবরণীটিকে আবশ্যকীয় থেকে বাধ্যতামূলক হিসাবে পরিবর্তন করে। এটি আপনার প্রয়োজনীয়তাগুলি কী তা নির্ধারণ করতে কিছু সরঞ্জামকে অসম্ভব করে তোলে। উদাহরণস্বরূপ, পাইচার্ম নির্দিষ্ট সমস্ত প্রয়োজনীয়তার স্বয়ংক্রিয় ইনস্টলেশন সরবরাহ করে install_requires। তবে, আপনি ঘোষণামূলক সিনট্যাক্স ব্যবহার না করলে এটি কাজ করে না।
পাইওটর ডব্রোগস্ট

55
@ পাইওটারডোব্রোগস্ট সম্ভবত পাইচর্ম বিকাশকারীদের তখন তাদের প্রোগ্রামটি ঠিক করা উচিত। setup.pyএমন একটি প্রোগ্রাম যা চালিত হওয়া উচিত, কোনও ডেটা ফাইল নয় যা পার্স করা উচিত। এই উত্তরটি আরও খারাপ করে না।
ফ্রেড্রিক ব্রেনান

5
আমি কেবল সম্ভাব্য সমস্যাগুলি দেখিয়ে দিচ্ছি; এই উত্তর পুরোপুরি ঠিক আছে। এটি কেবল পাইচার্ম নয় যা কোডের পিছনে তথ্য "লুকানো" থাকতে সমস্যা করে। এটি সর্বজনীন সমস্যা এবং সুতরাং পাইথন প্যাকেজিংয়ে মেটাডেটার ঘোষণামূলক স্পেসিফিকেশনের দিকে সাধারণ পদক্ষেপ রয়েছে।
পাইওটর ডব্রোগোস্ট

32
যতদিন আপনি করা যেমন কাজ করে জরিমানা include requirements.txtআপনার মধ্যে MANIFEST.inঅথবা আপনি একটি উৎস বন্টন থেকে আপনার লাইব্রেরিতে ইনস্টল করতে পারবেন না।
পঙ্করত

4
আমি জানি এটি একটি পুরানো প্রশ্ন, তবে আপনি কমপক্ষে আজকাল পছন্দসমূহ-> সরঞ্জাম-> পাইথন ইন্টিগ্রেটেড
টুলস-

64

প্রয়োজনীয় ফাইলগুলি একটি প্রসারিত পাইপ ফর্ম্যাট ব্যবহার করে, এটি কেবল তখনই কার্যকর যখন আপনার নিজের setup.pyদৃ stronger়তর বাঁধাগুলির পরিপূরক প্রয়োজন , উদাহরণস্বরূপ সঠিক ইউআরএল নির্দিষ্ট করে যে কিছু নির্ভরশীলতা অবশ্যই আসবে, বা pip freezeপুরো প্যাকেজটি জেনারেট-ওয়ার্কিংয়ে সেট করে রাখবে output সংস্করণ। আপনার যদি অতিরিক্ত বাধা প্রয়োজন না হয় তবে কেবল একটি ব্যবহার করুন setup.py। আপনার যদি মনে হয় আপনার requirements.txtযেকোন উপায়েই শিপিং করা দরকার তবে আপনি এটিকে একটি একক লাইন বানাতে পারেন:

.

এটি বৈধ হবে এবং এর বিষয়বস্তুগুলিকে হুবহু উল্লেখ করবে setup.py একই ডিরেক্টরিতে ।


9
তবে এক্ষেত্রে এটি আমার অ্যাপটিও ইনস্টল করার চেষ্টা করবে। আমার যদি এটির প্রয়োজন না হয় এবং কেবল ইনস্টল-রিকুইয়ারগুলি ইনস্টল করতে চান তবে কী হবে?
ffeast

2
@Feast যা জিজ্ঞাসা করছে তার বিশদটি জানাতে, যদি প্রয়োজনীয়তাগুলি কেবল সেটআপ.পিপি-তে থাকে pip install -r requirements.txt তবে প্যাকেজটি ইনস্টল না করে প্রয়োজনীয়তাগুলির (সমতুল্য ) ইনস্টল করার কোনও উপায় আছে কি?
haridsv

1
@Feast @haridsv -e .যথেষ্ট হবে। এই পৃষ্ঠাটি দেখুন: caremad.io/posts/2013/07/setup-vs-requirement
ডেক্সহান্টার

4
@ ডেক্সডি.হান্টার এটি এখনও অ্যাপটি ইনস্টল করার চেষ্টা করে। এটি আমরা যা চাই তা নয়
ffeast

38

এই প্রশ্নের সঠিক উত্তর না পেয়েও আমি ডোনাল্ড স্টাফ্টের ব্লগ পোস্টটি https://caremad.io/2013/07/setup-vs-requirement/ এ সুপারিশ করছি যাতে এই সমস্যাটি ভাল হয়। আমি এটি দুর্দান্ত সাফল্যে ব্যবহার করছি।

সংক্ষেপে, requirements.txtএকটি নয় setup.pyবিকল্প, কিন্তু একটি স্থাপনার সম্পূরক। এতে প্যাকেজ নির্ভরতার উপযুক্ত বিমূর্ততা রাখুন setup.pyrequirements.txtবিকাশ, পরীক্ষা, বা উত্পাদনের জন্য প্যাকেজ নির্ভরতার নির্দিষ্ট সংস্করণগুলি আনার জন্য তাদের আরও কিছু সেট করুন ।

উদাহরণস্বরূপ, রেপোতে অন্তর্ভুক্ত প্যাকেজগুলির সাথে deps/:

# fetch specific dependencies
--no-index
--find-links deps/

# install package
# NOTE: -e . for editable mode
.

পিপ প্যাকেজ কার্যকর করে setup.pyএবং ঘোষিত নির্ভরতার নির্দিষ্ট সংস্করণ ইনস্টল করে install_requires। কোনও সদৃশতা নেই এবং উভয় নিদর্শনগুলির উদ্দেশ্য সংরক্ষণ করা হয়েছে।


7
আপনি অন্যের মাধ্যমে ইনস্টল করার জন্য কোনও প্যাকেজ সরবরাহ করতে চাইলে এটি কাজ করে না pip install my-package। যদি আমার প্যাকেজটির জন্য নির্ভরতাগুলি আমার প্যাকেজ / সেটআপ.পিতে তালিকাভুক্ত না করা হয় তবে সেগুলি ইনস্টল হয় না pip install my-package। অন্যদের জন্য কীভাবে প্যাকেজ সরবরাহ করা যায় তা নির্ধারণ করতে আমি ব্যর্থ হয়েছি যাতে সেটআপ.পি-তে স্পষ্টভাবে উল্লেখ না করে নির্ভরতা অন্তর্ভুক্ত থাকে। প্রয়োজনীয় ফাইলটি ডাউনলোড না করে এবং ম্যানুয়ালি কল না করে যদি কেউ আমার-প্যাকেজ + নির্ভরতা ইনস্টল করতে দেয় তবে কীভাবে এটি ডিআরওয়াই রাখতে হবে তা যদি কেউ জানতে পারেন তবে তা জানতে আগ্রহী pip install -r my-package/requirements.txt
মালিনা

2
@ মালিনা এখানে প্যাকেজটি নিখুঁতভাবে ইনস্টলযোগ্য requirements.txt। এই হল ব্যপার. বিষয়গুলি আরও পরিষ্কার করার জন্য প্রশ্ন আপডেট করেছে। অপ্রচলিত ব্লগ পোস্ট লিঙ্কটিও আপডেট হয়েছে।
বিখ্যাতগারকিন

সুতরাং setup.py চালানোর সময় এটি stup.py এ তালিকাভুক্ত ফাইলগুলির নির্দিষ্ট সংস্করণগুলির জন্য প্রয়োজনীয়গুলি.txt কল করবে?
dtracers

এটি @dtracers এর অন্য উপায়ে। প্রয়োজনীয়তা.txt প্যাকেজটি এটি নিজেই নির্দেশ করে, যেখানে setup.py এর নির্ভরশীলতাগুলি বেছে নেওয়া যেতে পারে। সুতরাং প্রয়োজনীয়তা ব্যবহার করে ইনস্টল করার সময়, এটি কাজ করে এবং পাইপের মাধ্যমে ইনস্টল করার সময়, এটি খুব কার্যকর হয় - উভয় ক্ষেত্রেই সেটআপ.পি এর নির্ভরশীলতা ব্যবহার করে, তবে প্রয়োজনীয়তা.
txt

20

ব্যবহার parse_requirementsকরা সমস্যাযুক্ত কারণ পাইপ এপিআই প্রকাশ্যে নথিভুক্ত ও সমর্থিত নয়। পাইপ ১.6-এ, সেই ফাংশনটি আসলে চলমান, সুতরাং এর বিদ্যমান ব্যবহারগুলি ভাঙ্গার সম্ভাবনা রয়েছে।

আরো নির্ভরযোগ্য উপায় মধ্যে প্রতিলিপি নিষ্কাশন করে setup.pyএবং requirements.txtনির্দিষ্ট হয় আপনার নির্ভরতা setup.pyএবং তারপর করা -e .আপনার মধ্যে requirements.txtফাইল। pipকেন উন্নততর উপায় সে সম্পর্কে আরও বিকাশকারীদের কিছু তথ্য এখানে পাওয়া যায়: https://caremad.io/blog/setup-vs-requirement/


@ টমি এটি চেষ্টা করুন: caremad.io/2013/07/setup-vs-requirement এটি অন্য উত্তরে পোস্ট করা একই লিঙ্ক।
amit

18

উপরের অন্যান্য উত্তরগুলির বেশিরভাগই পাইপের API এর বর্তমান সংস্করণে কাজ করে না। এখানে পিপ-এর বর্তমান সংস্করণ (writing.০.৮ লেখার সময় এটি 7.১.২ এও কাজ করেছিল with

from pip.req import parse_requirements
from pip.download import PipSession

install_reqs = parse_requirements(<requirements_path>, session=PipSession())

reqs = [str(ir.req) for ir in install_reqs]

setup(
    ...
    install_requires=reqs
    ....
)

* সঠিক, এটি বর্তমান পাইপের সাথে পার্স_ প্রয়োজনীয়তা ব্যবহার করার উপায়। এটি এখনও সম্ভবত এটি করার সর্বোত্তম উপায় নয়, যেহেতু, উপরে পোস্টারগুলি যেমন বলেছে, পাইপ আসলে কোনও এপিআই বজায় রাখে না।


14

ট্র্যাভিসে বর্তমান প্যাকেজটি ইনস্টল করুন। এটি কোনও requirements.txtফাইলের ব্যবহার এড়ানো যায় । উদাহরণ স্বরূপ:

language: python
python:
  - "2.7"
  - "2.6"
install:
  - pip install -q -e .
script:
  - python runtests.py

2
এটি এখন পর্যন্ত "সঠিক" এবং "ব্যবহারিক" এর সর্বোত্তম সমন্বয়। আমি যুক্ত করে দিয়েছি যে পরীক্ষাগুলি পাস করার পরে আপনি ট্র্যাভিসকে প্রয়োজনীয়তা তৈরি করতে পেতে পারেন t টেক্সট সহ কোনও pip freezeফাইলটি আর্টিফ্যাক্ট হিসাবে (এস 3 বা কোনও কিছু) হিসাবে রফতানি করতে পারেন, তবে পুনরাবৃত্তিটি সঠিকভাবে ইনস্টল করার দুর্দান্ত উপায় আপনার কাছে রয়েছে পরীক্ষিত।
জোনাথন হ্যানসন

4

from pip.req import parse_requirements আমার পক্ষে কাজ করে নি এবং আমি মনে করি এটি আমার প্রয়োজনীয়তাগুলিতে ফাঁকা রেখার জন্য t txt, তবে এই ফাংশনটি কাজ করে

def parse_requirements(requirements):
    with open(requirements) as f:
        return [l.strip('\n') for l in f if l.strip('\n') and not l.startswith('#')]

reqs = parse_requirements(<requirements_path>)

setup(
    ...
    install_requires=reqs,
    ...
)

4

আপনি যদি আপনার ব্যবহারকারীদের পিপ ইনস্টল করতে বাধ্য করতে না চান তবে আপনি এর ব্যবহারটি এর সাথে অনুকরণ করতে পারেন:

import sys

from os import path as p

try:
    from setuptools import setup, find_packages
except ImportError:
    from distutils.core import setup, find_packages


def read(filename, parent=None):
    parent = (parent or __file__)

    try:
        with open(p.join(p.dirname(parent), filename)) as f:
            return f.read()
    except IOError:
        return ''


def parse_requirements(filename, parent=None):
    parent = (parent or __file__)
    filepath = p.join(p.dirname(parent), filename)
    content = read(filename, parent)

    for line_number, line in enumerate(content.splitlines(), 1):
        candidate = line.strip()

        if candidate.startswith('-r'):
            for item in parse_requirements(candidate[2:].strip(), filepath):
                yield item
        else:
            yield candidate

setup(
...
    install_requires=list(parse_requirements('requirements.txt'))
)

4

নিম্নলিখিত ইন্টারফেসটি পিপ 10 এ অবচয় করা হয়েছে:

from pip.req import parse_requirements
from pip.download import PipSession

সুতরাং আমি এটিকে কেবল সাধারণ পাঠ্য পার্সিংয়ে স্যুইচ করেছি:

with open('requirements.txt', 'r') as f:
    install_reqs = [
        s for s in [
            line.split('#', 1)[0].strip(' \t\n') for line in f
        ] if s != ''
    ]

এই সহজ পদ্ধতির 90% সময়ের উপরে কাজ করে। পাইথন ৩.6++ যারা ব্যবহার করেন তাদের জন্য আমি একটি উত্তরpathlib লিখেছি যা এটির একটি প্রকরণ
একিউম্যানাস

3

এই সহজ পদ্ধতির থেকে প্রয়োজনীয় ফাইলটি পড়ে setup.py। এটি দিমিত্রি এস এর উত্তরের একটি পরিবর্তন । এই উত্তরটি কেবল পাইথন 3.6+ এর সাথে সামঞ্জস্যপূর্ণ।

প্রতি ডিএস , requirements.txtনির্দিষ্ট সংস্করণ সংখ্যা সহ কংক্রিট প্রয়োজনীয়তা ডকুমেন্ট করতে পারে, অন্যদিকেsetup.py আলগা সংস্করণ ব্যাপ্তি সহ বিমূর্ত প্রয়োজনীয়তাগুলি ডকুমেন্ট করতে পারে।

নীচে আমার একটি অংশ setup.py

import distutils.text_file
from pathlib import Path
from typing import List

def _parse_requirements(filename: str) -> List[str]:
    """Return requirements from requirements file."""
    # Ref: https://stackoverflow.com/a/42033122/
    return distutils.text_file.TextFile(filename=str(Path(__file__).with_name(filename))).readlines()

setup(...
      install_requires=_parse_requirements('requirements.txt'),
   ...)

নোট যে distutils.text_file.TextFileমন্তব্য ফেলা হবে। এছাড়াও, আমার অভিজ্ঞতা অনুযায়ী, আপাতদৃষ্টিতে আপনার প্রয়োজনীয় ফাইলগুলিতে বান্ডিল করার জন্য কোনও বিশেষ পদক্ষেপ নেওয়ার দরকার নেই।


2

আচরণ থেকে সাবধান parse_requirements!

দয়া করে নোট করুন যে pip.req.parse_requirementsআন্ডারস্কোরগুলি ড্যাশগুলিতে পরিবর্তন করবে। এটি আবিষ্কার করার আগে কয়েক দিন এটি আমাকে বিরক্ত করেছিল। উদাহরণস্বরূপ উদাহরণ:

from pip.req import parse_requirements  # tested with v.1.4.1

reqs = '''
example_with_underscores
example-with-dashes
'''

with open('requirements.txt', 'w') as f:
    f.write(reqs)

req_deps = parse_requirements('requirements.txt')
result = [str(ir.req) for ir in req_deps if ir.req is not None]
print result

উত্পাদন করে

['example-with-underscores', 'example-with-dashes']

1
আন্ডারস্কোর সংস্করণটি পেতে অনিরাপদ_নামটি ব্যবহার করুন :[ir.req.unsafe_name for ir in req_deps if ir.req is not None]
অ্যালানজডস

5
অন্য কোথাও দেখানো হয়েছে, পিআইপি হ'ল একটি অ্যাপ্লিকেশন, লাইব্রেরি নয়। এটির কোনও প্রকাশ্যে সম্মত-এপিআই নেই, এবং এটি আপনার কোডে আমদানি করা কোনও সমর্থিত ব্যবহারের ক্ষেত্রে নয়। এটি অপ্রত্যাশিত আচরণের সাথে অবাক হওয়ার কিছু নেই; এর অভ্যন্তরীণ ক্রিয়াকলাপগুলি কখনও এভাবে ব্যবহার করার উদ্দেশ্যে করা হয়নি।
জোনাথন হ্যানসন

1

আমি এটির জন্য পুনরায় ব্যবহারযোগ্য ফাংশন তৈরি করেছি। এটি প্রকৃতপক্ষে প্রয়োজনীয় ফাইলগুলির একটি সম্পূর্ণ ডিরেক্টরিকে বিশ্লেষণ করে এবং এগুলি অতিরিক্ত_ প্রয়োজনীয়তার উপর সেট করে।

সর্বদা সর্বদা এখানে উপলভ্য: https://gist.github.com/akatrevorjay/293c26fefa24a7b812f5

import glob
import itertools
import os

# This is getting ridiculous
try:
    from pip._internal.req import parse_requirements
    from pip._internal.network.session import PipSession
except ImportError:
    try:
        from pip._internal.req import parse_requirements
        from pip._internal.download import PipSession
    except ImportError:
        from pip.req import parse_requirements
        from pip.download import PipSession


def setup_requirements(
        patterns=[
            'requirements.txt', 'requirements/*.txt', 'requirements/*.pip'
        ],
        combine=True):
    """
    Parse a glob of requirements and return a dictionary of setup() options.
    Create a dictionary that holds your options to setup() and update it using this.
    Pass that as kwargs into setup(), viola

    Any files that are not a standard option name (ie install, tests, setup) are added to extras_require with their
    basename minus ext. An extra key is added to extras_require: 'all', that contains all distinct reqs combined.

    Keep in mind all literally contains `all` packages in your extras.
    This means if you have conflicting packages across your extras, then you're going to have a bad time.
    (don't use all in these cases.)

    If you're running this for a Docker build, set `combine=True`.
    This will set `install_requires` to all distinct reqs combined.

    Example:

    >>> import setuptools
    >>> _conf = dict(
    ...     name='mainline',
    ...     version='0.0.1',
    ...     description='Mainline',
    ...     author='Trevor Joynson <github@trevor.joynson,io>',
    ...     url='https://trevor.joynson.io',
    ...     namespace_packages=['mainline'],
    ...     packages=setuptools.find_packages(),
    ...     zip_safe=False,
    ...     include_package_data=True,
    ... )
    >>> _conf.update(setup_requirements())
    >>> # setuptools.setup(**_conf)

    :param str pattern: Glob pattern to find requirements files
    :param bool combine: Set True to set install_requires to extras_require['all']
    :return dict: Dictionary of parsed setup() options
    """
    session = PipSession()

    # Handle setuptools insanity
    key_map = {
        'requirements': 'install_requires',
        'install': 'install_requires',
        'tests': 'tests_require',
        'setup': 'setup_requires',
    }
    ret = {v: set() for v in key_map.values()}
    extras = ret['extras_require'] = {}
    all_reqs = set()

    files = [glob.glob(pat) for pat in patterns]
    files = itertools.chain(*files)

    for full_fn in files:
        # Parse
        reqs = {
            str(r.req)
            for r in parse_requirements(full_fn, session=session)
            # Must match env marker, eg:
            #   yarl ; python_version >= '3.0'
            if r.match_markers()
        }
        all_reqs.update(reqs)

        # Add in the right section
        fn = os.path.basename(full_fn)
        barefn, _ = os.path.splitext(fn)
        key = key_map.get(barefn)

        if key:
            ret[key].update(reqs)
            extras[key] = reqs

        extras[barefn] = reqs

    if 'all' not in extras:
        extras['all'] = list(all_reqs)

    if combine:
        extras['install'] = ret['install_requires']
        ret['install_requires'] = list(all_reqs)

    def _listify(dikt):
        ret = {}

        for k, v in dikt.items():
            if isinstance(v, set):
                v = list(v)
            elif isinstance(v, dict):
                v = _listify(v)
            ret[k] = v

        return ret

    ret = _listify(ret)

    return ret


__all__ = ['setup_requirements']

if __name__ == '__main__':
    reqs = setup_requirements()
    print(reqs)

খুব সুন্দর! এমনকি সর্বশেষ
পাইপ

@ আমর ধন্যবাদ! আমি সামান্য পাইপটির জন্য সম্প্রতি এটি আপডেট করেছি, আমি নিশ্চিত নই যে তারা কেন তারা যেমন আচরণ করছে, জিনিসগুলিতে সরানোর মাধ্যমে pip._internal.. আপনি যদি ব্যবহারযোগ্য বহিরাগত এপিআই সরবরাহ না করেন তবে আপনার সবগুলি ভাঙা উচিত নয় যা আপনার দেওয়া সমস্ত ব্যবহার করছে।
ট্রেভরজ

0

আর একটি সম্ভাব্য সমাধান ...

def gather_requirements(top_path=None):
    """Captures requirements from repo.

    Expected file format is: requirements[-_]<optional-extras>.txt

    For example:

        pip install -e .[foo]

    Would require:

        requirements-foo.txt

        or

        requirements_foo.txt

    """
    from pip.download import PipSession
    from pip.req import parse_requirements
    import re

    session = PipSession()
    top_path = top_path or os.path.realpath(os.getcwd())
    extras = {}
    for filepath in tree(top_path):
        filename = os.path.basename(filepath)
        basename, ext = os.path.splitext(filename)
        if ext == '.txt' and basename.startswith('requirements'):
            if filename == 'requirements.txt':
                extra_name = 'requirements'
            else:
                _, extra_name = re.split(r'[-_]', basename, 1)
            if extra_name:
                reqs = [str(ir.req) for ir in parse_requirements(filepath, session=session)]
                extras.setdefault(extra_name, []).extend(reqs)
    all_reqs = set()
    for key, values in extras.items():
        all_reqs.update(values)
    extras['all'] = list(all_reqs)
    return extras

এবং তারপরে ...

reqs = gather_requirements()
install_reqs = reqs.pop('requirements', [])
test_reqs = reqs.pop('test', [])
...
setup(
    ...
    'install_requires': install_reqs,
    'test_requires': test_reqs,
    'extras_require': reqs,
    ...
)

কোথায় treeথেকে এসেছে?
ফ্রান্সেস্কো বোই

@ ফ্রেঞ্চসোবোই যদি আপনি সম্পূর্ণরূপে কার্যক্ষম সমাধান না উপস্থাপনের জন্য আমাকে কিছুটা ক্ষমা করেন ... ট্রি আসলে স্থানীয় ফাইল সিস্টেমের একটি স্ক্যান (লিনাক্সের "ট্রি" কমান্ডের সাথে খুব মিল)। এছাড়াও, আমার উপরের সমাধানটি এই মুহুর্তে পুরোপুরি কাজ করতে পারে না কারণ পাইপ ক্রমাগত আপডেট করা থাকে এবং আমি পাইপ ইন্টার্নাল ব্যবহার করি।
ব্রায়ান ব্রুগম্যান

0

আমি এই জাতীয় কাজ করার পরামর্শ দেব না। যেমনটি একাধিকবার উল্লেখ করা হয়েছে install_requiresএবং requirements.txtঅবশ্যই একই তালিকা হওয়ার কথা নয়। কিন্তু যেহেতু উত্তর প্রায় সব বেসরকারি অভ্যন্তরীণ API গুলি জড়িত বিভ্রান্তিকর অনেক আছে পিপ , এটা saner বিকল্প এ খুঁজছেন মূল্য হতে পারে ...

জন্য কোন প্রয়োজন নেই পিপ একটি বিশ্লেষণ করতে requirements.txtএকটি থেকে ফাইল setuptools setup.py স্ক্রিপ্ট। Setuptools ইতিমধ্যে প্রকল্প তার সব প্রয়োজনীয় টুলস রয়েছে শীর্ষ স্তরের প্যাকেজ pkg_resources

এটি কমবেশি এর মতো দেখতে পারে:

#!/usr/bin/env python3

import pathlib

import pkg_resources
import setuptools

with pathlib.Path('requirements.txt').open() as requirements_txt:
    install_requires = [
        str(requirement)
        for requirement
        in pkg_resources.parse_requirements(requirements_txt)
    ]

setuptools.setup(
    install_requires=install_requires,
)

আপনি যদি অবহিত না হন তবে যে কারণে 2015 এর আগে অনেকগুলি (নিজেকে অন্তর্ভুক্ত করেছেন) pip'পার্সিং' ব্যবহার করছেন এবং তা নয় pkg_resourcesএর কারণগুলি github.com/pypa/setuptools/issues/470 এর মতো বাগ রয়েছে । এই সঠিকটি আজকাল স্থির করা হয়েছে, তবে উভয় বাস্তবায়ন পৃথকভাবে বিকাশিত বলে মনে হচ্ছে বলে এটি ব্যবহার করতে আমি এখনও কিছুটা ভয় পেয়েছি।
ট্রেভরজ

@ ট্রেভরজ এই নির্দেশ করার জন্য ধন্যবাদ, আমি জানতাম না। ঘটনা আজকাল এটি কাজ করে এবং পাইপ জড়িত হওয়া আমার কাছে একটি হাস্যকর ধারণা বলে মনে হয় (বিশেষত এই ফ্যাশনে)। অন্যান্য উত্তরগুলি দেখুন, বেশিরভাগ ক্ষেত্রে একই সতর্কতা অবলম্বন না করে একই অসুস্থ-পরামর্শযুক্ত ধারণার সামান্য পরিবর্তনের মতো মনে হয়। এবং নতুনরা কেবল এই প্রবণতাটি অনুসরণ করতে পারে। আশা করি PEP517 এবং PEP518 এর মতো উদ্যোগগুলি সম্প্রদায়কে এই উন্মাদনা থেকে দূরে সরিয়ে দেবে।
সিনোরোক

-1

আর একটি সাধারণ, পিপ সংস্করণ প্রমাণ সমাধানের জন্য এই উত্তর প্রশ্নটি থেকে আমার উত্তর পোস্ট করুন Cross

try:  # for pip >= 10
    from pip._internal.req import parse_requirements
    from pip._internal.download import PipSession
except ImportError:  # for pip <= 9.0.3
    from pip.req import parse_requirements
    from pip.download import PipSession

requirements = parse_requirements(os.path.join(os.path.dirname(__file__), 'requirements.txt'), session=PipSession())

if __name__ == '__main__':
    setup(
        ...
        install_requires=[str(requirement.req) for requirement in requirements],
        ...
    )

তারপরে আপনার সমস্ত প্রয়োজনীয়তা requirements.txtপ্রকল্পের মূল ডিরেক্টরিতে অন্তর্ভুক্ত করুন।


-1

আমি এটা করেছি:

import re

def requirements(filename):
    with open(filename) as f:
        ll = f.read().splitlines()
    d = {}
    for l in ll:
        k, v = re.split(r'==|>=', l)
        d[k] = v
    return d

def packageInfo():
    try:
        from pip._internal.operations import freeze
    except ImportError:
        from pip.operations import freeze

    d = {}
    for kv in freeze.freeze():
        k, v = re.split(r'==|>=', kv)
        d[k] = v
    return d

req = getpackver('requirements.txt')
pkginfo = packageInfo()

for k, v in req.items():
    print(f'{k:<16}: {v:<6} -> {pkginfo[k]}')

-2

তবুও অন্য একটি parse_requirementsহ্যাক যা পরিবেশের চিহ্নিতকারীগুলিকেও পার্স করে extras_require:

from collections import defaultdict
from pip.req import parse_requirements

requirements = []
extras = defaultdict(list)
for r in parse_requirements('requirements.txt', session='hack'):
    if r.markers:
        extras[':' + str(r.markers)].append(str(r.req))
    else:
        requirements.append(str(r.req))

setup(
    ...,
    install_requires=requirements,
    extras_require=extras
)

এটি sdist এবং বাইনারি উভয় ডিস্ট সমর্থন করা উচিত।

যেমনটি অন্যদের দ্বারা বলা হয়েছে, parse_requirementsবেশ কয়েকটি ত্রুটি রয়েছে, তাই আপনার সরকারী প্রকল্পে এটি করা উচিত নয়, তবে এটি অভ্যন্তরীণ / ব্যক্তিগত প্রকল্পগুলির জন্য যথেষ্ট ice


পিপ 20.1 তাদের এপিআই পরিবর্তন করেছে এবং মার্কারগুলি আর কোনও মাধ্যমে পাওয়া যায় parse_requirements()না, তাই এটি এখন ব্যর্থ।
টুউকা মস্তোনেন

-3

রোমেনের উত্তরেরpip 9.0.1 উপর ভিত্তি করে এখানে একটি সম্পূর্ণ হ্যাক (পরীক্ষিত ) দেওয়া হয়েছে যা বর্তমান পরিবেশ চিহ্নিতকারী অনুসারে পার্স করে এবং ফিল্টার করে :requirements.txt

from pip.req import parse_requirements

requirements = []
for r in parse_requirements('requirements.txt', session='hack'):
    # check markers, such as
    #
    #     rope_py3k    ; python_version >= '3.0'
    #
    if r.match_markers():
        requirements.append(str(r.req))

print(requirements)

1
এটি কেবল আংশিক সত্য। আপনি যদি কল করেন r.match_markers()আপনি আসলে চিহ্নিতকারীদের মূল্যায়ন করছেন যা কোনও এসডিস্টের জন্য সঠিক জিনিস। তবে, আপনি যদি বাইনারি ডিস্ট (যেমন চাকা) তৈরি করে থাকেন তবে প্যাকেজটি কেবল সেই লাইব্রেরিগুলির তালিকা তৈরি করবে যা আপনার বিল্ড-টাইম পরিবেশের সাথে মিলে ।
টুকু মুস্তোনেন

@ টুকু মস্তোনেন, সুতরাং এর wheel environmentবিপরীতে চিহ্নিতকারীদের মূল্যায়ন করার জন্য এটি কোথায় (যদি ব্যক্তি এটি করার চেষ্টা করে) খুঁজে পাবে?
অ্যানাটোলি টেকটোনিক

স্ট্যাকওভারফ্লো.com/a/41172125/165629 এটিকেও সমর্থন করা উচিত দেখুন bdist_wheel। এটি চিহ্নিতকারীদের মূল্যায়ন করে না, এটি কেবল তাদের সাথে যুক্ত করে extras_require
টুকু মুস্তোনেন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.