Porting the main window to the qwappers
[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                 username, password = self._credentialsDialog.run(
524                         self._defaultCredentials[0], self._defaultCredentials[1], self.window
525                 )
526                 self._curentCredentials = username, password
527                 self._session.login(username, password)
528
529         def _show_account_dialog(self):
530                 if self._accountDialog is None:
531                         import dialogs
532                         self._accountDialog = dialogs.AccountDialog(self._app)
533                         if self._app.alarmHandler is None:
534                                 self._accountDialog.setIfNotificationsSupported(False)
535                 if self._app.alarmHandler is not None:
536                         self._accountDialog.notifications = self._app.alarmHandler.isEnabled
537                         self._accountDialog.notificationTime = self._app.alarmHandler.recurrence
538                         self._accountDialog.notifyOnMissed = self._app.notifyOnMissed
539                         self._accountDialog.notifyOnVoicemail = self._app.notifyOnVoicemail
540                         self._accountDialog.notifyOnSms = self._app.notifyOnSms
541                 self._accountDialog.set_callbacks(
542                         self._session.get_callback_numbers(), self._session.get_callback_number()
543                 )
544                 self._accountDialog.accountNumber = self._session.get_account_number()
545                 response = self._accountDialog.run(self.window)
546                 if response == QtGui.QDialog.Accepted:
547                         if self._accountDialog.doClear:
548                                 self._session.logout_and_clear()
549                         else:
550                                 callbackNumber = self._accountDialog.selectedCallback
551                                 self._session.set_callback_number(callbackNumber)
552                         if self._app.alarmHandler is not None:
553                                 self._app.alarmHandler.apply_settings(self._accountDialog.notifications, self._accountDialog.notificationTime)
554                                 self._app.notifyOnMissed = self._accountDialog.notifyOnMissed
555                                 self._app.notifyOnVoicemail = self._accountDialog.notifyOnVoicemail
556                                 self._app.notifyOnSms = self._accountDialog.notifyOnSms
557                 elif response == QtGui.QDialog.Rejected:
558                         _moduleLogger.info("Cancelled")
559                 else:
560                         _moduleLogger.info("Unknown response")
561
562         @QtCore.pyqtSlot(str)
563         @misc_utils.log_exception(_moduleLogger)
564         def _on_session_error(self, message):
565                 with qui_utils.notify_error(self._errorLog):
566                         self._errorLog.push_error(message)
567
568         @QtCore.pyqtSlot()
569         @misc_utils.log_exception(_moduleLogger)
570         def _on_login(self):
571                 with qui_utils.notify_error(self._errorLog):
572                         changedAccounts = self._defaultCredentials != self._curentCredentials
573                         noCallback = not self._session.get_callback_number()
574                         if changedAccounts or noCallback:
575                                 self._show_account_dialog()
576
577                         self._defaultCredentials = self._curentCredentials
578
579                         for tab in self._tabsContents:
580                                 tab.enable()
581
582         @QtCore.pyqtSlot()
583         @misc_utils.log_exception(_moduleLogger)
584         def _on_logout(self):
585                 with qui_utils.notify_error(self._errorLog):
586                         for tab in self._tabsContents:
587                                 tab.disable()
588
589         @QtCore.pyqtSlot()
590         @misc_utils.log_exception(_moduleLogger)
591         def _on_recipients_changed(self):
592                 with qui_utils.notify_error(self._errorLog):
593                         if self._session.draft.get_num_contacts() == 0:
594                                 return
595
596                         if self._smsEntryDialog is None:
597                                 import dialogs
598                                 self._smsEntryDialog = dialogs.SMSEntryWindow(self.window, self._app, self._session, self._errorLog)
599
600         @QtCore.pyqtSlot()
601         @QtCore.pyqtSlot(bool)
602         @misc_utils.log_exception(_moduleLogger)
603         def _on_login_requested(self, checked = True):
604                 with qui_utils.notify_error(self._errorLog):
605                         self._prompt_for_login()
606
607         @QtCore.pyqtSlot(int)
608         @misc_utils.log_exception(_moduleLogger)
609         def _on_tab_changed(self, index):
610                 with qui_utils.notify_error(self._errorLog):
611                         self._currentTab = index
612                         self._initialize_tab(index)
613
614         @QtCore.pyqtSlot()
615         @QtCore.pyqtSlot(bool)
616         @misc_utils.log_exception(_moduleLogger)
617         def _on_refresh(self, checked = True):
618                 with qui_utils.notify_error(self._errorLog):
619                         self._tabsContents[self._currentTab].refresh(force=True)
620
621         @QtCore.pyqtSlot()
622         @QtCore.pyqtSlot(bool)
623         @misc_utils.log_exception(_moduleLogger)
624         def _on_import(self, checked = True):
625                 with qui_utils.notify_error(self._errorLog):
626                         csvName = QtGui.QFileDialog.getOpenFileName(self._window, caption="Import", filter="CSV Files (*.csv)")
627                         if not csvName:
628                                 return
629                         import shutil
630                         shutil.copy2(csvName, self._app.fsContactsPath)
631                         self._tabsContents[self.CONTACTS_TAB].update_addressbooks()
632
633         @QtCore.pyqtSlot()
634         @QtCore.pyqtSlot(bool)
635         @misc_utils.log_exception(_moduleLogger)
636         def _on_account(self, checked = True):
637                 with qui_utils.notify_error(self._errorLog):
638                         self._show_account_dialog()
639
640
641 def run():
642         app = QtGui.QApplication([])
643         handle = Dialcentral(app)
644         qtpie.init_pies()
645         return app.exec_()
646
647
648 if __name__ == "__main__":
649         import sys
650
651         logFormat = '(%(relativeCreated)5d) %(levelname)-5s %(threadName)s.%(name)s.%(funcName)s: %(message)s'
652         logging.basicConfig(level=logging.DEBUG, format=logFormat)
653         try:
654                 os.makedirs(constants._data_path_)
655         except OSError, e:
656                 if e.errno != 17:
657                         raise
658
659         val = run()
660         sys.exit(val)