Така в предния урок ви показах как да си направите браузър, самият урок беше трудно да бъде предаден в по-разбираем вид. Ако сте го разбрали – добре, ако не съжалявам. За онези, които не са го разбрали или е все още сложно за тях реших да добавя днешния малко хумористичен урок на тема pynotify. Като крайния резултат ще бъде информативно балонче, което ще се стартира през определен период от време (или при стартирането на компютъра) и ще изважда афоризъм за жените от sqlite база данни. От сега искам да кажа, че самият скрипт като цяло е изключително лесен, но за начинаещите в Python може да им бъде полезен, представяйки им някои полезни и доста лесни функции за работа с бази данни и хващане на грешки.
Преди да започнем с урока искам да се извиня на всички жени, които попаднат на статията – афоризмите не са измислени от мен, но просто бяха най-удобния текст, с който можех да си поиграя за настоящия скрипт.
Какво ще ни бъде необходимо
Както и в предните уроци ще посъветвам да избегнете използването на IDE (Integrated Development Environment) – причината: Ако не напишете нещо грешно, няма как да го научите. Средите за разработка ви помагат едва след като сте усвоили самият език и ви трябва нещо по-мощно за работа, но ако сте твърдо решени да ползвате такава среда – не е проблем. Предварително трява да се уверите, че имате инсталирани следните библиотеки за Python:
- python-pysqlite2
- python-notify
- sqlite3
За да бъде примера по-близък до реалността няма да добавям в урока .db файла с базата данни, а само препратка към списъка с афоризмите. Първата ни стъпка ще бъде този списък да го превърнем в база данни и след това ще я използваме в нашият скрипт.
Списъкът можете да намерите на следния адрес: http://is.gd/c839M (използвайте опцията “Виж” и копирайте текста в нов файл, тъй като функцията за изтегляне все още не работи)
От текстов файл към база данни
Приемайки, че вече сте инсталирали всичко необходимо и имате файл thewomen, в който се съдържат афоризмите, идва моментът с прехвърлянето на тези записи в една база данни. Принципно бихме могли за този пример да използваме и самия файл, но това би било прекалено лесно, пък и какво по-хубаво от това да разберете малко за sqlite. Нека преди да напишем скрипта, който ще прехвърли всичко от текстовия файл в .db файла да структурираме стъпка по стъпка това, което трябва да се случи:
- Тъй като това е проста информация и не се нуждаем от кой знае каква функционалност базата ни данни ще съдържа две колони: id и womenfact
- id реално ще отговаря на реда в текстовия файл, womenfact на текста
- За да прехвърлим информацията е необходимо да прочетем файла ред по ред и всеки ред да бъде записан под следващото ID в базата данни
- id-то ще използваме по-късно, за да изкарваме произволен ред.
Нека пристъпим към самият скрипт. Аз ще го запиша първо целия и след това ще обясня ред по ред какво се случва:
#!/usr/bin/env python import codecs from pysqlite2 import dbapi2 as sqlite def main(): file = open('newtexts', 'r') try: conn = sqlite.connect('thewomen.db') c = conn.cursor() except: print "*** Problem creating the db file" try: c.execute("""CREATE TABLE women (id INTEGER PRIMARY KEY, womenfact TEXT)""") conn.commit() except: print "*** Problem creatint the table" for line in file: try: c.execute("""INSERT INTO women(womenfact) VALUES('%s')""" % (line.decode('utf-8'))) conn.commit() except: "*** Can't write to the database" file.close() c.close() if __name__ == '__main__': main()
Нека обясним сега какво сме направили.
В първите два реда вмъкваме необходимите библиотеки, които ще използва скрипта. След което дефинираме нашият главен метод main(). Започваме нашият метод с отварянето на файла thewomen в режим на четене (за това служи параметъра ‘r‘). След което опитваме да се свържем към базата данни thewomen.db. С except прихващаме възможни грешки, които евентуално биха възникнали при създаването на .db файла. После поставяме курсор “c“, и в следващият опит създаваме нашата таблица с две колони id и womenfact. Първата колона трябва да бъде Integer (т.е. число) и ще бъде наш главен ключ – това е достатъчно за sqlite да разбере, че тази стойност ще трябва сама да увеличава стойността си (за разлика от MySQL, където това трябва да опоменем изрично). Колоната womenfact ще съдържа текст (запознатите с MySQL може да потърсят VARCHAR, но в sqlite няма такъв тип данни[http://www.sqlite.org/datatype3.html]). Чрез conn.commit() казваме на sqlite да приложи нанесените от нас промени, т.е. да бъдат записани във файла. Това, което остава за нас е за всеки ред да извъшиме нов запис в базата данни, като важното в случая е да запомните, че ние ще ще декодираме информацията в utf-8, за да нямаме проблеми по-късно с родния ни език. При всеки запис ще потвърждаваме промените с conn.commit(). След като приключи цикъла, т.е. обходили сме всичките 130 реда от нашия файл, затваряме файла, който сме чели и затваряме връзката към базата данни.
Изпълнението на самият скрипт отнема около 5 секунди след което можете да прегледате съдържанието на базата данни с sqliteman.
Да се научим и да четем
В нашият случай първо се научихме да пишем, а след това да четем, но това е основният път към научаването в нашият случай. Ако незнаехме как да пишем – нямаше да има какво да четем нали така? Нека погледнем какво ще трябва да се случая в нашият четец:
- Трябва да осъществим връзка с базата данни
- Трябва да си генерираме произволно число между 0 и 130 (все пак не искаме всеки път да виждаме едно и също)
- Ще поискаме ред от базата данни с номер произволното число, което сме генерирали
- Резултата ще го разкодираме в utf-8 и ще го покажем чрез Notify балон.
Ето го и готовият скрипт:
#!/usr/bin/env python from pysqlite2 import dbapi2 as sqlite import codecs import random # това го забравих, но ще ни е необходимо ако не искаме # всеки път да пишем директния път до базата данни import os try: import pynotify except: "*** You don't have pynotify installed!" def main(): try: # Използваме os.environ['HOME'] за да вземем пътя до личната директория # на потребителя, все пак скрипта ни ще бъде стартиран като обикновен потребител # ако го стартираме като root, то ще трябва да запишем базата данни в # директорията на root: /root/.config/ conn = sqlite.connect('%s/.config/thewomen.db' % os.environ['HOME']) except: print "*** Error connecting to the db file" c = conn.cursor() number = random.randint(1, 130) try: c.execute("""SELECT womenfact FROM women WHERE id = %i""" % number) except: print "*** Problem selecting a row from the db file" row = c.fetchone() pynotify.init("womenfacts") n = pynotify.Notification("Womenfact:", "%s" % row[0].encode('utf-8'), "dialog-information") n.show() c.close() if __name__ == '__main__': main()
И така първите два реда с import са ви познати и от първия скрипт. С реда import random добавяме библиотеката за генериране на произволни числа. За библиотеката pynotify използваме опит, защото в случай, че потребителя няма инсталиран pynotify той трябва да знае за това, за да може да го инсталира. Ако предоставяте приложението си като .deb пакет примерно тази част можете и да я пропуснете, тъй като най-вероятно ще сте добавили python-pynotify в зависимостите на пакета. В main() метода свързването с базата данни е абсолютно същото, както и при създаването на базата данни – в случая нищо ново под слънцето. Променливата number използваме, за да запишем в нея произволно число използвайки метода randint (произволен integer), който приема като параметри диапазона, в който трябва да бъде числото, тъй като ние имаме 130 записа в нашата база данни, то диапазона ще бъде между 1 и 130. След което извикваме нашият курсор, като му казваме да избере womenfact от таблицата women, където id е равно на генерираното от нас число. Забележете, че при SQLITE сравненията не се правят с двойно равенство, както в Python. Нещо, което изпуснах да отбележа също е и, че при execute използваме тройни кавички – причината е, че в подобни заявки, може да ни се наложи да използваме двойни и единички кавички и е добра практика да използвате тройни, за всеки случай. Задаваме променлива row (ред), към която присвояваме първият резултат от нашата заявка. Имайте предвид, че резултата е масив – конкретно в нашият случай е с една единствена стойност, но все пак остава масив и ще трябва по-късно да го третираме като такъв. С реда pynotify.init("womenfacts") инициализираме pynotify, като му казваме, че ние сме ново приложение, което иска да използва услугата за уведомявания. Ако изпуснете този ред, най-вероятно няма да видите никакво балонче ;). Променливата n става нашето уведомление “Notification”, което приема три параметръра:
- Заглавие – “Womenfact:”
- Текст, който е първият елемент от масива, кодиран в utf-8
- Име на изображение, което да бъде използвано – dialog-information
Казваме на нашето уведомление да бъде показано с метода show() и прекъсваме връзката с базата данни.
Да направим използването на системата забавно
След като вече имаме нашият скрипт, който от своята база данни извежда произволен афоризъм може да се каже, че сме почти готови. Това което остава е да свъжеме скрипта ни със системата, така че да се показва автоматично. За целта имам три възможности:
- Да прикачим скрипта към глобална клавишна комбинация (виж Python: Актуалната песен в Clipboard)
- Да добавим скрипта към автоматично стартиращите се приложения (можете да го направите от Startup Applications)
- Последния и по-забавен разбира се е да накараме нашият скрипт да се стартира през определен период от време. За тази цел обаче ще трябва да използваме cron (услуга в UNIX/Linux света за автоматизиране на процеси)
Тъй като първите два варианта по обясними причини не са толкова интересни, в този урок ще обясня само последния. Преди да добавим нашият скрипт към списъка на cron е редно да направим няколко корекции.
- -Ще прекръстим скрипта си на нещо по-кратко и ще махнем разширението му – нека бъде
womenfactsи ще го направим изпълнум
mv името_на_вашия_скрипт.py womenfacts && chmod +x womenfacts
- Ще преместим нашата база данни на място, от което няма да я забършем по погрешка (
~/.config)
mv thewomen.db ~/.config/
- Трябва да нанесем промяната в нашият скрипт, за да нямаме проблеми с връзката към базата данни
Променяме:
conn = sqlite.connect('women.db')
на:
conn = sqlite.connect('%s/.config/women.db' % os.environ['HOME']) # Използваме os.environ['HOME'], за да вземем пътя до домашната директория на потребителя!
Наложително е да използваме абсолютния път до директорията – в случая ~/ няма да ни бъде от голяма полза.
- Копираме скрипта ни в
/usr/local/bin(за да бъде глобално изпълним):
sudo cp -fp womenfacts /usr/local/bin/ # използваме и параметъра -p, за да запазим правата върху файла
Тествайте, за да се уверите, че при изпълнението на womenfacts от терминала виждате балончето.
Сега идва реда на cron. Ако до сега не сте използвали cron. Първото нещо, което трябва да направите е да стартирате crontab с параметъра -e, в което ще бъдете попитани кой редактор искате да използвате (none, pino, vi, joe и т.н.). Имайте предвид, че ако искате cron да бъде запазен за всяка сесия, а не само за настоящата ще трябва да стартирате corntab като root (с администраторски права). По подрабиране, най-вероятно cron ще бъде празен. За нашия скрипт ние ще трябва да въведем следното:
*/5 * * * * DISPLAY=:0 PYTHONPATH=::/usr/lib/python2.6/dist-packages/gtk-2.0/:$PYTHONPATH /usr/bin/python /usr/local/bin/womenfacts # JOB_ID_1
Какво означава това. Първата част */5 означава да бъде стартиран всеки пет минути. Ако е само 5 означава в петата минута на всеки час. Останалите параметри са за съответно: час, ден от месеца, месец, ден от седмицата (общо пет с първия параметър). Тъй като нашият пример е малко по-специфичен – налага се да работиме с графично приложение задаваме някои константи преди да изпълниме нашият скрипт чрез cron. Първата и най-важна е DISPLAY=:0 означва, че ще използваме първия дисплей, останалите са свързани с пътищата да Python и използваната библиотека GTK и накрая пътят до нашият скрипт. За повече информация как да боравите с cron и как да разберете видовете настройки можете да прегледате информацията в wikipedia [http://en.wikipedia.org/wiki/Cron] или прегледайте man страницата. За по-бързо разяснение:
.---------------- минута (0 - 59) | .------------- час (0 - 23) | | .---------- ден от месеца (1 - 31) | | | .------- месец (1 - 12) ИЛИ jan,feb,mar,apr ... | | | | .---- ден от седмицата (0 - 7) (Неделя=0 или 7) ИЛИ sun,mon,tue,wed,thu,fri,sat | | | | | * * * * * команда, която да бъде изпълнена
Надявам се урокът да ви е бил полезен. Под статията ще намерите и готовите файлове, но ще се радвам да споделите в коментарите и други приложения на скрипта или поне вие по какъв начин го използвате.
thewomen-tut (8.78 KB) 96 изтегляния





2 Коментара
Отново първо едни благодарности за урочето и отново да спомена че казваш че ще вземаме произволно число от 1 до 130, но в функцията random.randint(1, 150), пише 150. Надявам се че приемаш коментарите ми като градивна критика, а не като нещо лошо.
Поздрави Николай.
Моя грешка, понеже съм копирал от скрипта, който ползвам при мен и там редовете са малко повече. Благодаря ти за поправката – сега ще коригирам и темата.
One Trackback
[...] Да разведрим деня с pynotify [...]…
…