evgenyl 11.08.2010 15:25

PythonОтслеживание РПО

Покупаю часто за бугром разные безделушки и как-то сложно стало за всеми ими следить, вот и родилось сие чудо.
Возможно кому-то пригодится програмка, а кому-то пример кода :)

Програмка висит в трее, по клику показывается окно отслеживания, в настройках можно добавлять новые номера, галка "Следить" обновляет статус раз в 3 часа.

Собственно скрин
=Скрин
код


  1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
#!/usr/bin/python
# -*- coding: UTF-8 -*-

import sys, os, re
reload(sys)
sys.setdefaultencoding('UTF-8')

import pygtk
pygtk.require("2.0")

import gtk
import gobject
import urllib
import sqlite3
import datetime
import time
from thread import start_new_thread
from cgi import escape

re_ERROR = re.compile(r'<P CLASS\="page_ERROR".*?>(.*?)<\/P>',re.I+re.M+re.S)
re_INFO = re.compile(r'<P CLASS\="page_TITLE".*?>(.*?)<\/P>',re.I+re.M+re.S)
re_TABLE = re.compile(r'<table.*?>(.*?)<\/table>',re.I+re.M+re.S)
re_TR = re.compile(r'<tr.*?>(.*?)<\/tr>',re.I+re.M+re.S)
re_TD = re.compile(r'<td.*?>(.*?)<\/td>',re.I+re.M+re.S)

def mydir():
return os.path.abspath(os.path.dirname(__file__))

DB_FN = mydir()+'/post.db'

class EditPost:
def __init__(self, config, model=None):
self.config = config
self.model = model
if model:
number=model<1>
desc=model<3>
else:
number=''
desc=''
self.win = gtk.Window()
self.win.resize(400,200)
self.win.set_position( gtk.WIN_POS_CENTER )
self.win.set_title('Почтовое отправление')
self.win.set_deletable(False)
self.win.set_border_width(5)
self.box = gtk.Table(3,2)
self.win.add(self.box)
self.l_number = gtk.Label('Номер')
self.box.attach(self.l_number, 0, 1, 0, 1, 0, 0)
self.entry = gtk.Entry()
self.entry.set_text(number)
self.box.attach(self.entry, 1, 2, 0, 1, gtk.EXPAND|gtk.FILL, 0)
self.l_desc = gtk.Label('Описание')
self.box.attach(self.l_desc, 0, 1, 1, 2, 0, gtk.EXPAND|gtk.FILL, 5)
self.textview = gtk.TextView()
self.textview.get_buffer().set_text(desc)
self.box.attach(self.textview, 1, 2, 1, 2, gtk.EXPAND|gtk.FILL, gtk.EXPAND|gtk.FILL,2,2)
self.hbox = gtk.HBox()
self.hbox.set_size_request(0, 25)
self.box.attach(self.hbox, 1, 2, 2, 3, gtk.EXPAND|gtk.FILL, 0)
self.b_save = gtk.Button('Сохранить')
self.b_save.connect('clicked', self.on_save)
self.hbox.add(self.b_save)
self.b_cancel = gtk.Button('Отменить')
self.b_cancel.connect('clicked', self.on_cancel)
self.hbox.add(self.b_cancel)
self.win.set_modal(True)
self.win.show_all()
def on_save(self, w):
text_buf = self.textview.get_buffer()
if self.model:
self.config.update_post(self.model, self.entry.get_text(), text_buf.get_text( text_buf.get_start_iter(), text_buf.get_end_iter() ) )
else:
self.config.add_post( self.entry.get_text(), text_buf.get_text( text_buf.get_start_iter(), text_buf.get_end_iter() ) )
self.win.destroy()
del self
def on_cancel(self, w):
self.win.destroy()
del self

class Config:
def __init__(self):

self.win = gtk.Window()
self.win.resize(700,350)
self.win.set_position( gtk.WIN_POS_CENTER )
self.win.set_title('Параметры')
self.vbox = gtk.VBox()
self.win.add(self.vbox)
self.win.connect('delete-event', self.on_delete_event)

self.liststore = gtk.ListStore(int, str, gobject.TYPE_BOOLEAN, str, str, str)
self.treeview = gtk.TreeView(self.liststore)
self.tv_post_number = gtk.TreeViewColumn('Номер')
self.tv_post_enable = gtk.TreeViewColumn('Следить')
self.tv_post_state = gtk.TreeViewColumn('Статус')
self.tv_post_desc = gtk.TreeViewColumn('Описание')
self.tv_post_date = gtk.TreeViewColumn('Дата')

