Debugowanie Django w Winpdb

Django posiada wbudowaną stronę służącą do zgłaszania błędów, dzięki której można zidentyfikować źródło błędu. Pojawia się zawsze gdy wystąpi nieobsłużony wyjątek, pod warunkiem, że w ustawieniach opcja DEBUG przyjmuje wartość True. Każdy developer Django pewnie widział ją nie raz. Jednak błędy oprogramowania, to nie tylko wyjątki, ale także niepoprawnie wyświetlane dane - tego Django już nie wyłapie. Czasami też zdaża się, że informacja ze strony błędu, to za mało, żeby zidentyfikować błąd. Można wtedy posiłkować się funkcją print, której zwróconą wartość widać w konsoli, na której został uruchomiony serwer developerski. Jest to jednak przydatne przy naprawie drobnych błędów, gdzie szybko można zorientować się co może być ich przyczyną. Korzystanie z print na pewno nie jest debugowaniem z prawdziwego zdarzenia. Żeby dokładnie prześledzić działanie stworzonego skryptu, najlepiej posłużyć się narzędziem przeznaczonym do tego. Takim narzędziem jest Winpdb - graficzna wersja pdb (Python Debugger).

Debugowanie aplikacji stworzonych w Django jest prostsze, niż mogłoby się to wydawać. Do prezentacji posłużyłem się bardzo prostym, testowym projektem:

test_project/
|-- __init__.py
|-- manage.py
|-- settings.py
|-- test_app
|   |-- __init__.py
|   |-- models.py
|   `-- views.py
`-- urls.py

Kod który chcę prześledzić w poszukiwaniu błędów znajduje się w pliku test_app/views.py

def test_view(request):
        a = 1
        b = 3
        c = a + b

        print c

Pierwszym krokiem do prześledzenia skryptu, jest uruchomienie developerskiego serwera Django z poziomu Winpdb. Najpierw wybieramy "File -> Launch" W oknie które się pojawi,trzeba wpisać polecenie, które uruchomi serwer developerski.

Launch command

W moim przypadku było to:

/home/jaro/strony/test_project/manage.py runserver --noreload

Opcja noreload umożliwia debugowanie i zatrzymywanie się wykonywania skryptu w breakpointach. Skrypt zostaje załadowany i żeby go uruchomić trzeba kliknąć na ikonkę play. Spowoduje to uruchomienie serwera developerskiego Django. W konsoli wyświetli się komunikat serwera.

Konsola Winpdb

Do zatrzymania wykonywania skryptu w wybranym miejscu, można posłużyć się breakpointem. W pierwszej kolejności trzeba otworzyć plik, w którym breakpoint będzie ustawiony (File -> Open Source). Plik załaduje się do okna "Source".

Breakpoint

Breakpoint ustawia się poprzez kliknięcie na linię kodu, która z kolei zostanie wyróżniona czerwonym kolorem, tak jak jest to widoczne na powyższym rysunku.

