ServerPortfolio  2.0
Python parsers and server
 All Classes Namespaces Files Functions Variables Properties Pages
Run_Parsers.py
Go to the documentation of this file.
1 #!/usr/bin/python
2 
3 ## @package Run_Parsers
4 #
5 # Standalone program, implement all possible functions with or without the Server running.\n
6 # If the server is running call the server functions (not always need to query the web page)\n
7 # or make a call to Parserstocks through UpdateStocks\n
8 #
9 # Should be called simply from apache/ROOT_application with a minimum wrapper\n
10 # Return a simple string to the caller
11 #
12 #
13 # Last Changed $Id$
14 
15 ## @page doc_runparsers Page documentation for RunParsers
16 #
17 # Implement all functions with or without the Server running.
18 # Always return simple strings of data, easy to parse.
19 #
20 # \section sec1 Exemples
21 #
22 # ./Run_Parsers.py --source=Boursorama --action=GET --list_stock CAC40,ORA
23 #
24 # ./Run_Parsers.py --s=Boursorama --a GET CAC40 ORA
25 #
26 # ./Run_Parsers.py --a RELOAD
27 #
28 # ./Run_Parsers.py -t
29 
30 import sys, time
31 import logging, argparse
32 
33 #from serverportfolio.GlobalDicts import DEBUG_MODE
34 #from serverportfolio.DictionaryStocks import DictionaryStocks
35 
36 from serverportfolio.UpdateStocks import UpdateStocks
37 #from serverportfolio.Parsers.ParserStocks import ParserStocks
38 import serverportfolio.SocketServer_Client as SocketServer_Client
39 from serverportfolio.PortfolioException import PortfolioError
40 
41 # global data to the module
42 verbose = None
43 #list_stock = list()
44 #source = None
45 #action = None
46 
47 # old usage, keep to remember the options
48 # def usage():
49 # print '''
50 # ./Run_Parsers --test_server / -t no argument
51 # --source Boursorama/Yahoo
52 # --action GET (instantaneous values) / UPDATE_CSV (missing CSV data) / INTRO ( first date in yahoo )
53 # RELOAD (reload dictionary)
54 # --list_stock X,X,X
55 # -h / --help
56 # ex.
57 # ./Run_Parsers.py --source=Boursorama --action=GET --list_stock CAC40,ORA
58 # ./Run_Parsers.py --s=Boursorama --a GET CAC40 ORA
59 # ./Run_Parsers.py --a RELOAD
60 # ./Run_Parsers.py -t
61 # '''
62 
63 # def main():
64 #
65 # # necessary to get from main
66 # global verbose
67 # global list_stock
68 # global source
69 # global action
70 #
71 # # try reading arguments
72 # try:
73 # opts, args = getopt.getopt(sys.argv[1:], "hlsa:tv", ["help", "list_stock=", "source=", "action=","test_server","reload"])
74 # #print "opts ",opts
75 # #print "args ",args
76 # if (opts==[] ) & (args==[] ):
77 # usage()
78 # sys.exit(2)
79 # except getopt.GetoptError, err:
80 # # print help information and exit:
81 # print "error parsing arguments"
82 # print str(err) # will print something like "option -a not recognized"
83 # usage()
84 # sys.exit(2)
85 #
86 # #verbose = None
87 #
88 # for o, a in opts:
89 # #print " o, a ", o, a
90 # if o == "-v":
91 # #print "ask verbose "
92 # verbose = True
93 # elif o in ("-h", "--help"):
94 # #print "ask help"
95 # usage()
96 # sys.exit()
97 # elif o in ("-l", "--list_stock"):
98 # #print "ask list stock a=", a
99 # list_stock = str.split(a,",")
100 #
101 # elif o in ("-s", "--source"):
102 # #print "ask source a= ", a
103 # source = a
104 #
105 # elif o in ("-a", "--action"):
106 # #print "ask action a= ", a
107 # action = a
108 #
109 # # special action, make an argument for it
110 # elif o in ("-t","--test_server"):
111 # print "special t arguemnt"
112 # action = 'TEST_SERVER'
113 #
114 # elif o in ("-r","--reload"):
115 # print "special r argument"
116 # action = 'RELOAD'
117 #
118 # else:
119 # # miss something ?? import or other ??
120 # #assert False, "unhandled option"
121 # print "cannot parse option"
122 # usage()
123 # sys.exit(2)
124 #
125 # for a in args:
126 # list_stock.append( a )
127 #
128 # # test required argument
129 # if ( action != 'TEST_SERVER' ) & ( action != 'RELOAD' ):
130 # # else all field required
131 # if ( action == None ) | ( source == None ) | (list_stock == [] ) :
132 # print "Missing action, source or list_stock"
133 # usage()
134 # sys.exit(2)
135 
136 # work for test, could be more general. All action could return a simple line of data (with optional header?)
137 # all depends on Stock, calling should be transparent..
138 # function could be in UpdateStocks get_string_data()
139 # whose responsible if server is running ? (server may need UpdateStocks/ParserStocks for sure)
140 
141 # 1 specific function to call the server/ 1 specific function to call updatestocks, makes sense
142 # to see regarding to ouput, to get a list of strings good for python/C++
143 
144 # named CallGET before
145 
146 ## @brief Get the last instantaneous data of the list of stocks.
147 #
148 # Only used with Boursorama at this point
149 #
150 # @method method
151 # @param list_stock of the stock symbols
152 # @param action
153 # @param header if True print a header before the data
154 def send_to_server( method, action, list_stock, header=False ):
155 
156  # not working ??
157  #received = str()
158  received = ''
159  #print "send_to_server server_running ", server_running
160  main_logger.debug("send_to_server server_running %s" % server_running)
161  # if server is running, must format the query. Can be done by UpdateStocks, just do not run the parser parse.
162  if server_running :
163 
164  print "server running call it directly"
165  print 'method ', method
166  str=''
167 
168  if method:
169  str += method + ' '
170  if action:
171  str += action + ' '
172  if list_stock:
173  str += ' '.join(stock for stock in list_stock)
174  #print "str: ", str
175  #str = action
176  # could make better
177  #for stock in list_stock:
178  # str += ' ' + stock
179 
180  print "str in CallGET ", str
181  received = SocketServer_Client.SendData( str ) #action
182  #print "received in CallGET ", received
183  #return received
184 
185  # server not running, parse in loop
186  else :
187  print "server not running call parsers"
188  main_logger.debug("server not running call parsers")
189 
190  # first test, better to call UpdateStocks, here action is known
191  update_stock = UpdateStocks( action )
192  # first test, better to call UpdateStocks ?
193 
194  # reuse of the internal parser if multi-stock, new accept option multithread
195  received += update_stock.get_string_data( list_stock, opt_header = header)
196 
197  # only one return, shoud deal with error, better exception
198  #print "generak received ", received
199  return received
200 
201 ## @brief Make calls to YahooAPI module.
202 # Not tested yet, work only for one stock
203 #
204 # Implements:
205 # - LAST_CSV_UPDATE :
206 # - UPDATE_CSV : Download stock values from last in file to today
207 # - INTRO : Download stock data from first available to first in file
208 def CallYahooCSV( dict_stocks, stock, action ):
209 
210  if DEBUG_MODE :
211  print "Entry CallYahooCSV"
212  print "action ", action
213  print "stock ", stock
214 
215  received = 'output'
216  # strange format, no space !
217  str = action + stock
218  if DEBUG_MODE :
219  print "str ", str
220 
221  # server do not implement a better method, do not use thread for this
222  # should implement action in AutoParser, and thread
223  if server_running :
224  received = SocketServer_Client.SendData( str )
225 
226  else :
227  # can overwrite source, Yahoo_CSV for all methods implemented here
228  parserstocks = ParserStocks( stock, source )
229  #print "manual "
230 
231  # need to get time of the last update
232  if action == 'LAST_CSV_UPDATE' :
233  time_t = parserstocks.LastCSV()
234  #print " time_t ", time_t
235  received = time_t
236 
237  # make the update, get time inside the function
238  elif action == 'UPDATE_CSV' :
239  received = parserstocks.UpdateCSV()
240 
241  # get intro
242  elif action == 'INTRO' :
243  print "INTRO"
244  time_t = parserstocks.GetDateYIntro()
245  print "time_t", time_t
246  received = time_t
247 
248  return received
249 
250 # no more main section,should call directly correct parsers/UpdateStocks functions
251 # focus on available option/action defined in UpdateStocks, no care of parsers/thread, impl of post-process
252 
253 
254 # parsing with argparse, variable defined with add_argument, parser bad name here !!
255 arg_parser = argparse.ArgumentParser(description="Main executable for parsing data from web page")
256 
257 # if not provided, should treat all stocks
258 arg_parser.add_argument("-stock", dest="list_stock", required=False, nargs='+', help="The list of stock symbol to update")
259 
260 # GET/FORCE, optional ? if server running should use it, otherwise call to get
261 arg_parser.add_argument("-method", dest="method",required=True, \
262  help='method GET / FORCE / UPDATE_CSV / TEST_SERVER')
263 
264 # all action should be available, maybe keep action for InstValue, ... like in the code
265 arg_parser.add_argument("-a","--action", \
266  help="Action to perform, available: EAction")
267 
268 # this is good, change the level in debug. Print to a file better for real usage
269 arg_parser.add_argument('-v','--verbose', dest='verbose', action='store_true', default="False",\
270  help='Set logging to debug mode, otherwise error/critical mode activated by default')
271 
272 # need to force boolean type default
273 arg_parser.set_defaults(verbose=False)
274 
275 try :
276  option = arg_parser.parse_args()
277 # parse_args return an exit
278 except SystemExit :
279  sys.exit(1)
280 
281 print "option.verbose", option.verbose
282 # logging from verbose option, could define a file output by default ?
283 # file is good, can test the call in production with server (read the output)
284 if option.verbose:
285  logging.basicConfig(level=logging.DEBUG)
286 else:
287  logging.basicConfig(level=logging.ERROR)
288 
289 # in all case, it is better to split log and returned data(used by apache server,by C++...?)
290 # logging.basicConfig(filename='run_parser.log', level=logging.INFO) # filemode='w' to not append to file
291 
292 # create loggers for modules and main, not working !
293 logger = logging.getLogger('SP')
294 main_logger = logging.getLogger("SP.run_parser")
295 
296 main_logger.debug("Main Run_Parsers")
297 main_logger.debug("OK, list_stock: %s" % option.list_stock)
298 main_logger.debug("method : %s" % option.method)
299 main_logger.debug("action : %s" % option.action)
300 main_logger.debug("option.verbose : %s" % option.verbose)
301 
302 # test if a server is running
303 server_running = SocketServer_Client.Connect()
304 main_logger.debug("server_running: %s", server_running)
305 
306 #print 'status ', status
307 # special case, no real action required, exit at the end
308 # server_running = False
309 if option.method == 'TEST_SERVER' :
310  if server_running == False :
311  print "NOT RUNNING"
312  else :
313  print "RUNNING"
314  sys.exit(0)
315 
316 #
317 elif option.method == 'RELOAD' :
318  print "RELOAD to implement"
319 
320 # transform to EAction not needed here, done later
321 
322 # get or force, one option, method is about action
323 #elif ( option.method == 'GET' ) | ( option.method == 'FORCE' ) :
324 # received = CallGET( list_stock, option.action )
325 
326 # call local function to Run_Parsers
327 try:
328  received = send_to_server( option.method, option.action, option.list_stock )
329 except PortfolioError as ex:
330  print "Caught PortfolioError in RunParser"
331  print "ex: ", ex.get_format_string()
332  print "ERROR"
333  sys.exit(1)
334 
335 
336 main_logger.debug("final output")
337 print received
338 
339 # ################### main function ##########
340 # no more main a priori
341 # if __name__ == "__main__":
342 
343 
344 #
345 # if DEBUG_MODE :
346 # print "Entry Run_Parser main "
347 #
348 # server_running = False
349 # # parse argument
350 # main()
351 #
352 #
353 # if DEBUG_MODE :
354 # print "verbose ", verbose
355 # print "source ", source
356 # print "list_stock ", list_stock
357 # print "action ", action
358 #
359 # # make singleton object for stocks
360 # dict_stocks = DictionaryStocks()
361 #
362 # # test if server running
363 # status = SocketServer_Client.Connect()
364 # #print "status ",status
365 #
366 # # if not, need to load the dictionary
367 # if ( status == False ) :
368 # server_running = False
369 # else :
370 # server_running = True
371 # #print " will use server "
372 #
373 # # special case, no real action required, exit at the end
374 # if action == 'TEST_SERVER' :
375 # if server_running == False :
376 # print "NOT RUNNING"
377 # else :
378 # print "RUNNING"
379 # sys.exit(0)
380 #
381 # elif action == 'RELOAD' :
382 # if server_running == False :
383 # print "server no running, RELOAD action has no effect"
384 # sys.exit(0)
385 # else :
386 # if DEBUG_MODE :
387 # print "Reload done from the server call"
388 # str = "RELOAD"
389 # #print "str for RELOAD ", str
390 # received = SocketServer_Client.SendData( str )
391 # print received
392 # sys.exit(0)
393 #
394 # # for the moment, work only with one stock for some actions, less and less
395 # # seems ok now, can delete
396 # #stock = list_stock[0]
397 # #print "stock ", stock
398 #
399 # # call GET or Force call function, will deal with all case
400 # # create the parser if needed only
401 # if ( action == 'GET' ) | ( action == 'FORCE' ) :
402 # received = CallGET( dict_stocks, list_stock )
403 # #print "final out", received
404 # print received
405 # #sys.exit(0)
406 #
407 # # same can do it, or use server and thread
408 # # combine with LAST_CSV_UPDATE and INTRO in a function CallYahooCSV
409 # elif ( action == 'UPDATE_CSV') | ( action== 'LAST_CSV_UPDATE') | \
410 # ( action == 'INTRO' ):
411 #
412 # # @todo make a loop over the list or inside
413 # received = CallYahooCSV( dict_stocks, list_stock[0], action )
414 # if received != None :
415 # print received
416 #
417 # else :
418 # print "action not implemented ",action
419 # #sys.exit(0)
420 
421 
Define class UpdateStocks and ParserFactory.
Definition: UpdateStocks.py:1
def CallYahooCSV
Make calls to YahooAPI module.
Definition: Run_Parsers.py:208
To communicate with the server.
Define custom and specific exceptions for the complete package.
Update data of a list of Stock's (only one action by call is possible).
Definition: UpdateStocks.py:45
def send_to_server
Get the last instantaneous data of the list of stocks.
Definition: Run_Parsers.py:154