Kawałek napisanego pythonowego kodu nieraz warto zamknąć jako bibliotekę i opublikować. W realizowanych czynnościach nie ma niczego trudnego ale ... wystarczy nie robić tego 2-3 miesiące, by nie pamiętać wszystkich kroków. Stąd ta notka.
Opisuję scenariusz, w którym publikuję i utrzymuję kod, który
będzie można instalować przez easy_install
(albo pip
) i którego
źródła będą dostępne dla wszystkich zainteresowanych.
Przygotowanie
Kod przeznaczony do opublikowania szykuję w formie opisanej w tym
artykule - tj. robię sensowną strukturę katalogów, tworzę
setup.py
i nadaję całości unikalną nazwę (co najłatwiej osiągnąć
używając namespace
, dlatego dla świętego spokoju nazywam swoje
moduły mekk.costam
).
Jeżeli moduł zawiera nie tylko kod ale też gotowe
skrypty/programy, odpowiednio je deklaruję. Tu
najwygodniejsza jest umieszczona w ramach setup.py
deklaracja taka jak:
setup(# ... # .... entry_points = """ [console_scripts] greader2org = mekk.feeds.greader2org.run:main """, # ..... )
gdzie z lewej strony mam publiczną nazwę skryptu (warto zadbać o jej
unikalność, będzie wrzucana do PATH
i nie powinna się z niczym
kłócić) a z prawej nazwa funkcji do uruchomienia (tu ma zostać
uruchomiona funkcja main
z modułu mekk.feeds.greader2org.run
czyli
z pliku mekk/feeds/greader2org/run.py
, przykład pochodzi z mojego
skrypciku wspomagającego Google Readera który akurat
jeszcze czeka na porządną publikację). Skryptów może być wiele (w
kolejnych wierszach) a w przypadku programów okienkowych do dyspozycji
jest [gui_scripts]
.
Alternatywą jest opisana w poprzednim artykule opcja
scripts
, od czasu jego napisania doszedłem do wniosku, żeconsole_scripts
jest wygodniejsze (zapewnia min. jednolity sposób uruchamiania pod Linuksem i pod Windows).
Wreszcie, kod trzymam w DVCSowym repozytorium (używając indywidualnego repozytorium dla całego modułu). Stosuję Mercuriala i publikuję na BitBuckecie, w przypadku Gita i GitHuba proces będzie bardzo podobny.
Rejestracja
... czyli publikacja pierwszej wersji.
Ostatni przegląd
Dokładnie przeglądam setup.py
, zwracając uwagę na mało w
wewnętrznym kodzie istotne opcje takie jak classifiers
,
description
, license
, keywords
, author
, author_email
...
Równie uważnie oglądam README.txt
(które będzie publicznym opisem
modułu), załączam właściwe LICENSE.txt
(dyskusję o tym czy BSD, Artistic, LGPL, czy
może GPL tym razem pominę).
Plik
README.txt
powinien być napisany w formacie ReStructuredText, bez odwołań do zewętrznych plików i bez niestandardowych rozszerzeń.
Sprawdzam, czy kod się poprawnie buduje:
$ python setup.py bdist_egg
Uruchamiam też testy (o ile je mam), próbuję uruchomić skrypty (o ile występują).
Wreszcie, ustawiam sensowne version
w setup.py
(najczęściej1.0.0
lub 0.1.0
) i taguję moduł tagiem zgodnym z tym
numerem wersji.
Pierwsza publikacja źródeł
Odklikuję stworzenie nowego repozytorium na BitBuckecie
(wybieram z menu Repositories/Create new
i wypełniam trzy pola):
W lokalnym pliku .hg/hgrc
tworzę alias wskazujący na to repozytorium, np.
[paths] bitbucket = https://Mekk@bitbucket.org/Mekk/mekk.greader/
wreszcie, wgrywam źródła i historię projektu na publiczny serwer:
$ hg push bitbucket
Jeżeli chcę używać strony z BitBucketa jako głównej strony kontaktowej dla innych użytkowników, wpisuję adres repozytorium jako
url
wsetup.py
a także wspominam go wREADME.txt
. Taką zmianę oczywiście także commituję i pcham na serwer.
Od tego momentu kod źródłowy jest publicznie widoczny i dostępny dla innych.
Rejestracja i pierwsza publikacja na PyPi
Tworzę plik ~/.pypirc
o treści:
[distutils] index-servers = pypi [pypi] username:TuMojeUserName password:TuMojeHaslo
wpisując swoje dane z PyPi (oczywiście przed publikacją pierwszego modułu musiałem się zarejestrować).
Niestety hasło trzeba podać jawnie, jakąś formą zabezpieczenia jest umieszczenie pliku na szyfrowanym dysku i podsymlinkowanie.
Następnie w katalogu publikowanego modułu wykonuję komendę:
$ python setup.py register
której efektem jest zarejestrowanie modułu na PyPi (z opisem i atrybutami
wynikającymi z ustawień w setup.py
).
Polecenie register
może zakończyć się błędem, np.
Server response (400): Invalid classifier "Operating System :: Any"
w takim wypadku poprawiam zgłoszony problem i próbuję ponownie.
Wreszcie, publikuję kod:
$ python setup.py sdist upload
Od tego momentu użytkownicy mogą instalować moduł przy pomocy
easy_install
(a także pip
, zc.buildout
i innych podobnych
narzędzi), jest też widoczny w najważniejszym indeksie modułów
pythonowych.
Weryfikacja
Na koniec weryfikuję, czy wszystko wygląda i działa poprawnie.
Najpierw sprawdzam, jak wygląda strona na PyPi. Trzeba to zrobić,
bo ewentualne błędu w składni opisu (tj. niepoprawny ReST w README)
nie są przez register
zgłaszane a jedynie powodują wyświetlanie
preformatowanego tekstu zamiast tytyłów, wcięć itp.
Próbuję też próbnie zainstalować nowo stworzony moduł, np.
$ mkvirtualenv test $ easy_install mekk.xmind
Aktualizacje
Aktualizacje po dokonaniu zmian są dużo mniej kłopotliwe, mam do wykonania tylko kilka prostych czynności (oczywiście już po wprowadzeniu zmian w kodzie i po ich przetestowaniu).
Przeglądam README.txt
i ewentualne inne pliki dokumentacyjne - sprawdzając,
czy są nadal aktualne.
Poprawiam numer wersji w setup.py
, commituję tą poprawkę i
nakładam tag zgodny z numerem wersji.
Publikuję zmiany źródeł:
$ hg push bitbucket
Publikuję nową wersję na PyPi:
$ python setup.py sdist upload
Jeżeli nastąpiły zmiany w README
albo w opisowych polach setup.py
, koryguję
opis na PyPi:
$ python setup.py register
i to już wszystko.
Powiadomienia
Ostatnim krokiem jest opublikowanie informacji o nowej bibliotece czy nowej jej wersji.
Właściwe miejsce zależy od tego czym właściwie jest komponent - może to być wpis na blogu, ogłoszenie na forum, list na liście mailowej, wreszcie - notka na usenetowej grupie comp.lang.python.announce
.