pax_global_header 0000666 0000000 0000000 00000000064 13723172202 0014511 g ustar 00root root 0000000 0000000 52 comment=c10d82766b8a29dded385ecb3c3eba9262a5834a
woob-c10d82766b8a29dded385ecb3c3eba9262a5834a-tools-boilerplate/ 0000775 0000000 0000000 00000000000 13723172202 0023256 5 ustar 00root root 0000000 0000000 woob-c10d82766b8a29dded385ecb3c3eba9262a5834a-tools-boilerplate/tools/ 0000775 0000000 0000000 00000000000 13723172202 0024416 5 ustar 00root root 0000000 0000000 woob-c10d82766b8a29dded385ecb3c3eba9262a5834a-tools-boilerplate/tools/boilerplate/ 0000775 0000000 0000000 00000000000 13723172202 0026720 5 ustar 00root root 0000000 0000000 woob-c10d82766b8a29dded385ecb3c3eba9262a5834a-tools-boilerplate/tools/boilerplate/__init__.py 0000664 0000000 0000000 00000000000 13723172202 0031017 0 ustar 00root root 0000000 0000000 woob-c10d82766b8a29dded385ecb3c3eba9262a5834a-tools-boilerplate/tools/boilerplate/boilerplate.py 0000775 0000000 0000000 00000004376 13723172202 0031611 0 ustar 00root root 0000000 0000000 #! /usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright(C) 2013-2019 Laurent Bachelier, Sébastien Jean
#
# This file is part of weboob.
#
# weboob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# weboob 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with weboob. If not, see .
from __future__ import print_function
import argparse
import os
import subprocess
import sys
from importlib import import_module
BOILERPLATE_PATH = os.getenv(
'BOILERPLATE_PATH',
os.path.realpath(os.path.join(os.path.dirname(__file__), 'boilerplate_data')))
sys.path.append(os.path.dirname(__file__))
sys.path.append(BOILERPLATE_PATH)
from recipe import Recipe # NOQA
def u8(s):
if isinstance(s, bytes):
return s.decode('utf-8')
return s
def gitconfig(entry):
return u8(subprocess.check_output('git config -z --get %s' % entry, shell=True)[:-1])
def main():
parser = argparse.ArgumentParser()
parser.add_argument(
'-a', '--author',
default=gitconfig('user.name'), type=u8)
parser.add_argument(
'-e', '--email',
default=gitconfig('user.email'), type=u8)
subparsers = parser.add_subparsers(dest='recipe')
subparsers.required = True
recipes_module = import_module('recipes', package='boilerplate_data')
if hasattr(recipes_module, '__all__'):
for k in recipes_module.__all__:
getattr(recipes_module, k).configure_subparser(subparsers)
else:
for k in dir(recipes_module):
print(k)
if issubclass(getattr(recipes_module, k), Recipe) and not k.startswith('_'):
getattr(recipes_module, k).configure_subparser(subparsers)
args = parser.parse_args()
recipe = args.recipe_class(args)
recipe.generate()
if __name__ == '__main__':
main()
woob-c10d82766b8a29dded385ecb3c3eba9262a5834a-tools-boilerplate/tools/boilerplate/boilerplate_data/ 0000775 0000000 0000000 00000000000 13723172202 0032213 5 ustar 00root root 0000000 0000000 base_browser.pyt 0000664 0000000 0000000 00000001173 13723172202 0035351 0 ustar 00root root 0000000 0000000 woob-c10d82766b8a29dded385ecb3c3eba9262a5834a-tools-boilerplate/tools/boilerplate/boilerplate_data <%inherit file="layout.pyt"/>
from weboob.browser import ${'LoginBrowser, need_login' if r.login else 'PagesBrowser'}, URL
from .pages import Page1, Page2
class ${r.classname}Browser(${'Login' if r.login else 'Pages'}Browser):
BASEURL = 'http://www.${r.name}.com'
page1 = URL('/page1\?id=(?P.+)', Page1)
page2 = URL('/page2', Page2)
% if login:
def do_login(self):
pass
@need_login
% endif
def get_stuff(self, _id):
self.page1.go(id=_id)
assert self.page1.is_here()
self.page.do_stuff(_id)
assert self.page2.is_here()
return self.page.do_more_stuff()
base_module.pyt 0000664 0000000 0000000 00000000613 13723172202 0035151 0 ustar 00root root 0000000 0000000 woob-c10d82766b8a29dded385ecb3c3eba9262a5834a-tools-boilerplate/tools/boilerplate/boilerplate_data <%inherit file="layout.pyt"/>
from weboob.tools.backend import Module
from .browser import ${r.classname}Browser
__all__ = ['${r.classname}Module']
class ${r.classname}Module(Module):
NAME = '${r.name}'
DESCRIPTION = '${r.name} website'
MAINTAINER = '${r.author}'
EMAIL = '${r.email}'
LICENSE = 'LGPLv3+'
VERSION = '${r.version}'
BROWSER = ${r.classname}Browser
base_pages.pyt 0000664 0000000 0000000 00000000374 13723172202 0034767 0 ustar 00root root 0000000 0000000 woob-c10d82766b8a29dded385ecb3c3eba9262a5834a-tools-boilerplate/tools/boilerplate/boilerplate_data <%inherit file="layout.pyt"/>
from weboob.browser.pages import HTMLPage
class Page1(HTMLPage):
def do_stuff(self, _id):
raise NotImplementedError()
class Page2(HTMLPage):
def do_more_stuff(self):
raise NotImplementedError()
base_test.pyt 0000664 0000000 0000000 00000000212 13723172202 0034636 0 ustar 00root root 0000000 0000000 woob-c10d82766b8a29dded385ecb3c3eba9262a5834a-tools-boilerplate/tools/boilerplate/boilerplate_data <%inherit file="layout.pyt"/>
from weboob.tools.test import BackendTest
class ${r.classname}Test(BackendTest):
MODULE = '${r.name}'
cap_module.pyt 0000664 0000000 0000000 00000001626 13723172202 0035007 0 ustar 00root root 0000000 0000000 woob-c10d82766b8a29dded385ecb3c3eba9262a5834a-tools-boilerplate/tools/boilerplate/boilerplate_data <%inherit file="layout.pyt"/>
from weboob.tools.backend import Module${', BackendConfig' if r.login else ''}
% if login:
from weboob.tools.value import Value, ValueBackendPassword
% endif
from ${r.capmodulename} import ${r.capname}
from .browser import ${r.classname}Browser
__all__ = ['${r.classname}Module']
class ${r.classname}Module(Module, ${r.capname}):
NAME = '${r.name}'
DESCRIPTION = '${r.name} website'
MAINTAINER = '${r.author}'
EMAIL = '${r.email}'
LICENSE = 'LGPLv3+'
VERSION = '${r.version}'
BROWSER = ${r.classname}Browser
% if login:
CONFIG = BackendConfig(
Value('username', help='Username'),
ValueBackendPassword('password', help='Password'),
)
def create_default_browser(self):
return self.create_browser(self.config['username'].get(), self.config['password'].get())
% endif
% for meth in r.methods:
${''.join(meth)}
% endfor
comic_module.pyt 0000664 0000000 0000000 00000001400 13723172202 0035324 0 ustar 00root root 0000000 0000000 woob-c10d82766b8a29dded385ecb3c3eba9262a5834a-tools-boilerplate/tools/boilerplate/boilerplate_data <%inherit file="layout.pyt"/>
from weboob.tools.capabilities.gallery.genericcomicreader import GenericComicReaderModule, DisplayPage
__all__ = ['${r.classname}Module']
class ${r.classname}Module(GenericComicReaderModule):
NAME = '${r.name}'
DESCRIPTION = u'${r.name} manga reading site'
MAINTAINER = u'${r.author}'
EMAIL = '${r.email}'
VERSION = '${r.version}'
LICENSE = 'LGPLv3+'
DOMAIN = 'www.${r.name}.com'
BROWSER_PARAMS = dict(
img_src_xpath="//img[@id='comic_page']/@src",
page_list_xpath="(//select[@id='page_select'])[1]/option/@value")
ID_REGEXP = r'[^/]+/[^/]+'
URL_REGEXP = r'.+${r.name}.com/(%s).+' % ID_REGEXP
ID_TO_URL = 'http://www.${r.name}.com/%s'
PAGES = {URL_REGEXP: DisplayPage}
comic_test.pyt 0000664 0000000 0000000 00000000443 13723172202 0035024 0 ustar 00root root 0000000 0000000 woob-c10d82766b8a29dded385ecb3c3eba9262a5834a-tools-boilerplate/tools/boilerplate/boilerplate_data <%inherit file="layout.pyt"/>
from weboob.tools.capabilities.gallery.genericcomicreadertest import GenericComicReaderTest
class ${r.classname}BackendTest(GenericComicReaderTest):
MODULE = '${r.name}'
def test_download(self):
return self._test_download('${r.download_id}')
init.pyt 0000664 0000000 0000000 00000000154 13723172202 0033635 0 ustar 00root root 0000000 0000000 woob-c10d82766b8a29dded385ecb3c3eba9262a5834a-tools-boilerplate/tools/boilerplate/boilerplate_data <%inherit file="layout.pyt"/>
from .module import ${r.classname}Module
__all__ = ['${r.classname}Module']
layout.pyt 0000664 0000000 0000000 00000001472 13723172202 0034213 0 ustar 00root root 0000000 0000000 woob-c10d82766b8a29dded385ecb3c3eba9262a5834a-tools-boilerplate/tools/boilerplate/boilerplate_data ${coding}
# Copyright(C) ${r.year} ${r.author}
#
# This file is part of a weboob module.
#
# This weboob module is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This weboob module 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this weboob module. If not, see .
from __future__ import unicode_literals
${self.body()}\
recipes.py 0000664 0000000 0000000 00000011100 13723172202 0034131 0 ustar 00root root 0000000 0000000 woob-c10d82766b8a29dded385ecb3c3eba9262a5834a-tools-boilerplate/tools/boilerplate/boilerplate_data # -*- coding: utf-8 -*-
# Copyright(C) 2013-2019 Laurent Bachelier, Sébastien Jean
#
# This file is part of weboob.
#
# weboob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# weboob 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with weboob. If not, see .
from __future__ import print_function
import importlib
import sys
from recipe import Recipe
__all__ = ['BaseRecipe', 'CapRecipe', 'ComicRecipe', 'ComicTestRecipe']
class BaseRecipe(Recipe):
NAME = 'base'
def generate(self):
self.write('__init__.py', self.template('init'))
self.write('module.py', self.template('base_module'))
self.write('browser.py', self.template('base_browser'))
self.write('pages.py', self.template('base_pages'))
self.write('test.py', self.template('base_test'))
class CapRecipe(Recipe):
NAME = 'cap'
def __init__(self, args):
super(CapRecipe, self).__init__(args)
self.capname = args.capname
self.login = args.login
@classmethod
def configure_subparser(cls, subparsers):
subparser = super(CapRecipe, cls).configure_subparser(subparsers)
subparser.add_argument('--login', action='store_true', help='The site requires login')
subparser.add_argument('capname', help='Capability name')
return subparser
def find_module_cap(self):
if '.' not in self.capname:
return self.search_cap()
PREFIX = 'weboob.capabilities.'
if not self.capname.startswith(PREFIX):
self.capname = PREFIX + self.capname
try:
self.capmodulename, self.capname = self.capname.rsplit('.', 1)
except ValueError:
self.error('Cap name must be in format module.CapSomething or CapSomething')
try:
module = importlib.import_module(self.capmodulename)
except ImportError:
self.error('Module %r not found' % self.capmodulename)
try:
cap = getattr(module, self.capname)
except AttributeError:
self.error('Module %r has no such capability %r' % (self.capmodulename, self.capname))
return cap
def search_cap(self):
import pkgutil
import weboob.capabilities
modules = pkgutil.walk_packages(weboob.capabilities.__path__, prefix='weboob.capabilities.')
for _, capmodulename, __ in modules:
module = importlib.import_module(capmodulename)
if hasattr(module, self.capname):
self.capmodulename = capmodulename
return getattr(module, self.capname)
self.error('Capability %r not found' % self.capname)
def error(self, message):
print(message, file=sys.stderr)
sys.exit(1)
def methods_code(self, klass):
import inspect
methods = []
for name, member in inspect.getmembers(klass):
if inspect.ismethod(member) and name in klass.__dict__:
lines, _ = inspect.getsourcelines(member)
methods.append(lines)
return methods
def generate(self):
cap = self.find_module_cap()
self.methods = self.methods_code(cap)
self.write('__init__.py', self.template('init'))
self.write('module.py', self.template('cap_module'))
self.write('browser.py', self.template('base_browser'))
self.write('pages.py', self.template('base_pages'))
self.write('test.py', self.template('base_test'))
class ComicRecipe(Recipe):
NAME = 'comic'
def generate(self):
self.write('__init__.py', self.template('init'))
self.write('module.py', self.template('comic_module'))
class ComicTestRecipe(Recipe):
NAME = 'comic.test'
@classmethod
def configure_subparser(cls, subparsers):
subparser = super(ComicTestRecipe, cls).configure_subparser(subparsers)
subparser.add_argument('download_id', help='Download ID')
return subparser
def __init__(self, args):
super(ComicTestRecipe, self).__init__(args)
self.download_id = args.download_id
def generate(self):
self.write('test.py', self.template('comic_test'))
woob-c10d82766b8a29dded385ecb3c3eba9262a5834a-tools-boilerplate/tools/boilerplate/recipe.py 0000664 0000000 0000000 00000005365 13723172202 0030552 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2013-2019 Laurent Bachelier, Sébastien Jean
#
# This file is part of weboob.
#
# weboob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# weboob 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with weboob. If not, see .
from __future__ import print_function
import codecs
import datetime
import os
import sys
from mako.lookup import TemplateLookup
from weboob import __version__
WEBOOB_MODULES = os.getenv(
'WEBOOB_MODULES',
os.path.realpath(os.path.join(os.path.dirname(__file__), '../../modules')))
BOILERPLATE_PATH = os.getenv(
'BOILERPLATE_PATH',
os.path.realpath(os.path.join(os.path.dirname(__file__), 'boilerplate_data')))
TEMPLATES = TemplateLookup(directories=[BOILERPLATE_PATH], input_encoding='utf-8')
def write(target, contents):
if not os.path.isdir(os.path.dirname(target)):
os.makedirs(os.path.dirname(target))
if os.path.exists(target):
print("%s already exists." % target, file=sys.stderr)
sys.exit(4)
with codecs.open(target, mode='w', encoding='utf-8') as f:
f.write(contents)
print('Created %s' % target)
class Recipe(object):
@classmethod
def configure_subparser(cls, subparsers):
subparser = subparsers.add_parser(cls.NAME)
subparser.add_argument('name', help='Module name')
subparser.set_defaults(recipe_class=cls)
return subparser
def __init__(self, args):
self.name = args.name.lower().replace(' ', '')
self.classname = args.name.title().replace(' ', '').replace('_', '')
self.year = datetime.date.today().year
self.author = args.author
self.email = args.email
self.version = __version__
self.login = False
def write(self, filename, contents):
return write(os.path.join(WEBOOB_MODULES, self.name, filename), contents)
def template(self, name, **kwargs):
if '.' not in name:
name += '.pyt'
return TEMPLATES.get_template(name) \
.render(r=self,
# workaround, as it's also a mako directive
coding='# -*- coding: utf-8 -*-',
login=self.login,
**kwargs).strip() + u'\n'
def generate(self):
raise NotImplementedError()