Code-Poets / coding-style

0 stars 0 forks source link

Aktualizowanie zależności pythonowych #12

Open cameel opened 6 years ago

cameel commented 6 years ago

Poniżej proponowany przeze mnie opis aktualizacji zależności. Tak to obecnie robimy w Concencie.

requirements.lock i requirements.txt

W repozytorium przechowujemy dwie osobne listy zależności:

Przykład requirements.txt:

Django >= 1.11, < 1.12
django-constance[database]
requests
-e git://github.com/dbtsai/python-mimeparse.git@1.6.0#egg=python-mimeparse

Wygenerowany z niego requirements.lock:

certifi==2018.4.16
chardet==3.0.4
Django==1.11.14
django-constance==2.2.0
django-picklefield==1.0.0
idna==2.7
-e git://github.com/dbtsai/python-mimeparse.git@9a758d1a68ebdb71111dc244acd0a4be42e6bdc8#egg=python_mimeparse
pytz==2018.5
requests==2.19.1
urllib3==1.23
Nazewnictwo plików

Prawie w każdym projekcie istnieje requirements.txt, ale nazwy dla drugiego pliku mogą być różne. Nie ma też ustalonej w Pythonie konwencji czy requirements.txt zawiera tylko bezpośrednie zależności czy wszystkie.

W jednym z naszych projektów requirements.txt zawierał wszystkie zależności, a te bezpośrednie były w pliku requirements.in. Obecnie zalecane są nazwy podane powyżej.

Dodawanie nowych zależności:

Przykład:

virtualenv /tmp/clean-env
source /tmp/clean-env/bin/activate
pip install --upgrade pip
pip install --requirement requirements.lock
pip install --requirement requirements.txt
pip freeze > requirements.lock

Ten sposób aktualizacji zapewnia, że nie zostaną zaktualizowane zależności innych pakietów. Aktualizacja wszystkich zależności zawsze niesie ze sobą ryzyko, że któryś z nich będzie niekompatybilny i spowoduje problemy. Dodając nowy pakiet chcemy skupić się tylko na nim, aby nie komplikować sobie zadania. Aktualizację reszty (jeżeli jest konieczna) możemy wykonać jako osobne zadanie.

Aktualizowanie wszystkich zależności do najnowszych wersji

Przykład:

virtualenv /tmp/clean-env
source /tmp/clean-env/bin/activate
pip install --upgrade pip
pip install --requirement requirements.txt
pip freeze > requirements.lock
kbeker commented 6 years ago

:+1:

dybi commented 6 years ago

@cameel, teraz wydaje mi si≥ę to oczywiste, ale chyba w sekcji:

Dodawanie nowych zależności:

warto wspomnieć o dodaniu nowej zależności również do reuirements.txt

cameel commented 6 years ago

Zaktualizowane.

Zmieniłem też trochę instrukcje: po zainstalowaniu pakietów z requirements.lock można po prostu zainstalować pakiety z requirements.txt zamiast instalować je ręcznie.

dybi commented 6 years ago

@cameel ,

Dodaj nowe pakiety do requirements.txt

Zainstaluj ręcznie, za pomocą pipa pakiety, które chcesz dodać

wydaje się, że nie trzeba już ręcznie instalować ;)

cameel commented 6 years ago

Racja. Wywalone. Byłem przekonany, że to usunąłem z opisu. Dzięki za wyłapanie tego.

rwrzesien commented 6 years ago

Może warto dodać info o konieczności dodania --find-links https://builds.golem.network/simple/pyelliptic do requirements.lock ?

cameel commented 6 years ago

To powinno być dodawane automatycznie. Jeżeli nie jest to albo potrzebujemy użyć jakiejś dodatkowej opcji żeby było albo, w najgorszym wypadku, zrobić prosty wrapper na pip freeze, który je doda.

cameel commented 5 years ago

@dybi Twoje pytanie jest związane z tematem, więc odpowiem tutaj

jest jakiś powód dla którego w plikach requirements.txt wersję golem-messages podajemy przez taga, a w requirements-lock przez commit?

tl;dr Bo tak jest prościej aktualizować requirements.lock i taki requirements.lock jest "good enough" dla naszych potrzeb.

requirements.txt podaje tylko top-levelowe zależności. Wersję podajemy tylko wtedy kiedy wiemy, że z innymi wersjami kod nie działa. Co do golem-messages - Concent praktycznie zawsze wymaga dostosowania pod konkretną wersję i będzie działać tylko z tą wersją, a więc ją podajemy. Ponieważ golem-messages nie jest na PyPI, wersję możemy zahardkodować jedynie przez gitowego taga.

requirements.lock zawiera wszystkie zależności i zawsze z zahardkodowanymi wersjami (nawet jeżeli nie są to jedyne wersje, z którymi działa) - po to aby wszyscy pracowali i testowali z dokładnie tym samym środowiskiem. Aby mieć pewność, że zawsze używamy absolutnie tego samego kodu, trzeba by dla każdego pakietu zahardkodować jego ID commitu. Inaczej nigdy nie mamy pewności, że instalujemy dokładnie to samo - w PyPI można zauploadować nowy pakiet z tą samą wersją; w gicie również tagi da się przestawiać. Niektóre narzędzia do zarządzania zależnościami (np. pipenv albo npm) z tego właśnie powodu zapisują nie tylko wersję, ale i hash zainstalowanej paczki.

W praktyce takie zmiany są rzadkie, a kiedy wystąpią, są zwykle pożądane (jeżeli ktoś zdecydował się zmienić już otagowany kod lub pakiet, pewnie był z nim jakiś spory problem), więc nam wystarczy hardkodowanie wersji/taga. Tak robimy dla pakietów z PyPI. W przypadku kodu z githuba też to by wystarczyło, ale pip freeze wypisuje commit. Żeby mieć tagi w obu miejscach musielibyśmy przetwarzać wyjście z pip freeze, co komplikuje aktualizowanie pliku requirements.lock.

Generalnie, jeżeli męczy cię nasz requirements.lock/requirements.txt, proponuję abyśmy przeszli na pipenv. Proponowałem to już kilka razy, ale nie widziałem specjalnego entuzjazmu dla tego pomysłu więc póki co stosujemy konwencję opisaną w tym issue.