Jak mogę uzyskać wersję zdefiniowaną w setup.py
moim pakiecie (do --version
innych celów)?
python
setuptools
elmarco
źródło
źródło
Odpowiedzi:
Zbadaj ciąg wersji już zainstalowanej dystrybucji
Aby pobrać wersję z pakietu w czasie wykonywania (o co faktycznie chodzi w pytaniu), możesz użyć:
Przechowuj ciąg wersji do użycia podczas instalacji
Jeśli chcesz przejść w drugą stronę (co wydaje się być tym, o czym inni autorzy odpowiedzi myśleli, że pytasz), umieść ciąg wersji w oddzielnym pliku i przeczytaj zawartość tego pliku
setup.py
.Możesz utworzyć version.py w swoim pakiecie z
__version__
linią, a następnie przeczytać go z pliku setup.py za pomocąexecfile('mypackage/version.py')
, aby ustawić go__version__
w przestrzeni nazw setup.py.Jeśli potrzebujesz prostszego sposobu, który będzie działał ze wszystkimi wersjami Pythona, a nawet językami innymi niż Python, które mogą wymagać dostępu do ciągu wersji:
Zapisz wersję jako jedyną zawartość zwykłego pliku tekstowego o nazwie np.
VERSION
I przeczytaj ten plik w trakciesetup.py
.Ten sam
VERSION
plik będzie działał wtedy dokładnie tak samo dobrze w każdym innym programie, nawet innym niż Python, i wystarczy zmienić ciąg znaków wersji w jednym miejscu dla wszystkich programów.Ostrzeżenie o stanie wyścigu podczas instalacji
Nawiasem mówiąc, NIE importuj swojego pakietu z pliku setup.py, jak sugeruje to w innej odpowiedzi tutaj: wydaje się, że działa on dla Ciebie (ponieważ masz już zainstalowane zależności pakietu), ale sieją spustoszenie wśród nowych użytkowników Twojego pakietu , ponieważ nie będą w stanie zainstalować pakietu bez ręcznej instalacji zależności.
źródło
execfile
działa bardzo dobrze ... ale (niestety) nie działa z Pythonem 3.with open('mypackage/version.py') as f: exec(f.read())
zamiastexecfile('mypackage/version.py')
. (Od stackoverflow.com/a/437857/647002 )przykładowe badanie:
mymodule
Wyobraź sobie taką konfigurację:
Następnie wyobraź sobie zwykły scenariusz, w którym masz zależności i
setup.py
wygląda tak:I przykład
__init__.py
:I na przykład
myclasses.py
:problem nr 1: importowanie
mymodule
podczas instalacjiJeśli
setup.py
importujesz,mymodule
to podczas konfiguracji najprawdopodobniej otrzymasz plikImportError
. Jest to bardzo częsty błąd, gdy pakiet ma zależności. Jeśli twój pakiet nie ma innych zależności niż wbudowane, możesz być bezpieczny; jednak nie jest to dobra praktyka. Powodem tego jest to, że nie jest przyszłościowe; powiedz, że jutro twój kod musi zużywać inną zależność.problem nr 2: gdzie jest mój
__version__
?Jeśli zakodujesz
__version__
na stałesetup.py
, może to nie odpowiadać wersji, którą dostarczysz w swoim module. Aby zachować spójność, umieściłbyś go w jednym miejscu i czytał z tego samego miejsca, kiedy tego potrzebujesz. Korzystanie zimport
ciebie może mieć problem nr 1.rozwiązanie: à la
setuptools
Można by użyć kombinacji
open
,exec
i zapewniają dict dlaexec
zmiennych dodają:I
mymodule/version.py
ujawnij wersję:W ten sposób wersja jest dostarczana z modułem i nie ma problemów podczas instalacji podczas próby zaimportowania modułu z brakującymi zależnościami (jeszcze do zainstalowania).
źródło
Najlepszą techniką jest zdefiniowanie
__version__
kodu produktu, a następnie zaimportowanie go stamtąd do pliku setup.py. Daje to wartość, którą możesz odczytać w uruchomionym module i masz tylko jedno miejsce, aby ją zdefiniować.Wartości w setup.py nie są instalowane, a setup.py nie utrzymuje się po instalacji.
Co zrobiłem (na przykład) w Cover.py:
UPDATE (2017): Coverage.py nie importuje się już, aby pobrać wersję. Zaimportowanie własnego kodu może uniemożliwić jego odinstalowanie, ponieważ kod produktu będzie próbował zaimportować zależności, które nie są jeszcze zainstalowane, ponieważ instaluje je plik setup.py.
źródło
__version__
w którym się znajduje, jest w jakiś sposób uszkodzony, wówczas import również zostanie uszkodzony. Python nie wie, jak interpretować tylko te instrukcje, które chcesz. @pjeby ma rację: jeśli twój moduł musi zaimportować inne moduły, mogą nie zostać jeszcze zainstalowane i będzie chaotycznie. Ta technika działa, jeśli uważasz, że import nie powoduje długiego łańcucha innych importów.pip install <packagename>
, pojawia się następujący błąd:ImportError: No module named <packagename>
. OSTRZEGAJ swoich czytelników, że nie możesz uruchamiać takich plików setup.py w środowiskach, w których pakiet nie jest jeszcze zainstalowany!Twoje pytanie jest trochę niejasne, ale myślę, że pytasz, jak je sprecyzować.
Musisz zdefiniować w ten
__version__
sposób:Następnie możesz potwierdzić, że setup.py wie o podanej wersji:
źródło
Nie byłem zadowolony z tych odpowiedzi ... nie chciałem wymagać narzędzi konfiguracyjnych ani tworzyć całego oddzielnego modułu dla jednej zmiennej, więc wymyśliłem je.
Gdy jesteś pewien, że główny moduł jest w stylu pep8 i taki pozostanie:
Jeśli chcesz być bardzo ostrożny i użyć prawdziwego parsera:
setup.py jest w pewnym sensie jednorazowym modułem, więc nie stanowi problemu, jeśli jest trochę brzydki.
Aktualizacja: dość zabawne Odszedłem od tego w ostatnich latach i zacząłem używać oddzielnego pliku w pakiecie o nazwie
meta.py
. Umieściłem tam wiele metadanych, które chciałbym często zmieniać. A więc nie tylko dla jednej wartości.źródło
ast.get_docstring()
z niektórymi.split('\n')[0].strip()
itp., Aby automatycznie wypełnićdescription
ze źródła. Jedna rzecz mniej do synchronizacjiUtwórz plik w swoim drzewie źródłowym, np. W yourbasedir / yourpackage / _version.py. Niech ten plik zawiera tylko jedną linię kodu, na przykład:
__version__ = "1.1.0-r4704"
Następnie w swoim setup.py otwórz ten plik i przeanalizuj numer wersji w następujący sposób:
Na koniec w
yourbasedir/yourpackage/__init__.py
import _version w ten sposób:Przykładem kodu, który to robi, jest pakiet „pyutil”, którym się opiekuję. (Zobacz PyPI lub wyszukiwarkę Google - stackoverflow zabrania mi umieszczania hiperłącza do niego w tej odpowiedzi).
@pjeby ma rację, że nie powinieneś importować swojego pakietu z jego własnego pliku setup.py. To zadziała, gdy przetestujesz go, tworząc nowy interpreter Pythona i uruchamiając w nim setup.py:
python setup.py
ale są przypadki, kiedy to nie zadziała. To dlatego,import youpackage
że nie oznacza odczytywania bieżącego katalogu roboczego dla katalogu o nazwie „twój pakiet”, oznacza to szukanie wsys.modules
nim klucza „twój pakiet”, a następnie robienie różnych rzeczy, jeśli go tam nie ma. Więc zawsze działa, gdy robisz,python setup.py
ponieważ masz świeży, pustysys.modules
, ale to ogólnie nie działa.Na przykład, co się stanie, jeśli py2exe wykonuje plik setup.py w ramach procesu pakowania aplikacji? Widziałem taki przypadek, w którym py2exe umieściłby nieprawidłowy numer wersji na pakiecie, ponieważ pakiet pobierał numer wersji z
import myownthing
w pliku setup.py, ale inna wersja tego pakietu została wcześniej zaimportowana podczas uruchamiania py2exe. Podobnie, co się stanie, jeśli setuptools, easy_install, dystrybucja lub distutils2 próbują zbudować Twój pakiet w ramach procesu instalowania innego pakietu, który zależy od Twojego? Następnie, czy twój pakiet jest możliwy do zaimportowania w czasie, gdy jego setup.py jest oceniany, czy też istnieje już wersja twojego pakietu, która została zaimportowana podczas życia tego interpretera Pythona, lub czy import twojego pakietu wymaga zainstalowania innych pakietów lub ma skutki uboczne, może zmienić wyniki. Miałem kilka problemów z próbą ponownego użycia pakietów Pythona, co spowodowało problemy z narzędziami takimi jak py2exe i setuptools, ponieważ ich setup.py importuje sam pakiet w celu znalezienia numeru wersji.Nawiasem mówiąc, ta technika dobrze współgra z narzędziami do automatycznego tworzenia
yourpackage/_version.py
pliku, na przykład czytając historię kontroli wersji i wypisując numer wersji w oparciu o najnowszy znacznik w historii kontroli wersji. Oto narzędzie, które robi to dla darcs: http://tahoe-lafs.org/trac/darcsver/browser/trunk/README.rst, a tutaj jest fragment kodu, który robi to samo dla git: http: // github .com / warner / python-ecdsa / blob / 0ed702a9d4057ecf33eea969b8cf280eaccd89a1 / setup.py # L34źródło
Powinno to również zadziałać, używając wyrażeń regularnych i zależnie od pól metadanych, aby mieć taki format:
Użyj poniższego na początku swojego setup.py:
Następnie możesz użyć metadanych w swoim skrypcie w następujący sposób:
źródło
Z taką strukturą:
gdzie version.py zawiera:
Możesz to zrobić w setup.py :
Nie spowoduje to żadnych problemów z zależnościami, które masz w swoim mymodule / __ init__.py
źródło
Aby uniknąć importowania pliku (a tym samym wykonywania jego kodu), można go przeanalizować i odzyskać
version
atrybut z drzewa składni:Ten kod próbuje znaleźć przypisanie
__version__
lubVERSION
na najwyższym poziomie zwracanego modułu jest wartością ciągu. Prawa strona może być ciągiem lub krotką.źródło
Istnieje tysiąc sposobów na oskórowanie kota - oto moje:
źródło
Czyszczenie https://stackoverflow.com/a/12413800 z @ gringo-suave:
źródło
Teraz jest to obrzydliwe i wymaga pewnego dopracowania (może nawet być odkryte wezwanie członka w pkg_resources, które przegapiłem), ale po prostu nie rozumiem, dlaczego to nie działa, ani dlaczego nikt nie zasugerował tego do tej pory (wyszukiwanie w Google ma nie włączyłem tego) ... zauważ, że to jest Python 2.xi wymagałoby użycia pkg_resources (westchnienie):
źródło
Chcieliśmy umieścić meta informacje na temat naszego pakietu
pypackagery
w__init__.py
, ale nie mógł, ponieważ ma zależności innych firm jako PJ Eby już wspomniano (patrz jego odpowiedź i ostrzeżenia dotyczące sytuacji wyścigu).Rozwiązaliśmy to, tworząc osobny moduł,
pypackagery_meta.py
który zawiera tylko metainformacje:następnie zaimportował metainformacje w
packagery/__init__.py
:i ostatecznie użyłem go w
setup.py
:Musisz dołączyć
pypackagery_meta
do swojego pakietu zpy_modules
argumentem konfiguracji. W przeciwnym razie nie możesz go zaimportować podczas instalacji, ponieważ w pakiecie dystrybucyjnym byłoby go brakuje.źródło
Prosty i prosty, utwórz plik o nazwie
source/package_name/version.py
o następującej zawartości:Następnie w swoim pliku
source/package_name/__init__.py
importujesz wersję, z której mogą korzystać inne osoby:Teraz możesz to założyć
setup.py
Przetestowane z Pythonem
2.7
,3.3
,3.4
,3.5
,3.6
i3.7
na Linux, Windows i Mac OS. Użyłem na moim pakiecie, który ma testy integracji i testów jednostkowych dla wszystkich tych platform. Można zobaczyć wyniki.travis.yml
iappveyor.yml
tutaj:Alternatywna wersja korzysta z menedżera kontekstu:
Możesz także używać
codecs
modułu do obsługi błędów Unicode zarówno w Pythonie, jak2.7
i3.6
Jeśli piszesz moduł Pythona w 100% w C / C ++ przy użyciu Python C Extensions, możesz zrobić to samo, ale używając C / C ++ zamiast Python.
W takim przypadku utwórz
setup.py
:Który czyta wersję z pliku
version.h
:Ale nie zapomnij utworzyć pliku,
MANIFEST.in
aby dołączyćversion.h
plik:I jest zintegrowany z główną aplikacją za pomocą:
Bibliografia:
źródło
wdrożyć pakiet na serwerze i konwencję nazewnictwa plików dla pakietów indeksów:
przykład dynamicznej konwersji wersji pip:
zdobyć:
prochowiec:
Znajdź przykład setup.py wywołuje dynamiczne dopasowanie wersji pip z git commit
źródło
Używam zmiennej środowiskowej, jak poniżej
WERSJA = 0.0.0 python setup.py sdist bdist_wheel
W setup.py
Do sprawdzenia spójności z wersją pakera używam poniższego skryptu.
źródło