From 7fc7478c979751606da53b7f9d5fbed0225f971d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 20 Apr 2011 14:06:56 -0600 Subject: [PATCH] Delay load calibre C extensions. Worker launch is now under 0.07 seconds (only about 3 times the time taken to launch bare python) --- src/calibre/constants.py | 64 +++++++++++++++++++++++----------- src/calibre/devices/scanner.py | 2 +- src/calibre/gui2/main.py | 6 ++-- 3 files changed, 48 insertions(+), 24 deletions(-) diff --git a/src/calibre/constants.py b/src/calibre/constants.py index 62612d9c66..a15ffbf967 100644 --- a/src/calibre/constants.py +++ b/src/calibre/constants.py @@ -12,7 +12,7 @@ __author__ = u"Kovid Goyal " Various run time constants. ''' -import sys, locale, codecs, os, importlib +import sys, locale, codecs, os, importlib, collections _tc = None def terminal_controller(): @@ -52,15 +52,12 @@ def debug(): DEBUG = True # plugins {{{ -plugins = None -if plugins is None: - # Load plugins - def load_plugins(): - plugins = {} - plugin_path = sys.extensions_location - sys.path.insert(0, plugin_path) - for plugin in [ +class Plugins(collections.Mapping): + + def __init__(self): + self._plugins = {} + plugins = [ 'pictureflow', 'lzx', 'msdes', @@ -74,19 +71,44 @@ if plugins is None: 'chm_extra', 'icu', 'speedup', - ] + \ - (['winutil'] if iswindows else []) + \ - (['usbobserver'] if isosx else []): - try: - p, err = importlib.import_module(plugin), '' - except Exception as err: - p = None - err = str(err) - plugins[plugin] = (p, err) - sys.path.remove(plugin_path) - return plugins + ] + if iswindows: + plugins.append('winutil') + if isosx: + plugins.append(['usbobserver']) + self.plugins = frozenset(plugins) - plugins = load_plugins() + def load_plugin(self, name): + if name in self._plugins: + return + sys.path.insert(0, sys.extensions_location) + try: + p, err = importlib.import_module(name), '' + except Exception as err: + p = None + err = str(err) + self._plugins[name] = (p, err) + sys.path.remove(sys.extensions_location) + + def __iter__(self): + return iter(self.plugins) + + def __len__(self): + return len(self.plugins) + + def __contains__(self, name): + return name in self.plugins + + def __getitem__(self, name): + if name not in self.plugins: + raise KeyError('No plugin named %r'%name) + self.load_plugin(name) + return self._plugins[name] + + +plugins = None +if plugins is None: + plugins = Plugins() # }}} # config_dir {{{ diff --git a/src/calibre/devices/scanner.py b/src/calibre/devices/scanner.py index c63eada0c8..9b729a3561 100644 --- a/src/calibre/devices/scanner.py +++ b/src/calibre/devices/scanner.py @@ -8,7 +8,7 @@ manner. import sys, os, re from threading import RLock -from calibre import iswindows, isosx, plugins, islinux +from calibre.constants import iswindows, isosx, plugins, islinux osx_scanner = win_scanner = linux_scanner = None diff --git a/src/calibre/gui2/main.py b/src/calibre/gui2/main.py index c67ec8c2b4..ee18d8e9ca 100644 --- a/src/calibre/gui2/main.py +++ b/src/calibre/gui2/main.py @@ -19,6 +19,9 @@ from calibre.utils.config import prefs, dynamic from calibre.library.database2 import LibraryDatabase2 from calibre.library.sqlite import sqlite, DatabaseException +if iswindows: + winutil = plugins['winutil'][0] + def option_parser(): parser = _option_parser('''\ %prog [opts] [path_to_ebook] @@ -80,8 +83,7 @@ def get_library_path(parent=None): if library_path is None: # Need to migrate to new database layout base = os.path.expanduser('~') if iswindows: - base = plugins['winutil'][0].special_folder_path( - plugins['winutil'][0].CSIDL_PERSONAL) + base = winutil.special_folder_path(winutil.CSIDL_PERSONAL) if not base or not os.path.exists(base): from PyQt4.Qt import QDir base = unicode(QDir.homePath()).replace('/', os.sep)