self.cr_text = gtk.CellRendererText()
self.cr_toggle = gtk.CellRendererToggle()
self.cr_toggle.set_property('activatable', True)
self.cr_toggle.connect('toggled', self.on_post_enable_toggled)

self.treeview.append_column(self.tv_post_enable)
self.treeview.append_column(self.tv_post_number)
self.treeview.append_column(self.tv_post_date)
self.treeview.append_column(self.tv_post_desc)

self.tv_post_enable.pack_start(self.cr_toggle, False)
self.tv_post_number.pack_start(self.cr_text, False)
self.tv_post_desc.pack_start(self.cr_text, True)
self.tv_post_date.pack_start(self.cr_text, False)

self.tv_post_enable.add_attribute(self.cr_toggle, "active", 2)
self.tv_post_number.set_attributes(self.cr_text, text=1)
self.tv_post_desc.set_attributes(self.cr_text, text=3)
self.tv_post_date.set_attributes(self.cr_text, text=4)

self.treeview.set_search_column(0)
#self.tvcolumn.set_sort_column_id(2)
self.treeview.set_reorderable(True)
self.vbox.add(self.treeview)
# - buttons ----------------
self.hbox = gtk.HBox()
self.hbox.set_size_request(0, 25)
self.vbox.pack_start(self.hbox, expand=False)
self.b_add = gtk.Button('Добавить')
self.b_add.connect('clicked', self.on_add)
self.b_edit = gtk.Button('Изменить')
self.b_edit.connect('clicked', self.on_edit)
self.b_del = gtk.Button('Удалить')
self.b_del.connect('clicked', self.on_delete)
self.hbox.add(self.b_add)
self.hbox.add(self.b_edit)
self.hbox.add(self.b_del)

def on_edit(self, w):
path, column = self.treeview.get_cursor()
if path != None:
post = EditPost(self, self.liststore<path>)

def on_delete(self, w):
path, column = self.treeview.get_cursor()
if path != None:
self.confirm = gtk.MessageDialog( parent=self.win, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO, message_format='Уверен?' )
self.confirm.set_position( gtk.WIN_POS_CENTER )
self.confirm.connect( 'delete_event', gtk.main_quit)
responce = self.confirm.run()
self.confirm.destroy()
if responce == gtk.RESPONSE_YES:
self.db_cur.execute('delete from posts where id = ?', < self.liststore</path><path><0> >)
self.db_con.commit()
self.liststore.remove(self.liststore</path><path>.iter)
def add_post(self, num, desc):
data = < None, num, 0, unicode(desc), str(datetime.datetime.now()), '' >
self.db_cur.execute('insert into posts values (?, ?, ?, ?, ?, ?)', data)
self.db_con.commit()
self.db_cur.execute('select max(id) from posts')
self.db_cur.execute( 'select * from posts where id = ?', self.db_cur.fetchone() )
self.liststore.append( self.db_cur.fetchone() )

def update_post(self, model, num, desc):
self.db_cur.execute( 'update posts set number = ?, desc = ? where id = ?', < num, desc, model<0> > )
self.db_con.commit()
model<1> = num
model<3> = desc

def on_add(self, w):
post = EditPost(self)

def on_post_enable_toggled(self, cell, path):
self.liststore</path><path><2> = not self.liststore</path><path><2>
self.db_cur.execute( 'update posts set enable = ? where id = ?', < self.liststore</path><path><2>, self.liststore</path><path><0> > )
self.db_con.commit()

def on_delete_event(self, w, a):
self.win.hide()
return True
def load(self, db=DB_FN):
if os.path.exists(db):
self.db_con = sqlite3.connect(db)
self.db_cur = self.db_con.cursor()
self.db_cur.execute('select * from posts')
for i in self.db_cur.fetchall():
self.liststore.append(i)
else:
self.db_con = sqlite3.connect(db)
self.db_cur = self.db_con.cursor()
self.db_cur.execute('create table posts (id INTEGER PRIMARY KEY ASC, number TEXT, enable INTEGER, desc TEXT, date TEXT, status TEXT)')

