change vocabulary

s/module/backend
s/backend/configured_backend
s/frontend/application
This commit is contained in:
Christophe Benz 2010-07-12 03:07:10 +02:00
commit 5c2ab81e16
2 changed files with 347 additions and 347 deletions

192
weboob/core/backends.py Normal file
View file

@ -0,0 +1,192 @@
# -*- coding: utf-8 -*-
# Copyright(C) 2010 Romain Bignon
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
from __future__ import with_statement
from ConfigParser import SafeConfigParser
import logging
from logging import debug, error, exception, warning
import os
import re
import stat
import weboob.backends
from weboob.capabilities.cap import ICap
from weboob.tools.backend import BaseBackend
__all__ = ['Backend', 'BackendsConfig', 'BackendsLoader']
class Backend(object):
def __init__(self, package):
self.package = package
self.klass = None
for attrname in dir(self.package):
attr = getattr(self.package, attrname)
if isinstance(attr, type) and issubclass(attr, BaseBackend) and attr != BaseBackend:
self.klass = attr
if not self.klass:
raise ImportError('%s is not a backend (no BaseBackend class found)' % package)
@property
def name(self):
return self.klass.NAME
@property
def maintainer(self):
return '%s <%s>' % (self.klass.MAINTAINER, self.klass.EMAIL)
@property
def version(self):
return self.klass.VERSION
@property
def description(self):
return self.klass.DESCRIPTION
@property
def license(self):
return self.klass.LICENSE
@property
def config(self):
return self.klass.CONFIG
@property
def icon_path(self):
return self.klass.ICON
def iter_caps(self):
for cap in self.klass.__bases__:
if issubclass(cap, ICap) and cap != ICap:
yield cap
def has_caps(self, *caps):
for c in caps:
if issubclass(self.klass, c):
return True
return False
def create_instance(self, weboob, name, config, storage):
backend_instance = self.klass(weboob, name, config, storage)
debug('Created backend instance "%s"' % name)
return backend_instance
class BackendsConfig(object):
class WrongPermissions(Exception):
pass
def __init__(self, confpath):
self.confpath = confpath
try:
mode = os.stat(confpath).st_mode
except OSError:
os.mknod(confpath, 0600)
else:
if mode & stat.S_IRGRP or mode & stat.S_IROTH:
raise self.WrongPermissions(
u'Weboob will not start until config file %s is readable by group or other users.' % confpath)
def iter_backends(self):
config = SafeConfigParser()
config.read(self.confpath)
for name in config.sections():
params = dict(config.items(name, raw=True))
try:
yield name, params.pop('_type'), params
except KeyError:
warning('Missing field "_type" for backend "%s"', name)
continue
def add_backend(self, name, _type, params, edit=False):
if not name:
raise ValueError(u'Please give a name to the backend.')
config = SafeConfigParser()
config.read(self.confpath)
if not edit:
config.add_section(name)
config.set(name, '_type', _type)
for key, value in params.iteritems():
config.set(name, key, value)
with open(self.confpath, 'wb') as f:
config.write(f)
def edit_backend(self, name, _type, params):
return self.add_backend(name, _type, params, True)
def get_backend(self, name):
config = SafeConfigParser()
config.read(self.confpath)
if not config.has_section(name):
raise KeyError(u'Backend instance "%s" not found' % name)
items = dict(config.items(name, raw=True))
try:
return items.pop('_type'), items
except KeyError:
warning('Missing field "_type" for backend "%s"', name)
raise KeyError(u'Backend "%s" not found' % name)
def remove_backend(self, name):
config = SafeConfigParser()
config.read(self.confpath)
config.remove_section(name)
with open(self.confpath, 'w') as f:
config.write(f)
class BackendsLoader(object):
def __init__(self):
self.loaded = {}
def get_or_load_backend(self, name):
if name not in self.loaded:
self.load_backend(name)
return self.loaded[name]
def iter_existing_backend_names(self):
for path in weboob.backends.__path__:
regexp = re.compile('^%s/([\w\d_]+)$' % path)
for root, dirs, files in os.walk(path):
m = regexp.match(root)
if m and '__init__.py' in files:
yield m.group(1)
def load_all(self):
for existing_backend_name in self.iter_existing_backend_names():
self.load_backend(existing_backend_name)
def load_backend(self, name):
try:
package_name = 'weboob.backends.%s' % name
backend = Backend(__import__(package_name, fromlist=[str(package_name)]))
except ImportError, e:
msg = u'Unable to load backend "%s": %s' % (name, e)
if logging.root.level == logging.DEBUG:
exception(msg)
return
else:
error(msg)
return
if backend.name in self.loaded:
debug('Backend "%s" is already loaded from %s' % (name, backend.package.__path__[0]))
return
self.loaded[backend.name] = backend
debug('Loaded backend "%s" from %s' % (name, backend.package.__path__[0]))

