Zespół gBlipa się rozszerza :)

gBlip LogoPrace nad nową wersją 0.1.5 gBlipa wreszcie nieco przyspieszą. Chcę serdecznie powitać nowego członka zespołu deweloperskiego. Witaj Vigrid na pokładzie! :)
Wczoraj odbyliśmy wstępną sesję pair-coding, z której wyszło kilka ciekawych wniosków. Po pierwsze, kod gBlipa nie należy do najczytelniejszych i eleganckich. Doszliśmy do wniosku, że to co do tej pory pisałem samemu wymaga pewnego refaktoringu, aby potem było łatwiejsze w utrzymaniu. Druga sprawa to fakt, że kod wymaga posprzątania - czyli usunięcia nieużywanych fragmentów. Byłem sam zdziwiony, jak dużo zostawiłem nieużywanego kodu. To pewnie zasługa tego, że chciałem jak najszybciej zrobić coś w miarę używalnego. :) Kolejny wniosek tyczy się samego Pythona - jest to bardzo wygodny język, który pozwala na dość swobodne kodowanie, ale także dość niechlujne. Postanowiliśmy wspólnie wypracować styl i konwencje kodowania w Pythonie, aby kod nie wyglądał miejscami jak bagno. W Pythonie najbardziej brakuje mi dobrej enkapsulacji, co prowadzi do powstawania różnych dziwnych konstrukcji. Podczas wspólnej sesji wyszło na jaw, że np. w ogóle nie korzystam z “prywatnych” pól klasy. O kwiatki w takim przypadku nie trudno. Także kodując w Pythonie trzeba się “trzymać za mordę”. :) Tyle jeśli chodzi o wnioski.

Świeże spojrzenie Vigrida na moje wypociny dało mi kolejną lekcję pokory. :) Mam nadzieję, że teraz wspólnymi siłami doprowadzimy gBlipa do porządku i jego rozwój nieco przyspieszy.

Dzięki Vigrid za dołączenie do teamu! :D

Lista wiadomości - problemy i rozwiązania

Miałem szczerą chęć wypuścić kolejną oficjalną wersję gBlipa jeszcze w tym tygodniu, czyli przed moim kolejnym wyjazdem do UK. Niestety, napotkałem na problem wymagający dość dużo pracy programistycznej. Mowa o liście wiadomości, a konkretnie o możliwości klikania na linki w tychże wiadomościach (czy np. na ksywki użytkowników).

Problem

W obecnej wersji gBlipa lista wiadomości funkcjonuje jako widżet gtk.TreeView ze źródłem danych gtk.ListStore. Jest to bardzo wygodna kontrolka, ale (o ile się nie mylę) niewystarczająca dla gBlipa. Miałem cichą nadzieję, że jest to komponent mocno konfigurowalny, ale akurat wspomnianych wymagań nie spełnia. Okazuje się, że elementy znajdujące się w komórkach listy nie mają obsługi klikania. Po prostu są głuche na zdarzenia myszy, czy ogólnie na jakiekolwiek inne zdarzenia. Elementy te, zwane gtk.CellRendererXxxx (gdzie Xxxx oznacza typ wyświetlanej zawartości) potrafią tylko rysować zawartość. Przynajmniej tak to wygląda na dzisiejszy stan mojej wiedzy. Nie widziałem też innej aplikacji, która umiałaby jakoś sobie z tym ograniczeniem poradzić. Być może można napisać własny CellRenderer z potrzebną funkcjonalnością, ale ja nie potrafię tego zrobić. Z tego też powodu nadeszła dość poważna decyzja - trzeba przepisać listę wiadomości od nowa.

Proponowane rozwiązanie

Postanowiłem zrezygnować całkowicie z używania TreeView na rzecz mieszaniny innych widżetów. Myślę tutaj o gtk.Table z dwoma kolumnami na (1) awatar + (2) wiadomość i n-wierszami reprezentującymi kolejne wiadomości. Awatar będzie wyświetlany przez zwykły gtk.Image, natomiast samą wiadomość planuję wyświetlać za pomocą kontrolki gtk.TextView. Obawiam się jednej rzeczy związanej z tym rozwiązaniem - że będzie dość mało wydajne i pamięciożerne. Widżet gtk.TextView jest dość “ciężkim” narzędziem, więc może dość mocno obciążyć program. Czas oczywiście zweryfikuje moją tezę… Póki co nie mam innego pomysłu.

