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_scriptsjest 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.txtpowinien 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
urlwsetup.pya 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.