Już wszystko jest gotowe do debugowania, teraz wystarczy wejść w przeglądarce na stronę, która uruchomi interesujący nas widok (np. http://localhost:8000/). Strona nie załaduje się, a jak przejdziemy do debuggera, to zobaczymy skrypt zatrzymany we wskazanej wcześniej linii.

Debugowanie skryptu

W widocznych oknach można zobaczyć aktualne wartości zmiennych, uruchomione wątki, stos, konsolę oraz kod źródłowy, którego kolejne linie można wykonywać interaktywnie, korzystając z przycisków w pasku narzędzi.

Internet przez komórkę pod Linuxem

Zazwyczaj jak korzystam z Internetu na laptopie, to albo w domu, albo gdzieś gdzie jest sieć bezprzewodowa. Czasami jednak pojawiają się sytuacje, w których potrzebuję dostępu do Internetu w miejscach, w których nie łapię żadnej sieci bezprzewodowej i nie ma gdzie się wpiąć kablem. Z pomocą przychodzi GPRS.

Co jest potrzebne żeby uruchomić GPRS pod Linuxem:

  1. telefon, który obsługuje tę technologię komunikacyjną
  2. włączoną opcję połączeń z Internetem przez kabel USB (w SE k800i ustawienia->łączność->USB->Włącz)
  3. kabel do telefonu lub blutetooth (przez IrDA chyba też się da)
  4. skompilowany i załadowany moduł jądra do obsługi modemów przez USB (USB_ACM)
  5. program global 3g

Modem w jajku

Po podłączeniu telefonu do komputera przez kabel, w katalogu /dev, powinny znajdować się pliki ACM*. Jeżeli są, to znaczy że moduł USB_ACM jest załadowany. W przeciwnym wypadku, najpierw można spróbować załadować go ręcznie (być może z jakiegoś powodu nie powiodło się automatyczne ładowanie):

# modprobe cdc_acm

Jeżeli to nie pomogło, to trzeba skompilować moduł USB_ACM. Nie będę opisywał szczegółowo jak to się robi, bo to temat na osobny wpis. W Internecie jest dużo informacji o kompilacji jądra. Podpowiem tylko gdzie i jakiej opcji w menu konfiguracyjnym trzeba szukać:

Location:
    -> Device Drivers
      -> USB Support
        -> Support for Host-side USB 
          -> USB Modem (CDC ACM) support

Po skompilowaniu modułu, powinien on automatycznie ładować się gdy telefon zostanie podłączony do komputera.

Połączenie ze światem

Czas na punkt kulminacyjny. Do połączenia użyłem świetnego programu Global 3G Jego wielkimi zaletami są wbudowane ustawienia do najpopularniejszych operatorów sieci komórkowych (w tym także polskich) oraz sterowniki do wielu telefonów. W konfiguracji programu wybrałem swojego operatora z listy dostawców, natomiast z listy urządzeń odpowiedni telefon. Posiadam Sony Ericsson k800i, który widnieje na liście obsługiwanych urządzeń, ale jak go wybrałem, to nie łączył się z Internetem. Dopiero jak wybrałem opcję "Sony Ericsson - Standard Models (2)", to zadziałało. W przypadku połączenia telefonu przez kabel, jako port trzeba wybrać USB -> ACM0 lub ACM1 jeżeli nie zadziała. Piszę tylko o kablu, bo nie próbowałem łączyć się przez blutetooth.

To by było na tyle jeśli chodzi o konfigurację. Wystarczy kliknąć "połącz" i wrota Internetu otworzą się przed nami. Wolnego, bo wolnego, ale w sytuacji awaryjnej wystarczy. Polecam wyłączyć w przeglądarce pobieranie obrazków, animacji, javascriptu i apletów javy. Niestety jest jeden szkopuł. Global 3G w darmowej wersji przed nawiązaniem połączenia z Internetem, zmusza nas do odczekania 6 minut (tylko za pierwszym razem w ciągu pojedynczego uruchomienia programu) i nie pamięta konfiguracji. Jeżeli chcemy pozbyć się tej uciążliwości, to trzeba zakupić od autora płatną wersję za 29 zł. Wydaje mi się, ze nie są to duże pieniądze i czuję, że fajnie jest zapłacić komuś drobną kwotę za dobrze wykonaną robotę.

Mobilność jest ekstra

Ostatnio przedłużyłem umowę z Orange i dzięki temu za jedyne 19 zł zakupiłem Sony Ericssona k800i. Wcześniej posiadałem (podobno kultowego) NEC-a e616v, który jest już trochę stary, ale cenię go za łatwość obsługi i solidność wykonania. Niemniej jednak miał trochę ograniczeń, typu mało funkcjonalny bluetooth, który służył tylko do obsługi bezprzewodowej słuchawki, czy MIDP niby w wersji 2.0, ale musiałem sporo nakombinować się, żeby zainstalować na nim jakieś aplikacje. Jak już jakąś udało się zainstalować, to zazwyczaj w wersji okrojonej.

Przy wyborze telefonu istotna dla mnie była obsługa protokołu SyncML, ponieważ potrzebuję możliwości synchronizacji Kalendarza Google z kalendarzem w telefonie. Oprócz tego dzięki temu protokołowi można eksportować na serwer kontakty, zadania i notatki. Ogólnie przydatne przy zmianie telefonu, albo po prostu jako backup.

Aplikacje które zainstalowałem

  • Fotokody - program do obsługi fotokodów
  • Gmail - klient poczty Gmail
  • Google Maps - z ciekawszych możliwości, to pokazywanie aktualnej lokalizacji, nawet jeżeli telefon nie posiada GPS-a
  • MidpSSH - klient SSH i Telnet
  • Opera Mini - mobilna wersja świetnej przeglądarki internetowej. Z powodzeniem zastępuje wbudowaną w telefon przeglądarkę stron WWW
  • Talkonaut - aplikacja umożliwia dzwonienie przez VoIP, korzystając z EDGE, 3G, WIFI. Ja używam go jako klienta Jabbera.
  • Wordmax - mobilny słownik Polsko-Angielski i Angielsko-Polski

Synchronizacja z Google Calendar

Niestety sam Google Calendar jeszcze nie umożliwia synchronizacji z innymi urządzeniami niż BlackBerry, iPhone i telefony z Windows Mobile. Musiałem więc szukać innych rozwiązań. Najpierw natknąłem się na GooSync. Początkowo wszystko działało jak należy, ale po około tygoniu postanowiłem szukać czegoś innego, bo, krótko mówiąc, przestało działać. Wybór padł na Schedule World, który oprócz kalendarza, umożliwia synchronizację zadań, notatek i książki adresowej. Możliwa jest także synchronizacja kontaktów z Gmaila. Życie stało się łatwiejsze, odkąd swój kalendarz mam w kieszeni i mogę dodawać wydarzenia zarówno przy pomocy komputera jak i telefonu.

Podsumowując, mobilność jest ekstra - mogę szybko zorientować się gdzie jestem przy pomocy Google Maps, sprawdzić pocztę wszędzie gdzie jest zasięg GPRS, sprawdzać rozkłady jazdy autobusów i pociągów przy pomocy Opery Mini. Nasuwa się jedno pytanie - ile to kosztuje? To zależy od operatora. Orange pobiera 25 groszy za 50 kB pobranych danych. Gdy z internetu korzysta się często, warto wykupić pakiet 5 MB za 5 zł. 5 MB w zupełności wystarczy do synchronizacji kalendarza i przeglądania kilku stron od czasu do czasu.

Wysyłanie maila z konsoli - skrypt Pythona

Jakiś czas temu postawiłem subversion na serwerze developerskim, który służył do testowania aplikacji którą piszę. Chciałem żeby informacje o każdym commit-cie były wysyłane na maila. Postanowiłem zrobić to przy pomocy skryptu w Pythonie.

import smtplib
import getopt
import email.Message
import sys

def main(argv):
    opts, args = getopt.getopt(argv, "u:p:s:h:t:r:t:", ["server=", "port=", "sender=", password=", "to=", "subject=", "text="])
    for opt, arg in opts:
        if opt in ["-u", "--server"]:
            serverURL = arg
        elif opt in ["-p", "--port"]:
            port = arg
        elif opt in ["-s", "--sender"]:
            sender = arg
        elif opt in ["-h", "--password"]:
            password = arg
        elif opt in ["-t", "--to"]:
            to = arg
        elif opt in ["-r", "--subject"]:
            subject = arg
        elif opt in ["-t", "--text"]:
            text = arg

    message = email.Message.Message()
    message["To"]      = to
    message["From"]    = sender
    message["Subject"] = subject
    message.set_payload(text)
    if port:
        mailServer = smtplib.SMTP(serverURL, port)
    else:
        mailServer = smtplib.SMTP(serverURL)
    mailServer.ehlo()
    mailServer.starttls()
    mailServer.ehlo()
    mailServer.login(sender, password)
    
    mailServer.sendmail(sender, to, message.as_string())
    mailServer.quit()

Wiadomość ma wysyłać się z serwera SMTP na gmailu, więc istotna jest tu część kodu:

mailServer.ehlo()
mailServer.starttls()
mailServer.ehlo()

Żeby wysłać maila, wystarczy wpisać polecenie: python /srv/mail.py --server=smtp.gmail.com --port=587 --sender=<adres_nadawcy> --password=<hasło_nadawcy> --to=<adres_odbiorcy> --subject="temat" --text="tresc wiadomosci"

Rozwijanie nazw w standardowej konsoli pythona

Konsola Pythona najczęściej służy mi do testowania drobnych fragmentów kodu. Zdarzało się że zapominałem jak nazywa się jakaś metoda danej klasy, albo chciałem szybko zobaczyć, jakie metody dana klasa udostępnia. Odkąd włączyłem rozwijanie nazw, które działa Unixopodobnie (po naciśnięciu klawisza Tab), nie stanowi to żadnego problemu. Sprawa jest bardzo prosta. Wystarczy w katalogu domowym utworzyć plik .pythonrc:

try:
    import readline
except ImportError:
    print "Brak modułu readline"
else:
    import rlcompleter
    readline.parse_and_bind("tab: complete")

Na koniec należy ustawić zmienną środowiskową:

export PYTHONSTARTUP=~/.pythonrc

Żeby nie robić tego za każdym razem po ponownym uruchomieniu systemu, wystarczy dopisać powyższą linijkę kodu do pliku .bashrc znajdującego się w katalogu domowym.

Zenity - bash i okna GTK

Jakiś czas temu przy aktualizacji paru pakietów, zwróciłem, nie wiem czemu, uwagę na jeden z nich. Jego nazwa nic mi nie mówiła, przeczytałem więc krótki opis, który zachęcił mnie do "googlowania". Mowa o Zenity, umożliwiającym uruchamianie zdefiniowanych okienek GTK o określonej funkcjonalności, z przeznaczeniem do wykorzystania w skryptach bash-a. Nie będę opisywał dostępnych okienek, bo to można wyczytać z dokumentacji. Skupię się zatem na konkretnym przykładzie wykorzystania Zenity.

Na szybko napisałem skrypt, który zastąpił moją metodę pomniejszania obrazków z wykorzystaniem z linii poleceń, opisaną w jednym z wcześniejszych wpisów.

#!/bin/bash

files=(`zenity --file-selection --title "Wybierz pliki do zmniejszenia" --multiple --separator " "`)

if [ $files == "" ]
then
        exit
fi

fnum=${#files[@]}
percent=$[100/$fnum]
current=$percent

scale=(`zenity --scale --title "Rozmiar miniatury" --text "Wybierz maksymalny rozmiar wysokości lub szerokości - obraz będzie zmniejszony proporcjonalnie" --max-value 1024`)

if [ $scale == 0 ]
then
        exit
fi

(for file in ${files[*]};
do
        type=`file -b -i $file`
        if [ ${type:0:5} == 'image' ]
        then            
                convert $file -resize "$scale"x"$scale" $file
        fi
        
        current=$[$current+$percent]
        echo $current
        
done) | zenity --progress --title "Zmniejszanie obrazków" --text "Postęp" --auto-close

Jest bardzo prosty, ale mi w zupełności wystarcza. Wykorzystuje polecenie "convert" z pakietu ImageMagick.

Debian & Broadcom Wireless & ndiswrapper

Ostatnio zakupiłem sobie router TP-Link TL-WR542G. Wcześniej używałem starego komputera z Pentium III 500 MHz, 96 RAM, z Gentoo w środku. Fajnie jest mieć router, którym można sobie zarządzać z konsoli, ale ma kilka wad - głośno chodzi, brak wi-fi, większy pobór prądu, zajmuje więcej miejsca. Ale starczy narzekania, do rzeczy. Pierwsze uruchomienie, szybka konfiguracja i coś tu nie gra. Internet strasznie zamula przez wi-fi. Wyniki testu łącza strasznie słabe - 300 kb przy pobieraniu danych, podczas gdy przy połączeniu przez kabel wychodziło około 2Mb. Jak nie trudno domyślić się, przyczyna tkwiła w sterowniku (BCM43xx). Z pomocą przychodzi ndiswrapper, który umożliwia instalację sterowników kart sieciowych, napisanych dla Windowsa. Sterowniki oraz listę obsługiwanych kart można znaleźć na stronie projektu. Przy wyborze sterownika należy zwrócić uwagę na pciid karty, które można odczytać przy pomocy polecenia lspci -nn. W moim przypadku jest to 14e4:4320
$ lspci -nn | grep Broadcom
02:04.0 Network controller [0280]: Broadcom Corporation BCM4306 802.11b/g Wireless LAN Controller [14e4:4320] (rev 03)
więc dla mojej karty odpowiedni jest sterownik bcmwl5. Czas na istalację: # aptitude install ndiswrapper-common
# ndiswrapper -i bcmwl5.inf
Jeszcze tylko załadowanie modułu: # modprobe ndiswrapper
FATAL: Module ndiswrapper not found
Jak widać, moduł który chcę załadować nie istnieje. Trzeba więc taki moduł stworzyć. Potrzebne do tego będą pakiety: build-essential, module-assistant, ndiswrapper-source oraz linux-headers-2.[wersja_jądra], w przypadku korzystania z jądra z repozytorium. # aptitude build-essential module-assistant ndiswrapper-source
# m-a a-i ndiswrapper
# modprobe ndiswrapper
Teraz już można w pełni cieszyć się bezprzewodowym dostępem do internetu.
Żeby moduł uruchamiał się przy starcie systemu, wystarczy dopisać go do listy /etc/modules: # echo "ndiswrapper" >> /etc/modules i dodać moduł bcm43xx do czarnej listy, żeby nie ładował się przy starcie systemu i nie kolidował z ndiswrapperem: # echo "blacklist bcm43xx" >> /etc/modprobe.d/blacklist

Phishing Paypal

Dostałem dziś takiego oto maila:

Jeżeli masz konto na PayPal i dostałeś takiego maila, to nie daj się zwieść! To jest przykład klasycznego phishing-u, czyli po krótce podszywania się pod oryginalną stronę. Kliknięcie na link w mailu i logowanie się na stronę która się wyświetli spowoduje przesłanie danych dostępowych do konta osobom niepowołanym.

Po czym poznać że to oszustwo? Akurat nie mam konta na PayPal, więc było mi łatwiej, ale można zauważyć tu kilka podejrzanych rzeczy. Najbardziej rzuca się w oczy adres nadawcy. Zamiast domeny paypal.co.uk, jest domena paypai.co.uk. Nieuważni użytikownicy przeoczą to i nie zauważą, że zamiast "l", jest małe "i". Oprócz tego podejrzana jest treść maila - zawieszenie konta z powodów bezpieczeństwa? I prośba o zalogowanie się w celu weryfikacji właściciela konta... ewidentnie coś tu śmierdzi.

Bądźcie czujni!

Tworzenie miniaturek z linii poleceń

Już wspominałem o tym w moim starym blogu, ale skoro ten blog ma zawierać głównie wpisy o tematyce technicznej, postanowiłem go umieścić również tutaj.

Czasami trzeba szybko zmniejszyć dużą ilość zdjęć, żeby np. umieścić je w galerii internetowej. Pod Linuxem jest na to prosty sposób. Wszystko czego potrzebujemy to pakiet ImageMagick.
Zakładam że będą pomniejszane wszystkie zdjęcia w formacie jpg z bieżącego katalogu.

W linii poleceń wystarczy wpisać: find . -maxdepth 1 -name '*.jpg' -exec convert {} -resize 800x800 {} ';' No i co to robi? Polecenie find wyszukuje w bieżącym katalogu wszystkie pliki o rozszerzeniu .jpg i wykonuje polecenie convert (z pakietu ImageMagick). Nawiasy "{}" oznaczają nazwę znalezionego pliku. Powyższe polecenie nadpisze oryginalne zdjęcia zmniejszonymi. Jeżeli chcemy uniknąć nadpisania, to można to zrobić np. tak find . -maxdepth 1 -name '*.jpg' -exec convert {} -resize 800x800 'min/{}' ';' Spowoduje to zapisanie miniaturek do katalogu min, który jest podkatalogiem bieżącego katalogu. Oczywiście "min" trzeba wcześniej utworzyć.
Jeżeli chcemy uniknąć nadpisania oryginalnych plików i zapisać miniaturki w bieżącym katalogu, można dodać prefiks przed nazwą miniatury: find * -maxdepth 1 -name '*.jpg' -exec convert {} -resize 800x800 "min"{} ';' Czemu akurat 800x800? Polecenie convert pomniejsza zdjęcia proporcjonalnie, więc jeżeli szerokość jest większa od wysokości to zmniejszy do rozdzielczości 800x..., a jeżeli jest odwrotnie to do rozdzielczości ...x800. Jeżeli nie chcemy zmniejszać wszystkich zdjęć do tego samego rozmiaru, tylko proporcjonalnie, to można użyć procentów, np. zamiast 800x800, 50%x50%. Opcja maxdepth określa ile poziomów podkatalogów ma być przeszukiwanych. Dla wartości 1 przeszukiwany jest tylko bieżący katalog.

W zasadzie powyższe przykłady prezentują cząstkę możliwości zarówno polecenia convert jak i find. Używając tego drugiego w analogiczny sposób można robić wiele innych rzeczy, np. przekonwertować wiele plików wav na mp3 przy użyciu lame.
ImageMagick jest wyposażony w narzędzie mogrify, które może pomniejszyć wiele zdjęć wg podanego filtra, więc te nieco długie powyższe przykłady, można zapisać krócej: mogrify -resize 800x800 *.jpg Mogrify nadpisuje oryginały, więc jeżeli nie chcemy ich utracić, trzeba pracować na kopiach.

Nowy rozdział.

Postanowiłem zmobilizować się do regularnego pisania, mało tego, do pisania o sprawach technicznych, wyszukiwania czegoś ciekawego i przelewania na bloga swoich doświadczeń. Wierzę w to, że dzięki staraniom o jakość wpisów, moja wiedza na dany temat będzie chociaż trochę bardziej rzetelna.

Oddzielam więc tematykę techniczną od mojego pierwotnego joggera (aczkolwiek nie usuwam ostatecznie), na którym będę pisał na luźne tematy i tak o dla siebie, dla uzewnętrznienia swoich wnętrzności.

Let the force be with me.