class App:
def __init__(self):
# - UI --------------------
self.win = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.win.set_position( gtk.WIN_POS_CENTER )
self.win.resize(600,350)
self.win.set_deletable(False)
self.win.set_title('Отслеживание РПО')
self.win.set_border_width(3)
self.win.connect('window-state-event', self.on_window_state)
# - menu ------------------
self.menu = gtk.Menu()
self.menu_config = gtk.ImageMenuItem(gtk.STOCK_PREFERENCES)
self.menu_config.connect('activate', self.on_config)
self.menu.append(self.menu_config)
self.menu_quit = gtk.ImageMenuItem(gtk.STOCK_QUIT)
self.menu_quit.connect('activate', self.quit)
self.menu.append(self.menu_quit)
# - tray ------------------
self.tray = gtk.StatusIcon()
self.tray.set_from_stock(gtk.STOCK_INFO)
self.tray.set_tooltip('Отслеживание РПО')
self.tray.connect('activate',self.show_win)
self.tray.connect('popup-menu', self.popup, self.menu)
# - init ------------------
self.config = Config()
vbox = gtk.VBox()
self.win.add(vbox)
sw = gtk.ScrolledWindow()
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
vbox.pack_start(sw)
hbox = gtk.HBox()
hbox.set_size_request(0, 25)
vbox.pack_start(hbox, expand=False)
b_update = gtk.Button('Обновить')
b_update.connect('clicked', self.on_update)
hbox.add(b_update)
b_update_all = gtk.Button('Обновить все')
b_update_all.set_label('Обновить все')
b_update_all.connect('clicked', self.on_update_all)
hbox.add(b_update_all)
b_config = gtk.Button('Параметры', gtk.STOCK_PREFERENCES)
b_config.connect('clicked', self.on_config)
hbox.add(b_config)
b_quit = gtk.Button('Выйти',gtk.STOCK_QUIT)
b_quit.connect('clicked', self.quit)
hbox.add(b_quit)
self.treeview = gtk.TreeView(self.config.liststore)
self.treeview.set_headers_visible(0)
self.treeview.set_rules_hint(1)
sw.add(self.treeview)
cr_text = gtk.CellRendererText()
tv_status = gtk.TreeViewColumn('Сатус', cr_text, markup=5)
self.treeview.append_column(tv_status)
self.config.load()
start_new_thread(self.update_by_timer,())

def on_window_state(self, w, e):
if e.new_window_state == gtk.gdk.WINDOW_STATE_ICONIFIED:
self.win.hide()
self.win.deiconify()

def update_by_timer(self):
while True:
time.sleep(60*60*3) # auto update every 3 hours
print 'Start auto update'
for i in self.config.liststore:
if i<2>:
self.update_model(i)

def on_update_all(self, w):
for i in self.config.liststore:
self.update_model( i )
def on_update(self, w):
path, column = self.treeview.get_cursor()
if path != None:
self.update_model( self.config.liststore</path><path> )

def on_config(self, widget):
self.config.win.show_all()

def popup(self, widget, button, time, data = None):
if button==3 and data:
data.show_all()
data.popup(None, None, None, 3, time)

def quit(self,widget):
gtk.main_quit()

def show_win(self,widget):
if self.win.get_property('visible'):
self.win.hide()
else:
self.win.show()
self.win.present()

def update_model(self, model):
print 'update', model<1>
query = { 'action':'search', 'barCodeSearchBtn':'?????', 'page':1, 'searchType':'barCode', 'show_form':'yes' }
query<'barCode'> = model<1>
text = 'Ошибка связи'
try:
status = urllib.urlopen( 'http://info.russianpost.ru/servlet/post_item', urllib.urlencode(query) ).read().decode('cp1251')
errors = < i.replace('<BR>','').replace('\n','') for i in re_ERROR.findall(status) >
info = < i.replace('<BR>','').replace('\n','') for i in re_INFO.findall(status) >
table = re_TABLE.findall(status)
if errors:
text = '<span background="red">'+'\n'.join(errors)+'</span>'
elif len(table) == 2:
text = ''
for i in re_TR.findall( table<1> )<2:>:
text+= ' '.join( < j.replace(' ',' ') for j in re_TD.findall(i)<:5> > ).strip() + '\n'
text = '<span background="green" foreground="black">'+text.strip()+'</span>'
else:
text = '<span background="yellow" foreground="black">'+escape( info<1>.strip() )+'</span>'