Konsekwencje

Jak pisałem na początku, chciałem wypuścić wersję 0.1.4 jeszcze w tym tygodniu. Z powodu dość drastycznych zmian w kodzie gBlipa postanowiłem wypuścić wersję 0.1.4 bez wsparcia dla klikania linków. W ten sposób każdy będzie mógł korzystać z tej w miarę stabilnej wersji, kiedy ja będę walczył z napisaniem od nowa listy wiadomości. Zatem możliwość klikania linków zostaje oficjalnie przesunięta do wersji 0.1.5, kiedy będzie napisany nowy komponent listy wiadomości. Jutro zostanie wypuszczona nieco zubożona (względem planowanej) wersja 0.1.4 programu gBlip, a prace nad kolejną wersją ruszą już w poniedziałek (jeśli dam radę).

PS. Jeśli ktoś z Was ma inny pomysł jak rozwiązać powyższy problem - walcie śmiało w komentarzach, na blipie czy po prostu emailem.

Projekt gBlip startuje

blip64.pngWreszcie znalazłem chwilkę czasu aby zabrać się za to, co chciałem już zacząć parę dni temu. A cóż to takiego? Postanowiłem, w ramach kolejnego etapu nauki Pythona, napisać klienta desktopowego Blipa. Wiem, że istnieje już napisany w Javie przez Serafina Blipper, który już teraz robi duże wrażenie. Mimo tego chcę napisać własny program służący do komunikacji przez platformę Blipa, ale napisany w Pythonie z użyciem biblioteki PyGtk. Nazwę programu podpowiedział Hadret, a jest nią po prostu: gBlip. Użycie biblioteki Gtk ma swój niezaprzeczalny plus - integracja ze środowiskiem GNOME czy Xfce. Do GNOME’a przylgnąłem już na długi czas, więc wybór był dla mnie oczywisty.

Teraz parę zdań na temat aktualnego stadium projektu. Jestem w fazie planowania i projektowania interfejsu. Jeśli chodzi o samą komunikację z serwerem Blipa to załatwi ją biblioteka BlipPy, którą napisałem parę dni temu i udostępniłem na portalu SourceForge.net. Tak samo się stanie oczywiście z gBlipem - będzie to projekt z otwartym kodem. Na pewno będę potrzebował pomocy od Was - potencjalnych użytkowników tego programu. Na początku chodzi o sam interfejs programu. Chciałbym od Was usłyszeć uwagi i pomysły z nim związane.

Projekt UI

Póki co mogę Wam pokazać makietę, która docelowo będzie interfejsem gBlipa:

gBlip - szkielet UI (1)

Przypominam, że gBlip korzysta z GTK+ więc wygląd programu bedzie się różnił w zależności od wybranej skórki GTK. Powyższy screen zrobiłem, jak miałem ustawioną dość minimalistyczną skórkę Rezlooks.

Kilka słów o UI

Zdecydowałem się na umieszczenie pola wpisywania wiadomości nad listą wiadomości - tak jak jest to na stronie Blipa. Chciałbym uniknąć nieco schzofrenicznej sytuacji, kiedy w jednym miejscu wiadomości wpisuje się u dołu, a w innym na górze. Ponieważ autorzy Blipa postanowili, że będzie to góra - nie zamierzam tego zmieniać. Wydaje mi się, że wszystkim będzie łatwiej, jak będą spójne zasady obsługi obu kanałów komunikacji.

Druga sprawa to tzw. sidebar, czyli pasek boczny z dostępnymi widokami. Po rozmowie z Hadretem doszliśmy do wniosku, że najlepiej będzie dać użytkownikowi w tym przypadku wybór - albo lewa strona albo prawa. Także zaznaczam, że będzie opcja, która umożliwi przerzucenie sidebara na drugą stronę okna.

