Bump to 1.2.18
[gc-dialer] / src / dialcentral_qt.py
1 #!/usr/bin/env python
2 # -*- coding: UTF8 -*-
3
4 from __future__ import with_statement
5
6 import os
7 import base64
8 import ConfigParser
9 import functools
10 import logging
11
12 from PyQt4 import QtGui
13 from PyQt4 import QtCore
14
15 import constants
16 from util import qtpie
17 from util import qwrappers
18 from util import qui_utils
19 from util import misc as misc_utils
20
21 import session
22
23
24 _moduleLogger = logging.getLogger(__name__)
25
26
27 class LedWrapper(object):
28
29         def __init__(self):
30                 self._ledHandler = None
31                 self._init = False
32
33         def off(self):
34                 self._lazy_init()
35                 if self._ledHandler is not None:
36                         self._ledHandler.off()
37
38         def _lazy_init(self):
39                 if self._init:
40                         return
41                 self._init = True
42                 try:
43                         import led_handler
44                         self._ledHandler = led_handler.LedHandler()
45                 except Exception, e:
46                         _moduleLogger.exception('Unable to initialize LED Handling: "%s"' % str(e))
47                         self._ledHandler = None
48
49
50 class Dialcentral(qwrappers.ApplicationWrapper):
51
52         _DATA_PATHS = [
53                 os.path.join(os.path.dirname(__file__), "../share"),
54                 os.path.join(os.path.dirname(__file__), "../data"),
55         ]
56
57         def __init__(self, app):
58                 self._dataPath = None
59                 self._aboutDialog = None
60                 self._ledHandler = LedWrapper()
61                 self.notifyOnMissed = False
62                 self.notifyOnVoicemail = False
63                 self.notifyOnSms = False
64
65                 try:
66                         import alarm_handler
67                         if alarm_handler.AlarmHandler is not alarm_handler._NoneAlarmHandler:
68                                 self._alarmHandler = alarm_handler.AlarmHandler()
69                         else:
70                                 self._alarmHandler = None
71                 except (ImportError, OSError):
72                         self._alarmHandler = None
73                 except Exception:
74                         _moduleLogger.exception("Notification failure")
75                         self._alarmHandler = None
76                 if self._alarmHandler is None:
77                         _moduleLogger.info("No notification support")
78
79                 qwrappers.ApplicationWrapper.__init__(self, app, constants)
80
81         def load_settings(self):
82                 try:
83                         config = ConfigParser.SafeConfigParser()
84                         config.read(constants._user_settings_)
85                 except IOError, e:
86                         _moduleLogger.info("No settings")
87                         return
88                 except ValueError:
89                         _moduleLogger.info("Settings were corrupt")
90                         return
91                 except ConfigParser.MissingSectionHeaderError:
92                         _moduleLogger.info("Settings were corrupt")
93                         return
94                 except Exception:
95                         _moduleLogger.exception("Unknown loading error")
96
97                 blobs = "", ""
98                 isFullscreen = False
99                 isPortrait = qui_utils.screen_orientation() == QtCore.Qt.Vertical
100                 tabIndex = 0
101                 try:
102                         blobs = [
103                                 config.get(constants.__pretty_app_name__, "bin_blob_%i" % i)
104                                 for i in xrange(len(self._mainWindow.get_default_credentials()))
105                         ]
106                         isFullscreen = config.getboolean(constants.__pretty_app_name__, "fullscreen")
107                         tabIndex = config.getint(constants.__pretty_app_name__, "tab")
108                         isPortrait = config.getboolean(constants.__pretty_app_name__, "portrait")
109                 except ConfigParser.NoOptionError, e:
110                         _moduleLogger.info(
111                                 "Settings file %s is missing option %s" % (
112                                         constants._user_settings_,
113                                         e.option,
114                                 ),
115                         )
116                 except ConfigParser.NoSectionError, e:
117                         _moduleLogger.info(
118                                 "Settings file %s is missing section %s" % (
119                                         constants._user_settings_,
120                                         e.section,
121                                 ),
122                         )
123                 except Exception:
124                         _moduleLogger.exception("Unknown loading error")
125
126                 if self._alarmHandler is not None:
127                         try:
128                                 self._alarmHandler.load_settings(config, "alarm")
129                                 self.notifyOnMissed = config.getboolean("2 - Account Info", "notifyOnMissed")
130                                 self.notifyOnVoicemail = config.getboolean("2 - Account Info", "notifyOnVoicemail")
131                                 self.notifyOnSms = config.getboolean("2 - Account Info", "notifyOnSms")
132                         except ConfigParser.NoOptionError, e:
133                                 _moduleLogger.info(
134                                         "Settings file %s is missing option %s" % (
135                                                 constants._user_settings_,
136                                                 e.option,
137                                         ),
138                                 )
139                         except ConfigParser.NoSectionError, e:
140                                 _moduleLogger.info(
141                                         "Settings file %s is missing section %s" % (
142                                                 constants._user_settings_,
143                                                 e.section,
144                                         ),
145                                 )
146                         except Exception:
147                                 _moduleLogger.exception("Unknown loading error")
148
149                 creds = (
150                         base64.b64decode(blob)
151                         for blob in blobs
152                 )
153                 self._mainWindow.set_default_credentials(*creds)
154                 self._fullscreenAction.setChecked(isFullscreen)
155                 self._orientationAction.setChecked(isPortrait)
156                 self._mainWindow.set_current_tab(tabIndex)
157                 self._mainWindow.load_settings(config)
158
159         def save_settings(self):
160                 _moduleLogger.info("Saving settings")
161                 config = ConfigParser.SafeConfigParser()
162
163                 config.add_section(constants.__pretty_app_name__)
164                 config.set(constants.__pretty_app_name__, "tab", str(self._mainWindow.get_current_tab()))
165                 config.set(constants.__pretty_app_name__, "fullscreen", str(self._fullscreenAction.isChecked()))
166                 config.set(constants.__pretty_app_name__, "portrait", str(self._orientationAction.isChecked()))
167                 for i, value in enumerate(self._mainWindow.get_default_credentials()):
168                         blob = base64.b64encode(value)
169                         config.set(constants.__pretty_app_name__, "bin_blob_%i" % i, blob)
170
171                 if self._alarmHandler is not None:
172                         config.add_section("alarm")
173                         self._alarmHandler.save_settings(config, "alarm")
174                 config.add_section("2 - Account Info")
175                 config.set("2 - Account Info", "notifyOnMissed", repr(self.notifyOnMissed))
176                 config.set("2 - Account Info", "notifyOnVoicemail", repr(self.notifyOnVoicemail))
177                 config.set("2 - Account Info", "notifyOnSms", repr(self.notifyOnSms))
178
179                 self._mainWindow.save_settings(config)
180
181                 with open(constants._user_settings_, "wb") as configFile:
182                         config.write(configFile)
183
184         def get_icon(self, name):
185                 if self._dataPath is None:
186                         for path in self._DATA_PATHS:
187                                 if os.path.exists(os.path.join(path, name)):
188                                         self._dataPath = path
189                                         break
190                 if self._dataPath is not None:
191                         icon = QtGui.QIcon(os.path.join(self._dataPath, name))
192                         return icon
193                 else:
194                         return None
195
196         def _close_windows(self):
197                 qwrappers.ApplicationWrapper._close_windows(self)
198                 if self._aboutDialog  is not None:
199                         self._aboutDialog.close()
200
201         @property
202         def fsContactsPath(self):
203                 return os.path.join(constants._data_path_, "contacts")
204
205         @property
206         def alarmHandler(self):
207                 return self._alarmHandler
208
209         @property
210         def ledHandler(self):
211                 return self._ledHandler
212
213         def _new_main_window(self):
214                 return MainWindow(None, self)
215
216         @QtCore.pyqtSlot()
217         @QtCore.pyqtSlot(bool)
218         @misc_utils.log_exception(_moduleLogger)
219         def _on_about(self, checked = True):
220                 with qui_utils.notify_error(self._errorLog):
221                         if self._aboutDialog is None:
222                                 import dialogs
223                                 self._aboutDialog = dialogs.AboutDialog(self)
224                         response = self._aboutDialog.run(self._mainWindow.window)
225
226
227 class DelayedWidget(object):
228
229         def __init__(self, app, settingsNames):
230                 self._layout = QtGui.QVBoxLayout()
231                 self._layout.setContentsMargins(0, 0, 0, 0)
232                 self._widget = QtGui.QWidget()
233                 self._widget.setContentsMargins(0, 0, 0, 0)
234                 self._widget.setLayout(self._layout)
235                 self._settings = dict((name, "") for name in settingsNames)
236
237                 self._child = None
238                 self._isEnabled = True
239
240         @property
241         def toplevel(self):
242                 return self._widget
243
244         def has_child(self):
245                 return self._child is not None
246
247         def set_child(self, child):
248                 if self._child is not None:
249                         self._layout.removeWidget(self._child.toplevel)
250                 self._child = child
251                 if self._child is not None:
252                         self._layout.addWidget(self._child.toplevel)
253
254                 self._child.set_settings(self._settings)
255
256                 if self._isEnabled:
257                         self._child.enable()
258                 else:
259                         self._child.disable()
260
261         def enable(self):
262                 self._isEnabled = True
263                 if self._child is not None:
264                         self._child.enable()
265
266         def disable(self):
267                 self._isEnabled = False
268                 if self._child is not None:
269                         self._child.disable()
270
271         def clear(self):
272                 if self._child is not None:
273                         self._child.clear()
274
275         def refresh(self, force=True):
276                 if self._child is not None:
277                         self._child.refresh(force)
278
279         def get_settings(self):
280                 if self._child is not None:
281                         return self._child.get_settings()
282                 else:
283                         return self._settings
284
285         def set_settings(self, settings):
286                 if self._child is not None:
287                         self._child.set_settings(settings)
288                 else:
289                         self._settings = settings
290
291
292 def _tab_factory(tab, app, session, errorLog):
293         import gv_views
294         return gv_views.__dict__[tab](app, session, errorLog)
295
296
297 class MainWindow(qwrappers.WindowWrapper):
298
299         KEYPAD_TAB = 0
300         RECENT_TAB = 1
301         MESSAGES_TAB = 2
302         CONTACTS_TAB = 3
303         MAX_TABS = 4
304
305         _TAB_TITLES = [
306                 "Dialpad",
307                 "History",
308                 "Messages",
309                 "Contacts",
310         ]
311         assert len(_TAB_TITLES) == MAX_TABS
312
313         _TAB_ICONS = [
314                 "dialpad.png",
315                 "history.png",
316                 "messages.png",
317                 "contacts.png",
318         ]
319         assert len(_TAB_ICONS) == MAX_TABS
320
321         _TAB_CLASS = [
322                 functools.partial(_tab_factory, "Dialpad"),
323                 functools.partial(_tab_factory, "History"),
324                 functools.partial(_tab_factory, "Messages"),
325                 functools.partial(_tab_factory, "Contacts"),
326         ]
327         assert len(_TAB_CLASS) == MAX_TABS
328
329         # Hack to allow delay importing/loading of tabs
330         _TAB_SETTINGS_NAMES = [
331                 (),
332                 ("filter", ),
333                 ("status", "type"),
334                 ("selectedAddressbook", ),
335         ]
336         assert len(_TAB_SETTINGS_NAMES) == MAX_TABS
337
338         def __init__(self, parent, app):
339                 qwrappers.WindowWrapper.__init__(self, parent, app)
340                 self._window.setWindowTitle("%s" % constants.__pretty_app_name__)
341                 #self._freezer = qwrappers.AutoFreezeWindowFeature(self._app, self._window)
342                 self._errorLog = self._app.errorLog
343
344                 self._session = session.Session(self._errorLog, constants._data_path_)
345                 self._session.error.connect(self._on_session_error)
346                 self._session.loggedIn.connect(self._on_login)
347                 self._session.loggedOut.connect(self._on_logout)
348                 self._session.draft.recipientsChanged.connect(self._on_recipients_changed)
349                 self._defaultCredentials = "", ""
350                 self._curentCredentials = "", ""
351                 self._currentTab = 0
352
353                 self._credentialsDialog = None
354                 self._smsEntryDialog = None
355                 self._accountDialog = None
356
357                 self._tabsContents = [
358                         DelayedWidget(self._app, self._TAB_SETTINGS_NAMES[i])
359                         for i in xrange(self.MAX_TABS)
360                 ]
361                 for tab in self._tabsContents:
362                         tab.disable()
363
364                 self._tabWidget = QtGui.QTabWidget()
365                 if qui_utils.screen_orientation() == QtCore.Qt.Vertical:
366                         self._tabWidget.setTabPosition(QtGui.QTabWidget.South)
367                 else:
368                         self._tabWidget.setTabPosition(QtGui.QTabWidget.West)
369                 defaultTabIconSize = self._tabWidget.iconSize()
370                 defaultTabIconWidth, defaultTabIconHeight = defaultTabIconSize.width(), defaultTabIconSize.height()
371                 for tabIndex, (tabTitle, tabIcon) in enumerate(
372                         zip(self._TAB_TITLES, self._TAB_ICONS)
373                 ):
374                         icon = self._app.get_icon(tabIcon)
375                         if constants.IS_MAEMO and icon is not None:
376                                 tabTitle = ""
377
378                         if icon is None:
379                                 self._tabWidget.addTab(self._tabsContents[tabIndex].toplevel, tabTitle)
380                         else:
381                                 iconSize = icon.availableSizes()[0]
382                                 defaultTabIconWidth = max(defaultTabIconWidth, iconSize.width())
383                                 defaultTabIconHeight = max(defaultTabIconHeight, iconSize.height())
384                                 self._tabWidget.addTab(self._tabsContents[tabIndex].toplevel, icon, tabTitle)
385                 defaultTabIconWidth = max(defaultTabIconWidth, 32)
386                 defaultTabIconHeight = max(defaultTabIconHeight, 32)
387                 self._tabWidget.setIconSize(QtCore.QSize(defaultTabIconWidth, defaultTabIconHeight))
388                 self._tabWidget.currentChanged.connect(self._on_tab_changed)
389                 self._tabWidget.setContentsMargins(0, 0, 0, 0)
390
391                 self._layout.addWidget(self._tabWidget)
392
393                 self._loginTabAction = QtGui.QAction(None)
394                 self._loginTabAction.setText("Login")
395                 self._loginTabAction.triggered.connect(self._on_login_requested)
396
397                 self._importTabAction = QtGui.QAction(None)
398                 self._importTabAction.setText("Import")
399                 self._importTabAction.triggered.connect(self._on_import)
400
401                 self._accountTabAction = QtGui.QAction(None)
402                 self._accountTabAction.setText("Account")
403                 self._accountTabAction.triggered.connect(self._on_account)
404
405                 self._refreshTabAction = QtGui.QAction(None)
406                 self._refreshTabAction.setText("Refresh")
407                 self._refreshTabAction.setShortcut(QtGui.QKeySequence("CTRL+r"))
408                 self._refreshTabAction.triggered.connect(self._on_refresh)
409
410                 fileMenu = self._window.menuBar().addMenu("&File")
411                 fileMenu.addAction(self._loginTabAction)
412                 fileMenu.addAction(self._refreshTabAction)
413
414                 toolsMenu = self._window.menuBar().addMenu("&Tools")
415                 toolsMenu.addAction(self._accountTabAction)
416                 toolsMenu.addAction(self._importTabAction)
417                 toolsMenu.addAction(self._app.aboutAction)
418
419                 self._initialize_tab(self._tabWidget.currentIndex())
420                 self.set_fullscreen(self._app.fullscreenAction.isChecked())
421                 self.set_orientation(self._app.orientationAction.isChecked())
422
423         def set_default_credentials(self, username, password):
424                 self._defaultCredentials = username, password
425
426         def get_default_credentials(self):
427                 return self._defaultCredentials
428
429         def walk_children(self):
430                 return ()
431
432         def start(self):
433                 qwrappers.WindowWrapper.start(self)
434                 assert self._session.state == self._session.LOGGEDOUT_STATE, "Initialization messed up"
435                 if self._defaultCredentials != ("", ""):
436                         username, password = self._defaultCredentials[0], self._defaultCredentials[1]
437                         self._curentCredentials = username, password
438                         self._session.login(username, password)
439                 else:
440                         self._prompt_for_login()
441
442         def close(self):
443                 for diag in (
444                         self._credentialsDialog,
445                         self._smsEntryDialog,
446                         self._accountDialog,
447                 ):
448                         if diag is not None:
449                                 diag.close()
450                 qwrappers.WindowWrapper.close(self)
451
452         def destroy(self):
453                 qwrappers.WindowWrapper.destroy(self)
454                 if self._session.state != self._session.LOGGEDOUT_STATE:
455                         self._session.logout()
456
457         def get_current_tab(self):
458                 return self._currentTab
459
460         def set_current_tab(self, tabIndex):
461                 self._tabWidget.setCurrentIndex(tabIndex)
462
463         def load_settings(self, config):
464                 backendId = 2 # For backwards compatibility
465                 for tabIndex, tabTitle in enumerate(self._TAB_TITLES):
466                         sectionName = "%s - %s" % (backendId, tabTitle)
467                         settings = self._tabsContents[tabIndex].get_settings()
468                         for settingName in settings.iterkeys():
469                                 try:
470                                         settingValue = config.get(sectionName, settingName)
471                                 except ConfigParser.NoOptionError, e:
472                                         _moduleLogger.info(
473                                                 "Settings file %s is missing section %s" % (
474                                                         constants._user_settings_,
475                                                         e.section,
476                                                 ),
477                                         )
478                                         return
479                                 except ConfigParser.NoSectionError, e:
480                                         _moduleLogger.info(
481                                                 "Settings file %s is missing section %s" % (
482                                                         constants._user_settings_,
483                                                         e.section,
484                                                 ),
485                                         )
486                                         return
487                                 except Exception:
488                                         _moduleLogger.exception("Unknown loading error")
489                                         return
490                                 settings[settingName] = settingValue
491                         self._tabsContents[tabIndex].set_settings(settings)
492
493         def save_settings(self, config):
494                 backendId = 2 # For backwards compatibility
495                 for tabIndex, tabTitle in enumerate(self._TAB_TITLES):
496                         sectionName = "%s - %s" % (backendId, tabTitle)
497                         config.add_section(sectionName)
498                         tabSettings = self._tabsContents[tabIndex].get_settings()
499                         for settingName, settingValue in tabSettings.iteritems():
500                                 config.set(sectionName, settingName, settingValue)
501
502         def set_orientation(self, isPortrait):
503                 qwrappers.WindowWrapper.set_orientation(self, isPortrait)
504                 if isPortrait:
505                         self._tabWidget.setTabPosition(QtGui.QTabWidget.South)
506                 else:
507                         self._tabWidget.setTabPosition(QtGui.QTabWidget.West)
508                 for child in (self._smsEntryDialog, ):
509                         if child is not None:
510                                 child.set_orientation(isPortrait)
511
512         def _initialize_tab(self, index):
513                 assert index < self.MAX_TABS, "Invalid tab"
514                 if not self._tabsContents[index].has_child():
515                         tab = self._TAB_CLASS[index](self._app, self._session, self._errorLog)
516                         self._tabsContents[index].set_child(tab)
517                         self._tabsContents[index].refresh(force=False)
518
519         def _prompt_for_login(self):
520                 if self._credentialsDialog is None:
521                         import dialogs
522                         self._credentialsDialog = dialogs.CredentialsDialog(self._app)
523                 credentials = self._credentialsDialog.run(
524                         self._defaultCredentials[0], self._defaultCredentials[1], self.window
525                 )
526                 if credentials is None:
527                         return
528                 username, password = credentials
529                 self._curentCredentials = username, password
530                 self._session.login(username, password)
531
532         def _show_account_dialog(self):
533                 if self._accountDialog is None:
534                         import dialogs
535                         self._accountDialog = dialogs.AccountDialog(self._app)
536                         if self._app.alarmHandler is None:
537                                 self._accountDialog.setIfNotificationsSupported(False)
538                 if self._app.alarmHandler is not None:
539                         self._accountDialog.notifications = self._app.alarmHandler.isEnabled
540                         self._accountDialog.notificationTime = self._app.alarmHandler.recurrence
541                         self._accountDialog.notifyOnMissed = self._app.notifyOnMissed
542                         self._accountDialog.notifyOnVoicemail = self._app.notifyOnVoicemail
543                         self._accountDialog.notifyOnSms = self._app.notifyOnSms
544                 self._accountDialog.set_callbacks(
545                         self._session.get_callback_numbers(), self._session.get_callback_number()
546                 )
547                 self._accountDialog.accountNumber = self._session.get_account_number()
548                 response = self._accountDialog.run(self.window)
549                 if response == QtGui.QDialog.Accepted:
550                         if self._accountDialog.doClear:
551                                 self._session.logout_and_clear()
552                         else:
553                                 callbackNumber = self._accountDialog.selectedCallback
554                                 self._session.set_callback_number(callbackNumber)
555                         if self._app.alarmHandler is not None:
556                                 self._app.alarmHandler.apply_settings(self._accountDialog.notifications, self._accountDialog.notificationTime)
557                                 self._app.notifyOnMissed = self._accountDialog.notifyOnMissed
558                                 self._app.notifyOnVoicemail = self._accountDialog.notifyOnVoicemail
559                                 self._app.notifyOnSms = self._accountDialog.notifyOnSms
560                 elif response == QtGui.QDialog.Rejected:
561                         _moduleLogger.info("Cancelled")
562                 else:
563                         _moduleLogger.info("Unknown response")
564
565         @QtCore.pyqtSlot(str)
566         @misc_utils.log_exception(_moduleLogger)
567         def _on_session_error(self, message):
568                 with qui_utils.notify_error(self._errorLog):
569                         self._errorLog.push_error(message)
570
571         @QtCore.pyqtSlot()
572         @misc_utils.log_exception(_moduleLogger)
573         def _on_login(self):
574                 with qui_utils.notify_error(self._errorLog):
575                         changedAccounts = self._defaultCredentials != self._curentCredentials
576                         noCallback = not self._session.get_callback_number()
577                         if changedAccounts or noCallback:
578                                 self._show_account_dialog()
579
580                         self._defaultCredentials = self._curentCredentials
581
582                         for tab in self._tabsContents:
583                                 tab.enable()
584
585         @QtCore.pyqtSlot()
586         @misc_utils.log_exception(_moduleLogger)
587         def _on_logout(self):
588                 with qui_utils.notify_error(self._errorLog):
589                         for tab in self._tabsContents:
590                                 tab.disable()
591
592         @QtCore.pyqtSlot()
593         @misc_utils.log_exception(_moduleLogger)
594         def _on_recipients_changed(self):
595                 with qui_utils.notify_error(self._errorLog):
596                         if self._session.draft.get_num_contacts() == 0:
597                                 return
598
599                         if self._smsEntryDialog is None:
600                                 import dialogs
601                                 self._smsEntryDialog = dialogs.SMSEntryWindow(self.window, self._app, self._session, self._errorLog)
602
603         @QtCore.pyqtSlot()
604         @QtCore.pyqtSlot(bool)
605         @misc_utils.log_exception(_moduleLogger)
606         def _on_login_requested(self, checked = True):
607                 with qui_utils.notify_error(self._errorLog):
608                         self._prompt_for_login()
609
610         @QtCore.pyqtSlot(int)
611         @misc_utils.log_exception(_moduleLogger)
612         def _on_tab_changed(self, index):
613                 with qui_utils.notify_error(self._errorLog):
614                         self._currentTab = index
615                         self._initialize_tab(index)
616
617         @QtCore.pyqtSlot()
618         @QtCore.pyqtSlot(bool)
619         @misc_utils.log_exception(_moduleLogger)
620         def _on_refresh(self, checked = True):
621                 with qui_utils.notify_error(self._errorLog):
622                         self._tabsContents[self._currentTab].refresh(force=True)
623
624         @QtCore.pyqtSlot()
625         @QtCore.pyqtSlot(bool)
626         @misc_utils.log_exception(_moduleLogger)
627         def _on_import(self, checked = True):
628                 with qui_utils.notify_error(self._errorLog):
629                         csvName = QtGui.QFileDialog.getOpenFileName(self._window, caption="Import", filter="CSV Files (*.csv)")
630                         if not csvName:
631                                 return
632                         import shutil
633                         shutil.copy2(csvName, self._app.fsContactsPath)
634                         self._tabsContents[self.CONTACTS_TAB].update_addressbooks()
635
636         @QtCore.pyqtSlot()
637         @QtCore.pyqtSlot(bool)
638         @misc_utils.log_exception(_moduleLogger)
639         def _on_account(self, checked = True):
640                 with qui_utils.notify_error(self._errorLog):
641                         self._show_account_dialog()
642
643
644 def run():
645         app = QtGui.QApplication([])
646         handle = Dialcentral(app)
647         qtpie.init_pies()
648         return app.exec_()
649
650
651 if __name__ == "__main__":
652         import sys
653
654         logFormat = '(%(relativeCreated)5d) %(levelname)-5s %(threadName)s.%(name)s.%(funcName)s: %(message)s'
655         logging.basicConfig(level=logging.DEBUG, format=logFormat)
656         try:
657                 os.makedirs(constants._data_path_)
658         except OSError, e:
659                 if e.errno != 17:
660                         raise
661
662         val = run()
663         sys.exit(val)