Zacząłem pracować z Pythonem. Dodałem requirements.txt
i setup.py
do mojego projektu. Ale nadal nie mam pojęcia, jaki jest cel obu plików. Czytałem, że setup.py
jest przeznaczony do rzeczy podlegających redystrybucji i requirements.txt
jest przeznaczony do rzeczy, które nie podlegają redystrybucji. Ale nie jestem pewien, czy to prawda.
Jak naprawdę mają być używane te dwa pliki?
Odpowiedzi:
wymagania.txt
Pomaga to skonfigurować środowisko programistyczne. Programy takie jak
pip
mogą być użyte do zainstalowania wszystkich pakietów wymienionych w pliku za jednym zamachem. Następnie możesz rozpocząć tworzenie skryptu w języku Python. Jest to szczególnie przydatne, jeśli planujesz, aby inne osoby przyczyniły się do rozwoju lub korzystania ze środowisk wirtualnych. Oto jak tego używasz:setup.py
Pozwala to na tworzenie pakietów, które można redystrybuować. Ten skrypt ma na celu zainstalowanie pakietu w systemie użytkownika końcowego, a nie przygotowanie środowiska programistycznego, jak to
pip install -r requirements.txt
ma miejsce. Zobacz tę odpowiedź, aby uzyskać więcej informacji na temat setup.py.Zależności projektu są wymienione w obu plikach.
źródło
Krótka odpowiedź jest taka, że
requirements.txt
wystarczy wymienić wymagania dotyczące pakietu.setup.py
z drugiej strony bardziej przypomina skrypt instalacyjny. Jeśli nie planujesz instalowania kodu w Pythonie, zwykle potrzebujesz tylkorequirements.txt
.Plik
setup.py
opisuje, oprócz zależności pakietu, zestaw plików i modułów, które powinny być spakowane (lub skompilowane, w przypadku modułów natywnych (tj. Napisane w C)) oraz metadane, które należy dodać do listy pakietów pythona ( np. nazwa pakietu, wersja pakietu, opis pakietu, autor, ...).Ponieważ oba pliki zawierają zależności, może to prowadzić do pewnego powielenia. Przeczytaj poniżej, aby uzyskać szczegółowe informacje.
wymagania.txt
Ten plik zawiera listę wymagań dotyczących pakietów Pythona. Jest to zwykły plik tekstowy (opcjonalnie z komentarzami), który zawiera listę zależności pakietów projektu w języku Python (po jednym w każdym wierszu). Tak nie jest opisują sposób, w którym został zainstalowany pakiet python. Zwykle zużywałbyś plik wymagań z rozszerzeniem
pip install -r requirements.txt
.Nazwa pliku tekstowego jest dowolna, ale często wynika
requirements.txt
z konwencji. Podczas eksploracji repozytoriów kodu źródłowego innych pakietów Pythona możesz natknąć się na inne nazwy, takie jakdev-dependencies.txt
lubdependencies-dev.txt
. Służą one temu samemu celowi,dependencies.txt
ale generalnie zawierają listę dodatkowych zależności interesujących deweloperów danego pakietu, mianowicie do testowania kodu źródłowego (np. Pytest, pylint itp.) Przed wydaniem. Użytkownicy pakietu na ogół nie potrzebowaliby całego zestawu zależności programisty do uruchomienia pakietu.Jeśli
requirements-X.txt
istnieje wiele wariantów, zwykle jeden będzie zawierał listę zależności środowiska wykonawczego, a drugi czas kompilacji lub zależności testowe. Niektóre projekty również kaskadowo tworzą swój plik wymagań, tj. Gdy jeden plik wymagań zawiera inny plik ( np ). Może to zmniejszyć liczbę powtórzeń.setup.py
To jest skrypt w języku Python, który używa
setuptools
modułu do zdefiniowania pakietu w języku Python (nazwa, dołączone pliki, metadane pakietu i instalacja). Będzie on, podobnierequirements.txt
, wyświetlał również listę zależności wykonawczych pakietu. Setuptools to de facto sposób budowania i instalowania pakietów Pythona, ale ma on swoje wady, które z czasem spowodowały rozwój nowych „menedżerów metapakietów”, takich jak pip. Przykładowe wady setuptools to brak możliwości zainstalowania wielu wersji tego samego pakietu oraz brak polecenia odinstalowania.Gdy użytkownik Pythona to zrobi
pip install ./pkgdir_my_module
(lubpip install my-module
), pip będzie działałsetup.py
w podanym katalogu (lub module). Podobnie każdy moduł, który posiada,setup.py
możnapip
zainstalować, np. Uruchamiającpip install .
z tego samego folderu.Czy naprawdę potrzebuję obu?
Krótka odpowiedź brzmi: nie, ale dobrze jest mieć jedno i drugie. Osiągają różne cele, ale oba mogą być używane do tworzenia listy zależności.
Jest jedna sztuczka, którą możesz rozważyć, aby uniknąć powielania listy zależności między
requirements.txt
isetup.py
. Jeśli napisałeś już w pełni działającą wersjęsetup.py
dla swojego pakietu, a twoje zależności są w większości zewnętrzne, możesz rozważyć prostą,requirements.txt
zawierającą tylko następujące elementy:-e
To specjalnapip install
opcja, która instaluje dany pakiet w edycji trybu. Popip -r requirements.txt
uruchomieniu na tym pliku pip zainstaluje Twoje zależności za pośrednictwem listy w./setup.py
. Opcja edytowalna umieści łącze symboliczne w katalogu instalacyjnym (zamiast jajka lub zarchiwizowanej kopii). Umożliwia programistom edycję kodu w miejscu z repozytorium bez ponownej instalacji.Możesz także skorzystać z tego, co nazywa się „dodatkami setuptools”, gdy masz oba pliki w repozytorium pakietów. Możesz zdefiniować opcjonalne pakiety w setup.py w niestandardowej kategorii i zainstalować te pakiety tylko z tej kategorii za pomocą pip:
a następnie w pliku wymagań:
Spowodowałoby to zachowanie wszystkich list zależności wewnątrz setup.py.
Uwaga : pip i setup.py zwykle uruchamiasz z piaskownicy, takiej jak te utworzone za pomocą programu
virtualenv
. Pozwoli to uniknąć instalowania pakietów Pythona poza kontekstem środowiska programistycznego projektu.źródło
.
w-e
środkurequirements.txt
. Ta metoda po prostu deleguje wszystkie wymaganiasetup.py
i nie musisz nikogo zmuszać do przejścia w tryb edytowalny. Użytkownicy nadal mogą to robić,pip install -e .
jeśli chcą.-e .
również używa setup.py do znalezienia zależności, ale łączy bieżący folder (na miejscu, za pomocą dowiązania symbolicznego) w folderze instalacyjnym pip, zamiast robić kopię --e
zwykle używasz tylko wtedy, gdy tworzysz pakiet. Dzięki temu-e
zmiany w plikach pakietów Pythona (* .py) zaczną obowiązywać natychmiast w środowisku pip, zamiast wymuszania ponownej instalacji pakietu po każdej zmianie.cd foo && pip install -r ./bar/requirements.txt
, to wyszuka setup.py wfoo/bar
lubfoo
? Jeśli to drugie, czy jest sposób na osiągnięcie tego pierwszego?pip -r REQ
nie dba o katalog, w którym znajduje się REQ. Można karmić je z FIFO nawet jeśli chcesz:pip install -r <(echo "mylib1"; echo "mylib2";)
. Gdzie<(CMD)
jest podstawianie poleceń bash, a nie przekierowanie stdin.W trosce o kompletność, oto jak widzę to pod
34 różnymi kątami.Oto dokładny opis cytowany z oficjalnej dokumentacji (wyróżnienie moje):
Ale może to nie być łatwe do zrozumienia, więc w następnej sekcji podamy 2 faktyczne przykłady pokazujące, w jaki sposób te dwa podejścia powinny być używane w różny sposób.
Ich rzeczywiste zastosowania są zatem (rzekomo) różne
Jeśli twój projekt
foo
ma zostać wydany jako samodzielna biblioteka (co oznacza, że inni prawdopodobnie by to zrobiliimport foo
), wtedy ty (i twoi dalsi użytkownicy) chcielibyście mieć elastyczną deklarację zależności, aby twoja biblioteka nie (i nie może ) bądź „wybredny” co do dokładnej wersji TWOICH zależności. Więc zazwyczaj plik setup.py zawierałby takie linie:Jeśli chcesz w jakiś sposób „udokumentować” lub „przypiąć” swoje DOKŁADNE bieżące środowisko dla swojej aplikacji
bar
, co oznacza, że Ty lub Twoi użytkownicy chcielibyście korzystać z aplikacji wbar
takiej postacipython bar.py
, w jakiej jest, tj. Działającej , można zechcieć zamrozić środowisko, aby zawsze zachowywał się tak samo. W takim przypadku Twój plik wymagań wyglądałby tak:W rzeczywistości, którego używam?
Jeśli tworzysz aplikację, z
bar
której będzie korzystałpython bar.py
, nawet jeśli jest to „tylko skrypt dla zabawy”, nadal zalecamy korzystanie z pliku Requirements.txt, ponieważ, kto wie, w przyszłym tygodniu (czyli w święta Bożego Narodzenia) otrzymasz nowy komputer w prezencie, więc musisz ponownie skonfigurować tam swoje dokładne środowisko.Jeśli tworzysz bibliotekę,
foo
która będzie używana przezimport foo
, musisz przygotować plik setup.py. Kropka. Ale nadal możesz wybrać jednocześnie plik Requirements.txt, który może:(a) być w
A==1.2.3
stylu (jak wyjaśniono w punkcie 2 powyżej);(b) lub po prostu zawierać magiczny singiel
.
co w przybliżeniu oznaczałoby „zainstaluj wymagania w oparciu o setup.py” bez duplikowania. Osobiście uważam, że to ostatnie podejście w pewnym sensie zaciera linię, pogłębia zamieszanie i tak naprawdę NIE dodaje wartości, niemniej jednak jest to sztuczka wywodząca się z podejścia, o którym wspomniał Donald, opiekun opakowań Pythona w swoim poście na blogu .
Różne dolne granice.
Nawet jeśli spełniłeś powyższe 3 kryteria i poprawnie zdecydowałeś, że twoja biblioteka
hybrid-engine
użyje asetup.py
do zadeklarowania swojej zależnościengine>=1.2.0
, a twoja przykładowa aplikacjareliable-car
użyjerequirements.txt
do zadeklarowania swojej zależnościengine>=1.2.3
, nawet jeśli najnowsza wersjaengine
jest już 1.4.0. Jak widzisz, wybór ich dolnej granicy jest nadal nieco inny. A oto dlaczego.hybrid-engine
zależy odengine>=1.2.0
tego, ponieważ, hipotetycznie rzecz biorąc, potrzebna zdolność "spalania wewnętrznego" została wprowadzona po raz pierwszy w programieengine 1.2.0
, a ta zdolność jest koniecznościąhybrid-engine
, niezależnie od tego, czy w takiej wersji mogą być jakieś (drobne) błędy i zostały poprawione w kolejnych wersjach 1.2.1 , 1.2.2 i 1.2.3.reliable-car
zależy od,engine>=1.2.3
ponieważ jest to jak dotąd najwcześniejsza wersja BEZ znanych problemów. Oczywiście, w późniejszych wersjach są nowe możliwości, powiedzmy, wprowadzono „silnik elektryczny”engine 1.3.0
i „reaktor jądrowy”engine 1.4.0
, ale nie są one konieczne w projekciereliable-car
.źródło
A==1.2.3
, a następnie, jeśli zdarzy sięA==1.2.4
, że pakiet podrzędny twojej biblioteki będzie zależał , teraz nie będzie sposobu, aby spełnić oba. Rozwiązaniem minimalizującym ten konflikt jest zdefiniowanie przez bibliotekę zakresu, o którym wiesz, że będzie działać. Zakładając, że wiele zewnętrznych bibliotek jest już zgodnych z semver.org ,A>=1,<2
zadziała.foo
maimport foo
dać? Ta nietrafiona, zaakceptowana odpowiedź w tym odnośniku, który podałeś, jest doskonałym przykładem tego, dlaczego opiekun pakietu „nie powinien i nie może być wybredny”. :-) Czy teraz mogę prosić o głos za?