View file

@ -23,9 +23,9 @@ import os
import sys
from weboob.core.bcall import BackendsCall
from weboob.core.modules import ModulesLoader, BackendsConfig
from weboob.core.backend import BaseBackend
from weboob.core.backends import BackendsConfig, BackendsLoader
from weboob.core.scheduler import Scheduler
from weboob.tools.backend import BaseBackend
if sys.version_info[:2] <= (2, 5):
import weboob.tools.property
@ -40,7 +40,7 @@ class Weboob(object):
def __init__(self, workdir=WORKDIR, backends_filename=None, scheduler=None):
self.workdir = workdir
self.backends = {}
self.backend_instances = {}
# Scheduler
if scheduler is None:
@ -53,10 +53,10 @@ class Weboob(object):
elif not os.path.isdir(self.workdir):
warning('"%s" is not a directory' % self.workdir)
# Modules loader
self.modules_loader = ModulesLoader()
# Backends loader
self.backends_loader = BackendsLoader()
# Backends config
# Backend instances config
if not backends_filename:
backends_filename = os.path.join(self.workdir, self.BACKENDS_FILENAME)
elif not backends_filename.startswith('/'):
@ -64,41 +64,26 @@ class Weboob(object):
self.backends_config = BackendsConfig(backends_filename)
def load_backends(self, caps=None, names=None, storage=None):
loaded_backends = {}
for name, _type, params in self.backends_config.iter_backends():
try:
module = self.modules_loader.get_or_load_module(_type)
except KeyError:
warning(u'Unable to find module "%s" for backend "%s"' % (_type, name))
loaded = {}
self.backends_loader.load_all()
for backend_name, backend in self.backends_loader.loaded.iteritems():
if caps is not None and not backend.has_caps(caps) or \
names is not None and backend_name not in names:
continue
backend_instance = backend.create_instance(self, backend_name, {}, storage)
self.backend_instances[backend_name] = loaded[backend_name] = backend_instance
return loaded
# Check conditions
if caps is not None and not module.has_caps(caps) or \
names is not None and name not in names:
def load_configured_backends(self, caps=None, names=None, storage=None):
loaded = {}
for instance_name, backend_name, params in self.backends_config.iter_backends():
backend = self.backends_loader.get_or_load_backend(backend_name)
if caps is not None and not backend.has_caps(caps) or \
names is not None and instance_name not in names:
continue
try:
self.backends[name] = module.create_backend(self, name, params, storage)
loaded_backends[name] = self.backends[name]
except Exception, e:
warning(u'Unable to load "%s" backend: %s. filename=%s' % (name, e, self.backends_config.confpath))
return loaded_backends
def load_modules(self, caps=None, names=None, storage=None):
loaded_backends = {}
self.modules_loader.load()
for name, module in self.modules_loader.modules.iteritems():
if caps is not None and not module.has_caps(caps) or \
names is not None and name not in names:
continue
try:
name = module.get_name()
self.backends[name] = module.create_backend(self, name, {}, storage)
loaded_backends[name] = self.backends[name]
except Exception, e:
warning(u'Unable to load "%s" module as backend with no config: %s' % (name, e))
return loaded_backends
backend_instance = backend.create_instance(self, instance_name, params, storage)
self.backend_instances[instance_name] = loaded[instance_name] = backend_instance
return loaded
def iter_backends(self, caps=None):
"""
@ -109,7 +94,7 @@ class Weboob(object):
@param caps Optional list of capabilities to select backends
@return iterator on selected backends.
"""
for name, backend in sorted(self.backends.iteritems()):
for name, backend in sorted(self.backend_instances.iteritems()):
if caps is None or backend.has_caps(caps):
with backend:
yield backend
@ -134,7 +119,7 @@ class Weboob(object):
def do_caps(self, caps, function, *args, **kwargs):
"""
Do calls on loaded modules with the specified capabilities, in
Do calls on loaded backends with the specified capabilities, in
separated threads.
See also documentation of the 'do' method.
@ -156,14 +141,14 @@ class Weboob(object):
elif isinstance(backends, (list,tuple)):
old_backends = backends
backends = []
for b in old_backends:
if isinstance(b, (str,unicode)):
for backend in old_backends:
if isinstance(backend, (str,unicode)):
try:
backends.append(self.backends[self.backends.index(b)])
backends.append(self.backends[self.backends.index(backend)])
except ValueError:
pass
else:
backends.append(b)
backends.append(backend)
return BackendsCall(backends, function, *args, **kwargs)
def schedule(self, interval, function, *args):