except Exception, e:
print 'Update error',model<1>, e
model<5> = u'<big><b>%s</b></big>\n<i>%s</i>\n<small>%s</small>' % (model<1>, escape(model<3>), text )
#model<5> = u'<big><b>%s</b></big>\n<i>%s</i>\n%s\n<small>%s</small>' % (model<1>, escape(model<3>), '-'*40, text )
db_con = sqlite3.connect(DB_FN)
db_cur = db_con.cursor()
db_cur.execute('update posts set status = ? where id = ?', < unicode(model<5>), model<0> > )
db_con.commit()

if __name__ == "__main__":
gobject.threads_init()
app = App()
app.win.show_all()
gtk.main()

</path>




файлик

PS:Я понемногу обновляю программу, будет что-то новое буду дописывать здесь.


Тэги: pygtk python РПО
+ 6 -
Похожие Поделиться

wiz 11.08.2010 15:45 #
Что за РПО?
evgenyl 11.08.2010 15:48 #
Регистрируемые Почтовые Отправления
Заказываешь че нить ... платишь, тебе дают номерок, а ты по нему смотришь, де твое барахло сейчас.
wiz 11.08.2010 15:52 #
А что там в начале за шаманства с релоадом?

И вообще, хотелось бы коментариев каких-то. Блог всё же Python, а не NevedomayaHnya.
evgenyl 11.08.2010 15:57 #
Какие коментарии ??? Задавай вопросы отвечу.
Это шаманство заставляет все строки хранится в UTF-8, удобно когда данные перегоняешь из pygtk сразу в sqlite избавляет от некоторых ошибок с кодировкой.
AlexGret 11.08.2010 16:38 #
Какие коментарии ???

К коду, разумеется. После строки кода поставил символ # и написал комментарий. Особенно, если код претендует на то, чтобы быть примером другим :)
evgenyl 11.08.2010 16:47 #
Кому надо, тот поймет без проблем поймет.
А комментировать каждую строчку у меня нет не времени не желания, тем более что имена переменных и функций имеют достаточно понятные названия.

Непонятно - спрашивай не стесняйся.
AlexGret 11.08.2010 17:06 #
Ну не каждую строчку, хотя бы общую идею. Вдруг кто-то захочет развивать программу :)
А со спойлером гораздо лучше. Спасибо.
evgenyl 11.08.2010 17:10 #
Если ты хотя бы немного знаком с pygtk тебе будет все понятно и так :)
wiz 11.08.2010 20:45 #
Код-то понятен. Непонятна программа (;

Надеюсь ты дорастёшь (как программист) до понимания таких тонкостей.
evgenyl 11.08.2010 22:04 #
Самомнения вам не отнять ), вот из за таких как этот человек совершенно отбивает желание тут что-то постить :\
evgenyl 11.08.2010 22:06 #
Ничего сам не написал а строит из себя ... эх уйду я от вас ... скоро
wiz 11.08.2010 22:57 #
... и это пройдёт (с)
ak3n 11.08.2010 16:34 #
у тебя в файле отступов нет
ak3n 11.08.2010 16:35 #
и может лучше код в спойлер?
evgenyl 11.08.2010 16:43 #
как ?
AlexGret 11.08.2010 16:43 #
Поддерживаю!
evgenyl 11.08.2010 16:49 #
Сделал.
ak3n 11.08.2010 16:52 #
Спасибо, стало гораздо лучше. :)
ak3n 11.08.2010 16:39 #
пардон за отступы, опера...
ak3n 11.08.2010 16:56 #
За программу спасибо, теперь буду использовать при заказе книг с books.ru.
evgenyl 11.08.2010 16:58 #
Рад что кому то пригодилась )
wiz 11.08.2010 20:46 #
Заверни в веб-сайт.
????
ПРОФИТ!
ak3n 11.08.2010 22:36 #
DuoV 12.08.2010 02:04 #
Style Guide for Python Code или PEP 8 придерживатся не пробывали?
Код сразу станет читабельнее.
blackraven 12.08.2010 16:13 #
Теги через запятую.
evgenyl 12.08.2010 16:59 #
Поправил.
atommixz 07.11.2011 03:22 #
поделитесь рабочим кодом
atommixz 08.11.2011 16:13 #
сам спросил, сам ответилзапостить сюда так и не удалось
atommixz 14.11.2011 16:33 #
Создал репозиторий, включающий новое обновление от автора https://bitbucket.org/atommixz/post_check