ServerPortfolio  2.0
Python parsers and server
 All Classes Namespaces Files Functions Variables Properties Pages
Validation.v2.py
Go to the documentation of this file.
1 #!/usr/bin/python
2 
3 ## @package serverportfolio.Validation
4 # @brief For user validation before updating the data
5 
6 # todo extend to console, extend to the update of list_csv/divsplit
7 
8 # ScrollVerticalFrame seems to work, but consums lots of memory, even crash, maybe memory leack ?
9 # see simple tests in bin..scroll3.py
10 # not seems to good to mix grid and pack "in the same container"
11 
12 import logging
13 
14 import Tkinter as tk
15 #from Tkinter import *
16 #from ttk import *
17 
18 ## @class ValidationTkinter
19 # @brief Small GUI to validate the update of data
20 class ValidationTkinter(tk.Frame):
21 
22  def __init__(self, dict_input, master=None):
23  tk.Frame.__init__(self, master)
24 
25  # default cell of the top-level windows can expend
26  self.grid(sticky=tk.N+tk.S+tk.E+tk.W)
27 
28  # dict_interactive in input/output
29  self.dict_input = dict_input
30  #self.grid()
31  self.createWidgets()
32 
33  def createWidgets(self):
34 
35  top=self.winfo_toplevel()
36  top.columnconfigure(0, weight=1)
37  #top.rowconfigure(0, weight=1)
38 
39  self.columnconfigure(0, weight=1)
40  # TO not forget for each column
41  #self.columnconfigure(1, weight=1)
42  #self.rowconfigure(0,weight=1)
43 
44  # will contains the IntVars
45  self.dict_choice = {}
46 
47  #i = 0
48  labf = {}
49  for key_action, value_action in self.dict_input.iteritems():
50 
51  # create key for each action
52  #self.dict_choice[key_action] = {}
53 
54  # move all the rest to create_one_input_xml, makes sense
55  # create a Label Frame for each action, expand horizontally
56  labf[key_action] = tk.LabelFrame(self, text=key_action)
57  # always add in the next row, column 0
58  labf[key_action].grid( sticky=tk.E+tk.W, pady=8,padx=5 )
59 
60  # create key for each action
61  self.dict_choice[key_action] = {}
62 
63  # same behaviour, if here, more logic
64  i = 0
65 
66  # list of value
67  for key_value, value_value in value_action.iteritems():
68 
69  name = key_value
70  old_value = value_value['xml_value']
71  new_value = value_value['new_value']
72  state = value_value['repl_add']
73  # can send dict_choice[key_action]
74  self.create_one_input_xml(i, labf[key_action], key_action, name, old_value, new_value, state) #, self.lchoice, self.lrb)
75  i += 1
76 
77  #
78  frame_button = tk.Frame(self)
79  frame_button.grid()
80  # parent first argument
81  self.validButton = tk.Button(frame_button, text='Valid', command=self.valid)
82  self.validButton.grid(column=0, row=0, sticky=tk.E, pady=5)
83 
84  self.quitButton = tk.Button(frame_button, text='Quit', command=self.quit)
85  self.quitButton.grid(column=1, row=0, sticky=tk.W, pady=5)
86 
87  #for child in self.winfo_children(): child.grid_configure(padx=5, pady=5)
88 
89  ## @brief Check Validation is valid (all radiobuttons selected)
90  def valid(self):
91  #print "Validation Button"
92  #print 'dict_choice ', self.dict_choice
93 
94  # check all values have been validated, could be common, never error in HistPrice
95  for key_action, value_action in self.dict_choice.iteritems():
96  for value in self.dict_choice[key_action].values():
97 
98  if not ((value.get() == 0) | (value.get() == 2)):
99  # make message, not all selected, continue, cancel...
100  self.popupmsg("All entries must be selected as Accepted or Rejected to continue,\nor press Quit to validate the default")
101  return
102 
103  # update dict_interactive, specific xml
104  for key_action in self.dict_choice.keys():
105 
106  #while any(self.dict_choice[key_action]):
107  for name in self.dict_choice[key_action].keys():
108 
109  # only one element
110  value = self.dict_choice[key_action][name]
111  #print "key, value ", value
112  self.dict_input[key_action][name]['repl_add'] = value.get()
113 
114  # quit application
115  self.quit()
116 
117  def create_one_input_xml(self, i, labframe, action, name, old_value, new_value, state):
118 
119  var = tk.IntVar()
120  var.set( state )
121 
122  # consider name is unique here, but still tricky to get the data
123  self.dict_choice[action][name] = var
124 
125  # this column, after new value, only can expad, looks ok, radio button always on the right
126  # minsize ok for initial, but bad when minimised
127  labframe.columnconfigure(2, weight=1,minsize=100 )
128  tk.Label( labframe, text=name).grid(column=0, row=i, sticky=tk.W, padx=5, pady=2)
129  tk.Label( labframe, text=str(old_value)).grid(column=1, row=i, sticky=tk.W, padx=5, pady=2)
130  # option Label width=50 makes text center
131  tk.Label( labframe, text=str(new_value)).grid(column=2, row=i, sticky=tk.W, padx=5, pady=2)
132  # radio button
133  tk.Radiobutton( labframe, text='Rej.', variable=var, value=0).grid(column=3, row=i, sticky=tk.E)
134  tk.Radiobutton( labframe, text='Acc.', variable=var, value=2).grid(column=4, row=i, sticky=tk.E)
135 
136 
137  def popupmsg(self,msg):
138 
139  popup = tk.Toplevel(takefocus=True)
140  popup.title('Message')
141  tk.Label( popup, text=msg).grid( padx=10, pady=10)
142  tk.Button(popup, text='Ok', command=popup.quit).grid( pady=10 )
143 
144 # to combine later, maybe base class and derived ones...
145 # or one class, and in a specific LabelFrame can be deal with both
146 
147 # http://tkinter.unpythonic.net/wiki/VerticalScrolledFrame
148 
149 class VerticalScrolledFrame(tk.Frame):
150  """A pure Tkinter scrollable frame that actually works!
151  * Use the 'interior' attribute to place widgets inside the scrollable frame
152  * Construct and pack/place/grid normally
153  * This frame only allows vertical scrolling
154 
155  """
156  def __init__(self, parent, *args, **kw):
157  tk.Frame.__init__(self, parent, *args, **kw)
158 
159  # needed if grid is used
160  self.columnconfigure(0, weight=1)
161 
162  # create a canvas object and a vertical scrollbar for scrolling it
163  vscrollbar = tk.Scrollbar(self, orient=tk.VERTICAL)
164  #vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
165  vscrollbar.grid(column=1, row=0, sticky=tk.E+tk.N+tk.S)
166 
167  canvas = tk.Canvas(self, bd=0, highlightthickness=0, yscrollcommand=vscrollbar.set)
168  #canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
169  canvas.grid(column=0, row=0, sticky=tk.W+tk.E)
170 
171  vscrollbar.config(command=canvas.yview)
172 
173  # reset the view
174  canvas.xview_moveto(0)
175  canvas.yview_moveto(0)
176 
177  # create a frame inside the canvas which will be scrolled with it
178  self.interior = interior = tk.Frame(canvas)
179  #self.interior.grid()
180  interior_id = canvas.create_window(0, 0, window=interior, anchor=tk.NW)
181  #interior_id = canvas.create_window(4, 4, window=interior, anchor=tk.NW)
182 
183  # track changes to the canvas and frame width and sync them,
184  # also updating the scrollbar
185  def _configure_interior(event):
186  # update the scrollbars to match the size of the inner frame
187  size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
188  canvas.config(scrollregion="0 0 %s %s" % size)
189  if interior.winfo_reqwidth() != canvas.winfo_width():
190  # update the canvas's width to fit the inner frame
191  canvas.config(width=interior.winfo_reqwidth())
192  interior.bind('<Configure>', _configure_interior)
193 
194  def _configure_canvas(event):
195  if interior.winfo_reqwidth() != canvas.winfo_width():
196  # update the inner frame's width to fill the canvas
197  canvas.itemconfigure(interior_id, width=canvas.winfo_width())
198  canvas.bind('<Configure>', _configure_canvas)
199 
200 ## @class ValidationTkHP
201 # @brief Small GUI, specific for dealing with list_csv
202 class ValidationTkHP(tk.Frame):
203 
204  def __init__(self, dict_input, master=None):
205  tk.Frame.__init__(self, master)
206 
207  self.logger = logging.getLogger('SP.ValidationtTkHP')
208  # default cell of the top-level windows can expend
209  self.grid(sticky=tk.N+tk.S+tk.E+tk.W)
210 
211  # dict_interactive in input/output
212  self.dict_input = dict_input
213  self.logger.debug("init ValidationTkHP")
214 
215  self.createWidgets()
216 
217  def createWidgets(self):
218  # to make resizable frame, columnconfigure must be called/ same with rowconfigure
219  top=self.winfo_toplevel()
220  # make column 0 resizable
221  top.columnconfigure(0, weight=1)
222  # only colomn 0, here need more
223 
224  self.columnconfigure(0, weight=1)
225  #self.quit.grid( 0,0 sticky=tk.N+tk.S+tk.E+tk.W)
226  # will contains the IntVars, common with XML
227  self.dict_choice = {}
228 
229 
230  #i = 0
231  # a priori only one label with csv, maybe DivSplit can be combined later
232  self.labf = {}
233  #self.dict_label_frame = {}
234 
235  for key_action, value_action in self.dict_input.iteritems():
236 
237  # create key
238  self.dict_choice[key_action] = {}
239 
240  label_frame = tk.LabelFrame(self, text=key_action)
241  # allow the scrollbar to stay on the rigth
242  label_frame.columnconfigure(0, weight=1)
243  label_frame.grid(sticky=tk.E+tk.W, pady=8,padx=5)
244 
245  # here common
246  # create a Label Frame for each action, parent is self (tk.Frame)
247  #labf[key_action] = tk.LabelFrame(self, text=key_action) #.grid()
248  # always add in the next row, column 0
249  #labf[key_action].grid( sticky=tk.E+tk.W, pady=8,padx=5 )
250 
251  self.labf[key_action] = VerticalScrolledFrame(label_frame) #self)
252  # grid or pack working ? both like said
253  self.labf[key_action].grid(sticky=tk.E+tk.W)
254 
255  #self.label = Label(self, text="Shrink the window to activate the scrollbar.")
256  #self.label.grid() #pack()
257 
258  #buttons = []
259  #for i in range(50):
260  # buttons.append(Button(self.labf[key_action].interior, text="Button " + str(i)))
261  # buttons[-1].grid() #pack()
262 
263 #
264  i = 0
265  # list of value, integer number, value == [ error: ['error_str',[list_values]], repl_add : intger
266  for key_value, value_value in value_action.iteritems():
267 
268  print "key_value/ value_value ", key_value, value_value
269 
270  #name = key_value, only an integer
271  #old_value = value_value['xml_value']
272  #new_value = value_value['new_value']
273  label_values = ' '.join(str(value) for value in value_value['error'][1])
274  #print "label_values ", label_values
275  label_error = value_value['error'][0]
276 
277  # most important
278  state = value_value['repl_add']
279  # or send self.dict_choice[action][name] ??
280  #self.createOneInput(i, labf[key_action], key_action, name, old_value, new_value, state) #, self.lchoice, self.lrb)
281  self.create_one_input_csv( i, self.labf[key_action], key_action, label_values, label_error, state )
282  i += 1
283  # if list long enought it is ok
284  #self.create_one_input_csv( i, self.labf[key_action], key_action, label_values, label_error, state )
285  #i += 1
286  #self.create_one_input_csv( i, self.labf[key_action], key_action, label_values, label_error, state )
287  #i += 1
288 
289  # change nothing, still long to load
290  #self.labf[key_action].grid(sticky=tk.E+tk.W)
291 
292  # this is similar with Valid XML
293  # to make a specific Frame to contain these buttons
294  # parent first argument, should combine with .grid()
295  frame_button = tk.Frame(self)
296  self.validButton = tk.Button(frame_button, text='Valid', command=self.valid)
297  # to make it print
298  #self.validButton.grid(column=1, row=i+2, sticky=tk.E+tk.W) #sticky=tk.N+tk.S+tk.E+tk.W)
299  self.validButton.grid(column=0, row = 0)
300  self.quitButton = tk.Button(frame_button, text='Quit', command=self.quit)
301  # to make it print
302  self.quitButton.grid(column=1, row=0, sticky=tk.N+tk.S+tk.E+tk.W )
303 
304  # strange not call to frame_button.grid( column=0, row =count_action) ??
305  frame_button.grid()
306 
307 
308  # need sticky for each ??
309  #for child in self.winfo_children(): child.grid_configure(padx=5, pady=5)
310 
311  ## @brief Check Validation is valid (all radiobuttons selected)
312  def valid(self):
313  #print "Validation Button"
314  print 'dict_choice ', self.dict_choice
315 
316  # check all values have been correctly selected
317  # key is an integer here
318  for key_action, value_action in self.dict_choice.iteritems():
319 
320  for value in self.dict_choice[key_action].values():
321 
322  if not ((value.get() == 0) | (value.get() == 2)):
323  # make message, not all selected, continue, cancel...
324  return
325 
326  # modify repl_add, similar to XML
327  print "Ok, all selected, Apply the selection"
328  for key_action in self.dict_choice.keys():
329 
330  for name in self.dict_choice[key_action].keys():
331 
332  # only one element
333  value = self.dict_choice[key_action][name]
334  print "name, value ", name, value, value.get()
335  self.dict_input[key_action][name]['repl_add'] = value.get()
336 
337  # quit application
338  self.quit()
339 
340  # label different
341  def create_one_input_csv(self, i, labframe, action, label_values, label_error, state):
342 
343  var = tk.IntVar()
344  var.set( state )
345 
346  # consider name is unique here, but still tricky to get the data
347  #self.dict_choice[action][name] = var
348  self.dict_choice[action][i] = var
349 
350  if state == 0:
351  color_lab = 'red'
352  else:
353  color_lab = 'black'
354 
355  # need interior here, or assign before ??
356  labframe.interior.columnconfigure(1, weight=1,minsize=100 )
357  label1 = tk.Label( labframe.interior, text=label_values, fg=color_lab).grid(column=0, row=i+1, sticky=tk.W )#, sticky=tk.N+tk.S+tk.E+tk.W ) # sticky=tk.N+tk.S+tk.E+tk.W how to strech
358  label2 = tk.Label( labframe.interior, text=label_error, fg=color_lab).grid(column=1, row=i+1, sticky=tk.W )
359  #label1 = tk.Label( labframe, text=str(old_value)).grid(column=2, row=i+1)
360  #label2 = tk.Label( labframe, text=str(new_value)).grid(column=3, row=i+1)
361 
362  # radio button, common to all as well
363  rb1 = tk.Radiobutton( labframe.interior, text='Rej.', variable=var, value=0).grid(column=3, row=i+1, sticky=tk.N+tk.S+tk.E+tk.W)
364  rb2 = tk.Radiobutton( labframe.interior, text='Acc..', variable=var, value=2).grid(column=4, row=i+1, sticky=tk.N+tk.S+tk.E+tk.W)
365 
366 
367 if __name__ == "__main__":
368 
369 # test = {
370 # 'Info': {'Sector': {'xml_value': None, 'new_value': 'Utilities', 'date': '2015-03-03', 'source': 'YQL', 'repl_add': 0},
371 # 'StockExchange': {'xml_value': None, 'new_value': 'Paris', 'date': '2015-03-03', 'source': 'YQL', 'repl_add': 2}
372 # },
373 # 'Other': {'Industry': {'xml_value': None, 'new_value': 'Diversified Utilities', 'date': '2015-03-03', 'source': 'YQL', 'repl_add': 2},
374 # 'Name': {'xml_value': None, 'new_value': 'GDF SUEZ', 'date': '2015-03-03', 'source': 'YQL', 'repl_add': 1}
375 # }
376 # }
377 # # ValidationTkXML
378 # app = ValidationTkinter( test )
379 
380  test = {
381  'HistPrice': {0: {'repl_add': 0, 'error': ['volume 0', [1425510000, 4929.04, 4974.64, 4926.09, 4963.51, 0.0]]}, 1: {'repl_add': 0, 'error': ['volume 0', [1425423600, 4882.94, 4917.35, 4856.14, 4917.35, 0.0]]}, 2: {'repl_add': 2, 'error': ['', [1425337200, 4922.43, 4936.47, 4863.92, 4869.25, 116619800.0]]}, 3: {'repl_add': 2, 'error': ['', [1425250800, 4937.43, 4950.59, 4900.11, 4917.32, 149942900.0]]}, 4: {'repl_add': 2, 'error': ['', [1424991600, 4905.77, 4951.48, 4903.09, 4951.48, 120717900.0]]}, 5: {'repl_add': 2, 'error': ['', [1424905200, 4884.89, 4910.62, 4877.24, 4910.62, 105228900.0]]}, 6: {'repl_add': 2, 'error': ['', [1424818800, 4885.0, 4894.6, 4863.22, 4882.22, 117214700.0]]}, 7: {'repl_add': 2, 'error': ['', [1424732400, 4865.68, 4899.52, 4843.96, 4886.44, 106329800.0]]}, 8: {'repl_add': 2, 'error': ['', [1424646000, 4872.13, 4875.97, 4832.36, 4862.3, 102128000.0]]}, 9: {'repl_add': 2, 'error': ['', [1424386800, 4821.38, 4837.93, 4780.81, 4830.9, 140055500.0]]}, 10: {'repl_add': 0, 'error': ['volume 0', [1424300400, 4788.4, 4841.69, 4770.17, 4833.28, 0.0]]}},
382  'Div': {0: {'repl_add': 0, 'error': ['volume 0', [1425510000, 4929.04, 4974.64, 4926.09, 4963.51, 0.0]]}, 1: {'repl_add': 0, 'error': ['volume 0', [1425423600, 4882.94, 4917.35, 4856.14, 4917.35, 0.0]]}, 2: {'repl_add': 2, 'error': ['', [1425337200, 4922.43, 4936.47, 4863.92, 4869.25, 116619800.0]]}, 3: {'repl_add': 2, 'error': ['', [1425250800, 4937.43, 4950.59, 4900.11, 4917.32, 149942900.0]]}, 4: {'repl_add': 2, 'error': ['', [1424991600, 4905.77, 4951.48, 4903.09, 4951.48, 120717900.0]]}, 5: {'repl_add': 2, 'error': ['', [1424905200, 4884.89, 4910.62, 4877.24, 4910.62, 105228900.0]]}, 6: {'repl_add': 2, 'error': ['', [1424818800, 4885.0, 4894.6, 4863.22, 4882.22, 117214700.0]]}, 7: {'repl_add': 2, 'error': ['', [1424732400, 4865.68, 4899.52, 4843.96, 4886.44, 106329800.0]]}, 8: {'repl_add': 2, 'error': ['', [1424646000, 4872.13, 4875.97, 4832.36, 4862.3, 102128000.0]]}, 9: {'repl_add': 2, 'error': ['', [1424386800, 4821.38, 4837.93, 4780.81, 4830.9, 140055500.0]]}, 10: {'repl_add': 0, 'error': ['volume 0', [1424300400, 4788.4, 4841.69, 4770.17, 4833.28, 0.0]]}}
383  }
384 
385  test = {
386  'HistPrice': {0: {'first_date': '2015-03-06 00:00:00', 'repl_add': 2, 'first_values': [1425596400, 19.14, 19.16, 18.86, 18.9, 6016200.0], 'last_date': '2015-02-02 00:00:00', 'error': '', 'last_values': [1422831600, 19.72, 19.88, 19.59, 19.83, 4641200.0]}},
387  'Div': {0: {'first_date': '2015-03-06 00:00:00', 'repl_add': 2, 'first_values': [1425596400, 19.14, 19.16, 18.86, 18.9, 6016200.0], 'last_date': '2015-02-02 00:00:00', 'error': '', 'last_values': [1422831600, 19.72, 19.88, 19.59, 19.83, 4641200.0]}}
388  }
389 
390  app = ValidationTkHP( test )
391  app.master.title('Manual Validation')
392  app.mainloop()
393 
394  # test modified with new values of repl_add
395  print "\n== Test Output ", test
def create_one_input_xml
Fill the frame specific to xml data: Info / Fundamental.
Definition: Validation.py:234
A pure Tkinter scrollable frame that actually works!.
Definition: Validation.py:28
def valid
Check Validation is valid (all radiobuttons selected)
def valid
Check all radio buttons have been selected and update repl_add entry with _var_radiob.
Definition: Validation.py:206
Small GUI, specific for dealing with list_csv.
def popupmsg
Message indicating that some entries have not been validated.
Definition: Validation.py:312