W pierwotnym projekcie, który namalowałem sobie zwyczajnie na kartce miałem jeszcze jeden element. Pod listą wiadomości miał znaleźć się mini panel z informacjami o użytkowniku zaznaczonej wiadomości (nie mylić z górnym panelem aktualnie zalogowanego). Póki co zrezygnowałem z tego ficzera. Jeśli uważacie, że byłby pomocny/potrzebny napiszcie o tym w komentarzach. Wtedy znajdzie się w którejś z wersji gBlipa.

Prośba o feedback

Na koniec prośba do Was wszystkich. Jeśli macie jakieś uwagi do powyższego projektu proszę napiszcie o nich w komentarzach. Jeśli jest wszystko okay to też napiszcie. Zawsze dobrze wiedzieć, że ktoś zgadza się z moimi wypocinami. Oczywiście chętnie przyjmę nowe pomysły dotyczące gBlipa. :)
PS. Tutaj tego nie widać, ale oczywiście będzie ikonka w tray’u. :) Jeszcze nie myślałem o jej funkcjonalności dokładnie. Może jakieś pomysły? :)

BlipPy - biblioteka pythonowa do Blipa

BLipPyParę dni temu postanowiłem pouczyć się czegoś nowego. Padło na polecanego mi przez wielu znajomych Pythona. Ale jak to ze mną bywa nie umiałem uczyć się “na sucho” i musiałem znaleźć sobie jakiś cel. Postanowiłem zatem napisać prostą bibliotekę komunikacyjną, która umożliwia interakcję z serwisem Blip.pl. Dlaczego akurat Blip? Po pierwsze go używam, a po drugie dowiedziałem się, że ma API. I tak oto powstała biblioteka obsługująca Blipa dla Pythona. Nazywa się BlipPy.

Z czym to się je?

Jedzenie należy zacząć od zassania samej biblioteki. Aktualna wersja, czyli 0.1, jest dostępna w repozytorium subversion. Póki co zawiera jedynie jedną klasę o nazwie Communicator, która zapewnia komunikację z Blipem poprzez API. W planach wersji 0.2 jest napisanie innej klasy, która będzie zarządzała danymi zasysanymi z Blipa. Będzie ona najprawdopodobniej użyta do napisania klienta desktopowego Blipa (kolejny etap mojej nauki). Narazie jest tylko komunikacja - powiedzmy - niskopoziomowa.
Aby pobrać bibliotekę należy mieć zainstalowanego klienta subversion i wydać następującą komendę:

svn co https://blippy.svn.sourceforge.net/svnroot/blippy blippy

Biblioteka jest mała i zawiera się w jednym pliku o nazwie blippy.py. Wystarczy go umieścić w katalogu naszej aplikacji i zaimportować. Należy także doinstalować moduł cjson, który jest używany przez bibliotekę do obsługi formatu JSON. W dalszej części pokrótce opiszę, jak używać BlipPy’ego. Nie będzie to syntetyczny opis wszystkich metod, gdyż do tego lepsze będą komentarze opisujące metody. Tutaj tylko parę przykładów obrazujących jak zacząć biblioteki używać. Zaczynamy…

Inicjalizacja

Do komunikacji z Blipem, jak wspomniałem, służy klasa Communicator. Tak tworzymy jej instancję:

import blippy

com = blippy.Communicator("user", "password")

Za pomocą powyższego kodu zostanie utworzony komunikator uwierzytelniony, czyli działający w kontekście danego użytkownika serwisu Blip.pl. Jako trzeci parametr można podać tzw. user-agent (czyli jak się przedstawiamy serwerowi Blipa). Można także w ogóle pominąć parametry i wtedy komunikator będzie anonimowy. Pamiętajcie jednak, że wiele operacji na zasobach Blipa wymaga podania użytkownika i hasła.

Pobranie bliposfery

Najprostszą czynnością na Blipie jest chyba pobranie bliposfery, czyli n-ostatnich statusów użytkowników. Gdy już mamy obiekt Communicator możemy pobrać tę informację w taki oto sposób:

bliposphere = com.GetBliposphere(10)

