Commit 5c2ab81e authored by Christophe Benz's avatar Christophe Benz

change vocabulary

s/module/backend
s/backend/configured_backend
s/frontend/application
parent 29d28ba1
......@@ -35,7 +35,7 @@ class Boobank(ConsoleApplication):
COPYRIGHT = 'Copyright(C) 2010 Romain Bignon'
def main(self, argv):
self.load_backends(ICapBank)
self.load_configured_backends(ICapBank)
return self.process_command(*argv[1:])
@ConsoleApplication.command('List every available accounts')
......
......@@ -32,7 +32,7 @@ class Chatoob(ConsoleApplication):
COPYRIGHT = 'Copyright(C) 2010 Christophe Benz'
def main(self, argv):
self.load_backends(ICapChat)
self.load_configured_backends(ICapChat)
#for backend, result in self.weboob.do('start_chat_polling', self.on_new_chat_message):
#logging.info(u'Polling chat messages for backend %s' % backend)
return self.process_command(*argv[1:])
......
......@@ -38,7 +38,7 @@ class HaveSex(PromptApplication):
def main(self, argv):
self.load_config()
self.load_backends(ICapDating, storage=self.create_storage(self.STORAGE_FILENAME))
self.load_configured_backends(ICapDating, storage=self.create_storage(self.STORAGE_FILENAME))
self.weboob.do('init_optimizations').wait()
......
......@@ -233,7 +233,6 @@ class Masstransit(BaseApplication):
COPYRIGHT = 'Copyright(C) 2010 Julien Hébert'
def main(self, argv):
"main fonction"
self.load_modules(ICapTravel)
self.load_backends(ICapTravel)
MasstransitHildon(self.weboob)
gtk.main()
......@@ -93,7 +93,7 @@ class Monboob(ConsoleApplication):
def main(self, argv):
self.load_config()
self.load_backends(ICapMessages, storage=self.create_storage())
self.load_configured_backends(ICapMessages, storage=self.create_storage())
return self.process_command(*argv[1:])
......
......@@ -36,10 +36,10 @@ class MainWindow(QtMainWindow):
self.setCentralWidget(self.manager)
self.connect(self.ui.actionModules, SIGNAL("triggered()"), self.modulesConfig)
self.connect(self.ui.actionBackends, SIGNAL("triggered()"), self.backendsConfig)
self.connect(self.ui.actionRefresh, SIGNAL("triggered()"), self.refresh)
def modulesConfig(self):
def backendsConfig(self):
bckndcfg = BackendCfg(self.weboob, (ICapMessages,), self)
bckndcfg.show()
......
......@@ -27,7 +27,7 @@ class QBoobMsg(QtApplication):
COPYRIGHT = 'Copyright(C) 2010 Romain Bignon'
def main(self, argv):
self.load_backends(ICapMessages, storage=self.create_storage())
self.load_configured_backends(ICapMessages, storage=self.create_storage())
self.main_window = MainWindow(self.config, self.weboob)
self.main_window.show()
......
......@@ -29,7 +29,7 @@
<property name="title">
<string>File</string>
</property>
<addaction name="actionModules"/>
<addaction name="actionBackends"/>
<addaction name="actionRefresh"/>
<addaction name="separator"/>
<addaction name="actionQuit"/>
......@@ -47,12 +47,12 @@
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="actionModules"/>
<addaction name="actionBackends"/>
<addaction name="actionRefresh"/>
</widget>
<action name="actionModules">
<action name="actionBackends">
<property name="text">
<string>Modules</string>
<string>Backends</string>
</property>
</action>
<action name="actionQuit">
......
......@@ -44,10 +44,10 @@ class MainWindow(QtMainWindow):
self.ui.tabWidget.addTab(ContactsWidget(self.weboob), self.tr('Contacts'))
self.ui.tabWidget.addTab(QWidget(), self.tr('Calendar'))
self.connect(self.ui.actionModules, SIGNAL("triggered()"), self.modulesConfig)
self.connect(self.ui.actionBackends, SIGNAL("triggered()"), self.backendsConfig)
self.connect(self.ui.tabWidget, SIGNAL('currentChanged(int)'), self.tabChanged)
def modulesConfig(self):
def backendsConfig(self):
bckndcfg = BackendCfg(self.weboob, (ICapDating,), self)
bckndcfg.show()
......
......@@ -28,7 +28,7 @@ class QHaveSex(QtApplication):
STORAGE_FILENAME = 'dating.storage'
def main(self, argv):
self.load_backends(ICapDating, storage=self.create_storage())
self.load_configured_backends(ICapDating, storage=self.create_storage())
self.main_window = MainWindow(self.config, self.weboob)
self.main_window.show()
......
......@@ -37,7 +37,7 @@
<property name="title">
<string>File</string>
</property>
<addaction name="actionModules"/>
<addaction name="actionBackends"/>
<addaction name="separator"/>
<addaction name="actionQuit"/>
</widget>
......@@ -54,11 +54,11 @@
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="actionModules"/>
<addaction name="actionBackends"/>
</widget>
<action name="actionModules">
<action name="actionBackends">
<property name="text">
<string>Modules</string>
<string>Backends</string>
</property>
</action>
<action name="actionQuit">
......
......@@ -32,7 +32,7 @@ class QVideoob(QtApplication):
}
}
def main(self, argv):
self.load_modules(ICapVideo)
self.load_backends(ICapVideo)
self.load_config()
self.main_window = MainWindow(self.config, self.weboob)
......
......@@ -27,7 +27,7 @@ class QWeboobCfg(QtApplication):
COPYRIGHT = 'Copyright(C) 2010 Romain Bignon'
def main(self, argv):
self.load_backends()
self.load_configured_backends()
self.dlg = BackendCfg(self.weboob)
self.dlg.show()
......
......@@ -29,8 +29,7 @@ class Travel(ConsoleApplication):
COPYRIGHT = 'Copyright(C) 2010 Romain Bignon'
def main(self, argv):
self.load_modules(ICapTravel)
self.load_backends(ICapTravel)
return self.process_command(*argv[1:])
@ConsoleApplication.command('Search stations')
......
......@@ -41,7 +41,7 @@ class Videoob(ConsoleApplication):
def command_info(self, _id):
_id, backend_name = self.parse_id(_id)
names = (backend_name,) if backend_name is not None else None
self.load_modules(ICapVideo, names=names)
self.load_backends(ICapVideo, names=names)
for backend, video in self.weboob.do('get_video', _id):
if video is None:
continue
......@@ -49,7 +49,7 @@ class Videoob(ConsoleApplication):
@ConsoleApplication.command('Search for videos')
def command_search(self, pattern=None):
self.load_modules(ICapVideo)
self.load_backends(ICapVideo)
self.set_formatter_header(u'Search pattern: %s' % pattern if pattern else u'Last videos')
for backend, video in self.do('iter_search_results', pattern=pattern, nsfw=self.options.nsfw):
self.format(video, backend.name)
......@@ -72,7 +72,7 @@ class VideoobWeb(BaseApplication):
def main(self, argv):
self.load_config()
self.weboob.load_modules(ICapVideo)
self.weboob.load_backends(ICapVideo)
print 'Web server created. Listening on http://%s:%s' % (
self.config.get('host'), int(self.config.get('port')))
srv = make_server(self.config.get('host'), int(self.config.get('port')), self.make_app)
......
......@@ -44,65 +44,10 @@ class WeboobCfg(ConsoleApplication):
return False
return True
@ConsoleApplication.command('List backends')
def command_backends(self, *caps):
self.set_default_formatter('table')
self.weboob.modules_loader.load()
for name, backend in self.weboob.modules_loader.modules.iteritems():
if caps and not self.caps_included(backend.iter_caps(), caps):
continue
row = OrderedDict([('Name', name),
('Capabilities', ', '.join(cap.__name__ for cap in backend.iter_caps())),
('Description', backend.get_description()),
])
self.format(row)
@ConsoleApplication.command('List applications')
def command_applications(self, *caps):
applications = set()
import weboob.applications
for path in weboob.applications.__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:
applications.add(m.group(1))
print ' '.join(sorted(applications)).encode('utf-8')
@ConsoleApplication.command('Display information about a backend')
def command_info(self, name):
try:
backend = self.weboob.modules_loader.get_or_load_module(name)
except KeyError:
logging.error('No such backend: "%s"' % name)
return 1
print '.------------------------------------------------------------------------------.'
print '| Backend %-68s |' % backend.get_name()
print "+-----------------.------------------------------------------------------------'"
print '| Version | %s' % backend.get_version()
print '| Maintainer | %s' % backend.get_maintainer()
print '| License | %s' % backend.get_license()
print '| Description | %s' % backend.get_description()
print '| Capabilities | %s' % ', '.join([cap.__name__ for cap in backend.iter_caps()])
first = True
for key, field in backend.get_config().iteritems():
value = field.description
if not field.default is None:
value += ' (default: %s)' % field.default
if first:
print '| | '
print '| Configuration | %s: %s' % (key, value)
first = False
else:
print '| | %s: %s' % (key, value)
print "'-----------------'"
@ConsoleApplication.command('Add a configured backend')
def command_add(self, name, *options):
self.weboob.modules_loader.load()
if name not in [module_name for module_name, module in self.weboob.modules_loader.modules.iteritems()]:
self.weboob.backends_loader.load_all()
if name not in [name for name, backend in self.weboob.backends_loader.loaded.iteritems()]:
logging.error(u'Backend "%s" does not exist.' % name)
return 1
......@@ -116,9 +61,9 @@ class WeboobCfg(ConsoleApplication):
return 1
params[key] = value
# ask for params non-specified on command-line arguments
module = self.weboob.modules_loader.get_or_load_module(name)
backend = self.weboob.backends_loader.get_or_load_backend(name)
asked_config = False
for key, value in module.get_config().iteritems():
for key, value in backend.config.iteritems():
if not asked_config:
asked_config = True
print u'Configuration of backend'
......@@ -155,16 +100,74 @@ class WeboobCfg(ConsoleApplication):
except ConfigParser.DuplicateSectionError:
print u'Instance "%s" already exists for backend "%s".' % (new_name, name)
@ConsoleApplication.command('List configured backends')
@ConsoleApplication.command('Show applications')
def command_applications(self, *caps):
applications = set()
import weboob.applications
for path in weboob.applications.__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:
applications.add(m.group(1))
print ' '.join(sorted(applications)).encode('utf-8')
@ConsoleApplication.command('Show available backends')
def command_backends(self, *caps):
self.set_default_formatter('table')
self.weboob.backends_loader.load_all()
for name, backend in sorted(self.weboob.backends_loader.loaded.iteritems()):
if caps and not self.caps_included(backend.iter_caps(), caps):
continue
row = OrderedDict([('Name', name),
('Capabilities', ', '.join(cap.__name__ for cap in backend.iter_caps())),
('Description', backend.description),
])
self.format(row)
@ConsoleApplication.command('Show configured backends')
def command_configured(self):
self.set_default_formatter('table')
for instance_name, name, params in self.weboob.backends_config.iter_backends():
for instance_name, name, params in sorted(self.weboob.backends_config.iter_backends()):
row = OrderedDict([('Instance name', instance_name),
('Backend name', name),
('Configuration', ', '.join('%s=%s' % (key, value) for key, value in params.iteritems())),
])
self.format(row)
@ConsoleApplication.command('Edit configuration file')
def command_edit(self):
subprocess.call([os.environ.get('EDITOR', 'vi'), self.weboob.backends_config.confpath])
@ConsoleApplication.command('Display information about a backend')
def command_info(self, name):
try:
backend = self.weboob.backends_loader.get_or_load_backend(name)
except KeyError:
logging.error('No such backend: "%s"' % name)
return 1
print '.------------------------------------------------------------------------------.'
print '| Backend %-68s |' % backend.name
print "+-----------------.------------------------------------------------------------'"
print '| Version | %s' % backend.version
print '| Maintainer | %s' % backend.maintainer
print '| License | %s' % backend.license
print '| Description | %s' % backend.description
print '| Capabilities | %s' % ', '.join([cap.__name__ for cap in backend.iter_caps()])
first = True
for key, field in backend.config.iteritems():
value = field.description
if not field.default is None:
value += ' (default: %s)' % field.default
if first:
print '| | '
print '| Configuration | %s: %s' % (key, value)
first = False
else:
print '| | %s: %s' % (key, value)
print "'-----------------'"
@ConsoleApplication.command('Remove a configured backend')
def command_remove(self, instance_name):
try:
......@@ -172,7 +175,3 @@ class WeboobCfg(ConsoleApplication):
except ConfigParser.NoSectionError:
logging.error('Backend instance "%s" does not exist' % instance_name)
return 1
@ConsoleApplication.command('Edit configuration file')
def command_edit(self):
subprocess.call([os.environ.get('EDITOR', 'vi'), self.weboob.backends_config.confpath])
......@@ -32,14 +32,14 @@ class WeboobDebug(ConsoleApplication):
@ConsoleApplication.command('Debug backend')
def command_shell(self, backend_name):
try:
backend = self.weboob.load_modules(names=[backend_name])[backend_name]
backend = self.weboob.load_backends(names=[backend_name])[backend_name]
except KeyError:
logging.error(u'Unable to load backend "%s"' % backend_name)
return 1
browser = backend.browser
from IPython.Shell import IPShellEmbed
shell = IPShellEmbed(argv=[])
locs = dict(backend=backend, browser=browser, frontend=self, weboob=self.weboob)
locs = dict(backend=backend, browser=browser, application=self, weboob=self.weboob)
banner = 'Weboob debug shell\nBackend "%s" loaded.\nAvailable variables: %s' % (backend_name, locs)
shell.set_banner(shell.IP.BANNER + '\n\n' + banner)
shell(local_ns=locs, global_ns={})
......@@ -15,6 +15,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
from nose import run
from weboob.tools.application.console import ConsoleApplication
......@@ -32,13 +33,13 @@ class WeboobTests(ConsoleApplication):
@ConsoleApplication.command('Run tests')
def command_run(self):
self.load_modules()
self.load_backends()
self.load_configured_backends()
suite = []
for backend in self.weboob.iter_backends():
t = backend.get_test()
if t:
suite.append(t)
test = backend.get_test()
if test:
suite.append(test)
return run(suite=suite)
......@@ -33,7 +33,7 @@ class Weboorrents(ConsoleApplication):
CONFIG = {}
def main(self, argv):
self.load_backends(ICapTorrent)
self.load_configured_backends(ICapTorrent)
return self.process_command(*argv[1:])
@ConsoleApplication.command('Get information about a torrent')
......
......@@ -32,7 +32,7 @@ class WetBoobs(ConsoleApplication):
COPYRIGHT = 'Copyright(C) 2010 Romain Bignon'
def main(self, argv):
self.load_modules(ICapWeather)
self.load_backends(ICapWeather)
return self.process_command(*argv[1:])
......
......@@ -26,45 +26,50 @@ import re
import stat
import weboob.backends
from weboob.core.backend import BaseBackend
from weboob.capabilities.cap import ICap
from weboob.tools.backend import BaseBackend
__all__ = ['Module']
__all__ = ['Backend', 'BackendsConfig', 'BackendsLoader']
class Module(object):
def __init__(self, name, module):
self.name = name
self.module = module
class Backend(object):
def __init__(self, package):
self.package = package
self.klass = None
for attrname in dir(self.module):
attr = getattr(self.module, attrname)
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("This is not a backend module (no BaseBackend class found)")
raise ImportError('%s is not a backend (no BaseBackend class found)' % package)
def get_name(self):
@property
def name(self):
return self.klass.NAME
def get_maintainer(self):
@property
def maintainer(self):
return '%s <%s>' % (self.klass.MAINTAINER, self.klass.EMAIL)
def get_version(self):
@property
def version(self):
return self.klass.VERSION
def get_description(self):
@property
def description(self):
return self.klass.DESCRIPTION
def get_license(self):
@property
def license(self):
return self.klass.LICENSE
def get_config(self):
@property
def config(self):
return self.klass.CONFIG
def get_icon_path(self):
@property
def icon_path(self):
return self.klass.ICON
def iter_caps(self):
......@@ -78,9 +83,11 @@ class Module(object):
return True
return False
def create_backend(self, weboob, name, config, storage):
debug('Created backend "%s"' % name)
return self.klass(weboob, name, config, storage)
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):
......@@ -128,7 +135,7 @@ class BackendsConfig(object):
config = SafeConfigParser()
config.read(self.confpath)
if not config.has_section(name):
raise KeyError(u'Backend "%s" not found' % name)
raise KeyError(u'Backend instance "%s" not found' % name)
items = dict(config.items(name, raw=True))
try:
......@@ -141,19 +148,20 @@ class BackendsConfig(object):
config = SafeConfigParser()
config.read(self.confpath)
config.remove_section(name)
with open(self.confpath, 'wb') as f:
with open(self.confpath, 'w') as f:
config.write(f)
class ModulesLoader(object):
class BackendsLoader(object):
def __init__(self):
self.modules = {}
self.loaded = {}
def get_or_load_module(self, name):
if name not in self.modules:
self.load_module('weboob.backends.%s' % name)
return self.modules[name]
def get_or_load_backend(self, name):
if name not in self.loaded:
self.load_backend(name)
return self.loaded[name]
def iter_existing_module_names(self):
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):
......@@ -161,23 +169,24 @@ class ModulesLoader(object):
if m and '__init__.py' in files:
yield m.group(1)
def load(self):
for existing_module_name in self.iter_existing_module_names():
self.load_module('weboob.backends.%s' % existing_module_name)
def load_all(self):
for existing_backend_name in self.iter_existing_backend_names():
self.load_backend(existing_backend_name)
def load_module(self, name):
def load_backend(self, name):
try:
module = Module(name, __import__(name, fromlist=[str(name)]))
package_name = 'weboob.backends.%s' % name
backend = Backend(__import__(package_name, fromlist=[str(package_name)]))
except ImportError, e:
msg = 'Unable to load module "%s": %s' % (name, 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 module.get_name() in self.modules:
warning('Module "%s" is already loaded (%s)' % (self.modules[module.get_name()].module, name))
if backend.name in self.loaded:
debug('Backend "%s" is already loaded from %s' % (name, backend.package.__path__[0]))
return
self.modules[module.get_name()] = module
debug('Loaded module "%s" from %s' % (name, module.module.__path__))
self.loaded[backend.name] = backend
debug('Loaded backend "%s" from %s' % (name, backend.package.__path__[0]))
......@@ -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
# Check conditions
if caps is not None and not module.has_caps(caps) or \
names is not None and 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:
backend_instance = backend.create_instance(self, backend_name, {}, storage)
self.backend_instances[backend_name] = loaded[backend_name] = backend_instance
return loaded
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:
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):