Spowoduje to pobranie ostatnich 10 statusów bliposfery. Zmienna bliposphere będzie zawierała tablicę 10 słowników. W każdym słowniku znajduje się para klucz->wartość. Oto przykładowa zawartość pojedynczego słownika:

{
'body': u'Ha, nowiutki statusik :)',
'user_path': '\\/users\\/bayger',
'created_at': '2008-03-29 12:00:00',
'type': 'Status',
'id': 123456789,
'transport': {'name': 'sms', 'id': 2}
}

Z nazw kluczy słownika możemy wywnioskować ich zawartość. Po szczegóły zapraszam do oficjalnej dokumentacji API Blipa, gdzie podane są przykłady zwracanych wartości przez API.

Wysłanie nowego statusu

Równie prostą czynnością jest wysłanie nowego statusu na Blipa. Potrzebujemy do tego uwierzytelnionego Communicatora, a robimy to tak:

com.SendStatus("Oh hai! I iz tryng to blip somtink")

Po wykonaniu się powyższej operacji powinniśmy na kokpicie użytkownika i bliposferze zaobserwować nowy status. Dodam tylko, że metody klasy Communicator oczekują łańcuchów znaków w kodowaniu UTF-8.

Wysłanie wiadomości do użytkownika

Kolejną rzeczą, jaką udostępnia API Blipa jest wysyłanie tzw. wiadomości skierowanych do użytkownika. Nie są one tak naprawdę prywatne (każdy może je zobaczyć), ale ukazują się tylko na kokpicie adresata. Tak wysyła się wiadomość skierowaną:

com.SendMessage("nick_adresata", "wiadomość_do_adresata")

Jeśli wszystko pójdzie dobrze to adresat powinien dostać wiadomość.

Obsługa błędów

Błędy obsługiwane są standardowo, czyli za pomocą wyjątków. Jeśli coś pójdzie nie tak to dana metoda rzuci jednym z następujących wyjątków:

  • NotFoundException - gdy brak szukanego zasobu na serwerze
  • BadArgumentsException - gdy źle podaliśmy argumenty wywołania (np. w niedozwolonym formacie)
  • BadCredentialsException - gdy próbujemy zrobić coś, co wymaga uwierzytelnienia a podaliśmy zły login/hasło (lub nie podaliśmy)
  • ServerBusyException - gdy serwer jest bardzo zajęty i nie może obsłużyć naszego żądania; należy spróbować ponownie
  • BadOperationException - gdy wystąpił bliżej nieokreślony błąd

Update: Dodatkowo metody mogą rzucić wyjątkami, gdy coś na linii protokołu HTTP będzie nie tak.

Co innego udostępnia BlipPy?

Ponieważ wszystkie przykłady użycia biblioteki są dość proste wymienię tylko możliwości jakie daje w obecnym kształcie BlipPy:

  • pobieranie bliposfery i kokpitu użytkownika
  • wysyłanie i kasowanie statusów i wiadomości skierowanych
  • pobieranie informacji o obrazkach, nagraniach, linkach, filmach
  • pobieranie informacji o avatarch i tłach użytkowników
  • ustawianie avatara i tła użytkownika
  • dodawanie i usuwanie obserwowanych użytkowników
  • pobieranie informacji o użytkownikach

Co dalej?

Kolejna wersja biblioteki (0.2) będzie najprawdopodobniej udostępniała klasę zarządzającą komunikacją z Blipem. Innymi słowy będzie to podstawa do napisania klienta desktopowego dla Blipa. Jego kształt dopiero rodzi się w mojej głowie. Poza tym muszę zbadać co oferuje Python jeśli chodzi o programowanie UI. O postępach nie omieszkam powiadomić na łamach bloga. Poza tym dodam do Communicatora obsługę offsetów, które umknęły mi w czasie lektury API.

Przypominam także, że jest to mój pierwszy kod w Pythonie i, być może, nie jest on najlepszy. Starałem się wpasować w język jak tylko na daną chwilę umiałem. Chętnych proszę o testowanie i wysyłanie ewentualnych uwag, bugów, sugestii na mój adres email (patrz: strona O mnie) lub po prostu w komentarzach poniżej. Z góry za nie dziękuję!