- """
-
- def __call__(self, item):
- self.encoding = item.page.ENCODING if item.page.ENCODING else 'utf-8'
- return self.filter(self.select(self.selector, item))
-
- @debug()
- def filter(self, txt):
- try:
- try:
- from urllib.parse import unquote
- txt = unquote(txt, self.encoding)
- except ImportError:
- from urllib import unquote
- txt = unquote(txt.encode('ascii')).decode(self.encoding)
- except (UnicodeDecodeError, UnicodeEncodeError):
- pass
-
- return txt
-
-
-from weboob.browser.filters.standard import Env as _Env
-class Env(_Env):
- """
- Filter to get environment value of the item.
-
- It is used for example to get page parameters, or when there is a parse()
- method on ItemElement.
- """
-
- def __init__(self, name, default=_NO_DEFAULT):
- super(Env, self).__init__(default)
- self.name = name
-
- def __call__(self, item):
- try:
- return item.env[self.name]
- except KeyError:
- return self.default_or_raise(ItemNotFound('Environment variable %s not found' % self.name))
-
-
-from weboob.browser.filters.standard import TableCell as _TableCell
-class TableCell(_TableCell):
- """
- Used with TableElement, gets the cell element from its name.
-
- For example:
-
- >>> from weboob.capabilities.bank import Transaction
- >>> from weboob.browser.elements import TableElement, ItemElement
- >>> class table(TableElement):
- ... head_xpath = '//table/thead/th'
- ... item_xpath = '//table/tbody/tr'
- ... col_date = u'Date'
- ... col_label = [u'Name', u'Label']
- ... class item(ItemElement):
- ... klass = Transaction
- ... obj_date = Date(TableCell('date'))
- ... obj_label = CleanText(TableCell('label'))
- ...
-
- The 'colspan' variable enables the handling of table tags that have
- a "colspan" attribute that modify the width of the column:
- for example will occupy two columns instead of one,
- creating a column shift for all the next columns that must be taken
- in consideration when trying to match columns values with column heads.
- """
-
- def __init__(self, *names, **kwargs):
- support_th = kwargs.pop('support_th', False)
- self.colspan = kwargs.pop('colspan', False)
- super(TableCell, self).__init__(**kwargs)
- self.names = names
-
- if support_th:
- self.td = '(./th | ./td)[%s]'
- else:
- self.td = './td[%s]'
-
- """
- The two methods below are used to verify that modifying TableCell
- to handle colspans does not modify the class behavior in weboob modules.
- The "assert" should crash if a module does not return the same results
- with and without handling colspans.
- """
-
- def call_without_colspan(self, item):
- # Former behavior without handling colspans > 1
- for name in self.names:
- idx = item.parent.get_colnum(name)
- if idx is not None:
- ret = item.xpath(self.td % (idx + 1))
- for el in ret:
- self.highlight_el(el, item)
- return ret
- return self.default_or_raise(ColumnNotFound('Unable to find column %s' % ' or '.join(self.names)))
-
- def call_with_colspan(self, item):
- # New behavior, handling colspans > 1
- for name in self.names:
- col_idx = item.parent.get_colnum(name)
- if col_idx is not None:
- current_col = 0
- for td_idx in range(col_idx + 1):
- ret = item.xpath(self.td % (td_idx + 1))
- if col_idx <= current_col:
- for el in ret:
- self.highlight_el(el, item)
- return ret
-
- if not ret:
- # There might no be no TD at all
- # ColumnNotFound seems for case when corresponding header is not found
- # Thus for compat return empty
- return []
-
- current_col += int(ret[0].attrib.get('colspan', 1))
-
- return self.default_or_raise(ColumnNotFound('Unable to find column %s' % ' or '.join(self.names)))
-
- def __call__(self, item):
- if self.colspan:
- return self.call_with_colspan(item)
-
- ret_without_colspan = self.call_without_colspan(item)
- ret_with_colspan = self.call_with_colspan(item)
- assert ret_without_colspan == ret_with_colspan, 'Different behavior with and without colspan in TableCell'
- return ret_with_colspan
-
-
-from weboob.browser.filters.standard import RawText as _RawText
-class RawText(_RawText):
- """Get raw text from an element.
-
- Unlike :class:`CleanText`, whitespace is kept as is.
- """
-
- def __init__(self, selector=None, children=False, default=_NO_DEFAULT):
- """
- :param children: whether to get text from children elements of the select elements
- :type children: bool
- """
-
- super(RawText, self).__init__(selector, default=default)
- self.children = children
-
- @debug()
- def filter(self, el):
- if isinstance(el, (tuple, list)):
- return u' '.join([self.filter(e) for e in el])
-
- if self.children:
- text = el.text_content()
- else:
- text = el.text
-
- if text is None:
- result = self.default
- else:
- result = unicode(text)
-
- return result
-
-
-from weboob.browser.filters.standard import CleanText as _CleanText
-class CleanText(_CleanText):
- """
- Get a cleaned text from an element.
-
- It first replaces all tabs and multiple spaces
- (including newlines if ``newlines`` is True)
- to one space and strips the result string.
-
- The result is coerced into unicode, and optionally normalized
- according to the ``normalize`` argument.
-
- Then it replaces all symbols given in the ``symbols`` argument.
-
- >>> CleanText().filter('coucou ') == u'coucou'
- True
- >>> CleanText().filter(u'coucou\xa0coucou') == u'coucou coucou'
- True
- >>> CleanText(newlines=True).filter(u'coucou\\r\\n coucou ') == u'coucou coucou'
- True
- >>> CleanText(newlines=False).filter(u'coucou\\r\\n coucou ') == u'coucou\\ncoucou'
- True
- """
-
- def __init__(self, selector=None, symbols='', replace=[], children=True, newlines=True, normalize='NFC', **kwargs):
- """
- :param symbols: list of strings to remove from text
- :type symbols: list
- :param replace: optional pairs of text replacements to perform
- :type replace: list[tuple[str, str]]
- :param children: whether to get text from children elements of the select elements
- :type children: bool
- :param newlines: if True, newlines will be converted to space too
- :type newlines: bool
- :param normalize: Unicode normalization to perform
- :type normalize: str or None
- """
-
- super(CleanText, self).__init__(selector, **kwargs)
- self.symbols = symbols
- self.toreplace = replace
- self.children = children
- self.newlines = newlines
- self.normalize = normalize
-
- @debug()
- def filter(self, txt):
- if isinstance(txt, (tuple, list)):
- txt = u' '.join([self.clean(item, children=self.children) for item in txt])
-
- txt = self.clean(txt, self.children, self.newlines, self.normalize)
- txt = self.remove(txt, self.symbols)
- txt = self.replace(txt, self.toreplace)
- # ensure it didn't become str by mistake
- return unicode(txt)
-
- @classmethod
- def clean(cls, txt, children=True, newlines=True, normalize='NFC'):
- if not isinstance(txt, basestring):
- if children:
- txt = [t.strip() for t in txt.itertext()]
- else:
- txt = [t.strip() for t in txt.xpath('./text()')]
- txt = u' '.join(txt) # 'foo bar'
- if newlines:
- txt = re.compile(u'\s+', flags=re.UNICODE).sub(u' ', txt) # 'foo bar'
- else:
- # normalize newlines and clean what is inside
- txt = '\n'.join([cls.clean(l) for l in txt.splitlines()])
- txt = txt.strip()
- # lxml under Python 2 returns str instead of unicode if it is pure ASCII
- txt = unicode(txt)
- # normalize to a standard Unicode form
- if normalize:
- txt = unicodedata.normalize(normalize, txt)
- return txt
-
- @classmethod
- def remove(cls, txt, symbols):
- for symbol in symbols:
- txt = txt.replace(symbol, '')
- return txt.strip()
-
- @classmethod
- def replace(cls, txt, replace):
- for before, after in replace:
- txt = txt.replace(before, after)
- return txt
-
-
-from weboob.browser.filters.standard import Lower as _Lower
-class Lower(_Lower):
- """Extract text with :class:`CleanText` and convert to lower-case."""
-
- @debug()
- def filter(self, txt):
- txt = super(Lower, self).filter(txt)
- return txt.lower()
-
-
-from weboob.browser.filters.standard import Upper as _Upper
-class Upper(_Upper):
- """Extract text with :class:`CleanText` and convert to upper-case."""
-
- @debug()
- def filter(self, txt):
- txt = super(Upper, self).filter(txt)
- return txt.upper()
-
-
-from weboob.browser.filters.standard import Capitalize as _Capitalize
-class Capitalize(_Capitalize):
- """Extract text with :class:`CleanText` and capitalize it."""
-
- @debug()
- def filter(self, txt):
- txt = super(Capitalize, self).filter(txt)
- return txt.title()
-
-
-from weboob.browser.filters.standard import Currency as _Currency
-class Currency(_Currency):
- @debug()
- def filter(self, txt):
- txt = super(Currency, self).filter(txt)
- return BaseCurrency.get_currency(txt)
-
-
-from weboob.browser.filters.standard import NumberFormatError as _NumberFormatError
-class NumberFormatError(_NumberFormatError):
+try:
+ __all__ = OLD.__all__
+except AttributeError:
pass
-from weboob.browser.filters.standard import CleanDecimal as _CleanDecimal
-class CleanDecimal(_CleanDecimal):
- """
- Get a cleaned Decimal value from an element.
-
- `replace_dots` is False by default. A dot is interpreted as a decimal separator.
-
- If `replace_dots` is set to True, we remove all the dots. The ',' is used as decimal
- separator (often useful for French values)
-
- If `replace_dots` is a tuple, the first element will be used as the thousands separator,
- and the second as the decimal separator.
-
- See http://en.wikipedia.org/wiki/Thousands_separator#Examples_of_use
-
- For example, for the UK style (as in 1,234,567.89):
-
- >>> CleanDecimal('./td[1]', replace_dots=(',', '.')) # doctest: +SKIP
- """
-
- def __init__(self, selector=None, replace_dots=False, sign=None, legacy=True, default=_NO_DEFAULT):
- """
- :param sign: function accepting the text as param and returning the sign
- """
-
- super(CleanDecimal, self).__init__(selector, default=default)
- self.replace_dots = replace_dots
- self.sign = sign
- self.legacy = legacy
- if not legacy:
- thousands_sep, decimal_sep = self.replace_dots
- self.matching = re.compile(r'([+-]?)\s*(\d[\d%s%s]*|%s\d+)' % tuple(map(re.escape, (thousands_sep, decimal_sep, decimal_sep))))
- self.thousand_check = re.compile(r'^[+-]?\d{1,3}(%s\d{3})*(%s\d*)?$' % tuple(map(re.escape, (thousands_sep, decimal_sep))))
-
- @debug()
- def filter(self, text):
- if type(text) in (float, int, long):
- text = str(text)
-
- if empty(text):
- return self.default_or_raise(FormatError('Unable to parse %r' % text))
-
- original_text = text = super(CleanDecimal, self).filter(text)
-
- if self.legacy:
- if self.replace_dots:
- if type(self.replace_dots) is tuple:
- thousands_sep, decimal_sep = self.replace_dots
- else:
- thousands_sep, decimal_sep = '.', ','
- text = text.replace(thousands_sep, '').replace(decimal_sep, '.')
-
- text = re.sub(r'[^\d\-\.]', '', text)
- else:
- thousands_sep, decimal_sep = self.replace_dots
-
- matches = self.matching.findall(text)
- if not matches:
- return self.default_or_raise(NumberFormatError('There is no number to parse'))
- elif len(matches) > 1:
- return self.default_or_raise(NumberFormatError('There should be exactly one number to parse'))
-
- text = '%s%s' % (matches[0][0], matches[0][1].strip())
-
- if thousands_sep and thousands_sep in text and not self.thousand_check.match(text):
- return self.default_or_raise(NumberFormatError('Thousands separator is misplaced in %r' % text))
-
- text = text.replace(thousands_sep, '').replace(decimal_sep, '.')
-
- try:
- v = Decimal(text)
- if self.sign:
- v *= self.sign(original_text)
- return v
- except InvalidOperation as e:
- return self.default_or_raise(NumberFormatError(e))
-
- @classmethod
- def US(cls, *args, **kwargs):
- kwargs['legacy'] = False
- kwargs['replace_dots'] = (',', '.')
- return cls(*args, **kwargs)
-
- @classmethod
- def French(cls, *args, **kwargs):
- kwargs['legacy'] = False
- kwargs['replace_dots'] = (' ', ',')
- return cls(*args, **kwargs)
-
- @classmethod
- def SI(cls, *args, **kwargs):
- kwargs['legacy'] = False
- kwargs['replace_dots'] = (' ', '.')
- return cls(*args, **kwargs)
-
-
-from weboob.browser.filters.standard import Slugify as _Slugify
-class Slugify(_Slugify):
- @debug()
- def filter(self, label):
- label = re.sub(r'[^A-Za-z0-9]', ' ', label.lower()).strip()
- label = re.sub(r'\s+', '-', label)
- return label
-
-
-from weboob.browser.filters.standard import Type as _Type
-class Type(_Type):
+class Coalesce(MultiFilter):
"""
- Get a cleaned value of any type from an element text.
- The type_func can be any callable (class, function, etc.).
- By default an empty string will not be parsed but it can be changed
- by specifying minlen=False. Otherwise, a minimal length can be specified.
-
- >>> Type(CleanText('./td[1]'), type=int) # doctest: +SKIP
-
- >>> Type(type=int).filter(42)
- 42
- >>> Type(type=int).filter('42')
- 42
- >>> Type(type=int, default='NaN').filter('')
- 'NaN'
- >>> Type(type=list, minlen=False, default=list('ab')).filter('')
- []
- >>> Type(type=list, minlen=0, default=list('ab')).filter('')
- ['a', 'b']
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
"""
-
- def __init__(self, selector=None, type=None, minlen=0, default=_NO_DEFAULT):
- super(Type, self).__init__(selector, default=default)
- self.type_func = type
- self.minlen = minlen
-
@debug()
- def filter(self, txt):
- if isinstance(txt, self.type_func):
- return txt
- if empty(txt):
- return self.default_or_raise(FormatError('Unable to parse %r' % txt))
- if self.minlen is not False and len(txt) <= self.minlen:
- return self.default_or_raise(FormatError('Unable to parse %r' % txt))
- try:
- return self.type_func(txt)
- except ValueError as e:
- return self.default_or_raise(FormatError('Unable to parse %r: %s' % (txt, e)))
-
-
-from weboob.browser.filters.standard import Field as _Field
-class Field(_Field):
- """
- Get the attribute of object.
-
- Example::
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
- obj_foo = CleanText('//h1')
- obj_bar = Field('foo')
- will make "bar" field equal to "foo" field.
+class MapIn(Filter):
"""
-
- def __init__(self, name):
- super(Field, self).__init__()
- self.name = name
-
- def __call__(self, item):
- return item.use_selector(getattr(item, 'obj_%s' % self.name), key=self._key)
-
-
-# Based on nth from https://docs.python.org/2/library/itertools.html
-def nth(iterable, n, default=None):
- "Returns the nth item or a default value, n can be negative, or '*' for all"
- if n == '*':
- return iterable
- if n < 0:
- iterable = reversed(list(iterable))
- n = abs(n) - 1
- return next(islice(iterable, n, None), default)
-
-
-def ordinal(n):
- "To have some readable debug information: '*' => all, 0 => 1st, 1 => 2nd..."
- if n == '*':
- return 'all'
- i = abs(n)
- n = n - 1 if n < 0 else n + 1
- return str(n) + ('th' if i > 2 else ['st', 'nd', 'rd'][i])
-
-
-from weboob.browser.filters.standard import Regexp as _Regexp
-class Regexp(_Regexp):
- r"""
- Apply a regex.
-
- >>> from lxml.html import etree
- >>> doc = etree.fromstring(' Date: 13/08/1988 ')
- >>> Regexp(CleanText('//p'), r'Date: (\d+)/(\d+)/(\d+)', '\\3-\\2-\\1')(doc) == u'1988-08-13'
- True
-
- >>> (Regexp(CleanText('//body'), r'(\d+)', nth=1))(doc) == u'08'
- True
- >>> (Regexp(CleanText('//body'), r'(\d+)', nth=-1))(doc) == u'1988'
- True
- >>> (Regexp(CleanText('//body'), r'(\d+)', template='[\\1]', nth='*'))(doc) == [u'[13]', u'[08]', u'[1988]']
- True
- >>> (Regexp(CleanText('//body'), r'Date:.*'))(doc) == u'Date: 13/08/1988'
- True
- >>> (Regexp(CleanText('//body'), r'^(?!Date:).*', default=None))(doc)
- >>>
- """
-
- def __init__(self, selector=None, pattern=None, template=None, nth=0, flags=0, default=_NO_DEFAULT):
- super(Regexp, self).__init__(selector, default=default)
- assert pattern is not None
- self.pattern = pattern
- self._regex = re.compile(pattern, flags)
- self.template = template
- self.nth = nth
-
- def expand(self, m):
- if self.template is None:
- try:
- return next(g for g in m.groups() if g is not None)
- except StopIteration:
- return m.string
- return self.template(m) if callable(self.template) else m.expand(self.template)
-
- @debug()
- def filter(self, txt):
- """
- :raises: :class:`RegexpError` if `pattern` was not found
- """
-
- if isinstance(txt, (tuple, list)):
- txt = u' '.join([t.strip() for t in txt.itertext()])
-
- m = self._regex.search(txt) if self.nth == 0 else \
- nth(self._regex.finditer(txt), self.nth)
- if not m:
- msg = 'Unable to find %s %s in %r' % (ordinal(self.nth), self.pattern, txt)
- return self.default_or_raise(RegexpError(msg))
-
- if isinstance(m, Iterator):
- return list(map(self.expand, m))
-
- return self.expand(m)
-
-
-from weboob.browser.filters.standard import Map as _Map
-class Map(_Map):
- """Map selected value to another value using a dict.
-
- Example::
-
- TYPES = {
- 'Concert': CATEGORIES.CONCERT,
- 'Cinéma': CATEGORIES.CINE,
- }
-
- obj_type = Map(CleanText('./li'), TYPES)
+ Map the pattern of a selected value to another value using a dict.
"""
def __init__(self, selector, map_dict, default=_NO_DEFAULT):
"""
:param selector: key from `map_dict` to use
"""
-
- super(Map, self).__init__(selector, default=default)
+ super(MapIn, self).__init__(selector, default=default)
self.map_dict = map_dict
@debug()
def filter(self, txt):
"""
- :raises: :class:`ItemNotFound` if key does not exist in dict
- """
-
- try:
- return self.map_dict[txt]
- except KeyError:
- return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
-
-
-from weboob.browser.filters.standard import DateTime as _DateTime
-class DateTime(_DateTime):
- """Parse date and time."""
-
- def __init__(self, selector=None, default=_NO_DEFAULT, dayfirst=False, translations=None,
- parse_func=parse_date, fuzzy=False):
- """
- :param dayfirst: if True, the day is be the first element in the string to parse
- :type dayfirst: bool
- :param parse_func: the function to use for parsing the datetime
- :param translations: string replacements from site locale to English
- :type translations: list[tuple[str, str]]
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
"""
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
- super(DateTime, self).__init__(selector, default=default)
- self.dayfirst = dayfirst
- self.translations = translations
- self.parse_func = parse_func
- self.fuzzy = fuzzy
-
- @debug()
- def filter(self, txt):
- if empty(txt) or txt == '':
- return self.default_or_raise(FormatError('Unable to parse %r' % txt))
- try:
- if self.translations:
- for search, repl in self.translations:
- txt = search.sub(repl, txt)
- return self.parse_func(txt, dayfirst=self.dayfirst, fuzzy=self.fuzzy)
- except (ValueError, TypeError) as e:
- return self.default_or_raise(FormatError('Unable to parse %r: %s' % (txt, e)))
-
-
-from weboob.browser.filters.standard import Date as _Date
-class Date(_Date):
- """Parse date."""
-
- def __init__(self, selector=None, default=_NO_DEFAULT, dayfirst=False, translations=None,
- parse_func=parse_date, fuzzy=False):
- super(Date, self).__init__(selector, default=default, dayfirst=dayfirst, translations=translations,
- parse_func=parse_func, fuzzy=fuzzy)
-
- @debug()
- def filter(self, txt):
- datetime = super(Date, self).filter(txt)
- if hasattr(datetime, 'date'):
- return datetime.date()
- else:
- return datetime
-
-
-from weboob.browser.filters.standard import DateGuesser as _DateGuesser
-class DateGuesser(_DateGuesser):
- def __init__(self, selector, date_guesser, **kwargs):
- super(DateGuesser, self).__init__(selector)
- self.date_guesser = date_guesser
- self.kwargs = kwargs
-
- def __call__(self, item):
- values = self.select(self.selector, item)
- date_guesser = self.date_guesser
- # In case Env() is used to kive date_guesser.
- if isinstance(date_guesser, _Filter):
- date_guesser = self.select(date_guesser, item)
-
- if isinstance(values, basestring):
- values = re.split('[/-]', values)
- if len(values) == 2:
- day, month = map(int, values)
- else:
- raise FormatError('Unable to take (day, month) tuple from %r' % values)
- return date_guesser.guess_date(day, month, **self.kwargs)
-
-
-from weboob.browser.filters.standard import Time as _Time
-class Time(_Time):
- """Parse time."""
-
- klass = datetime.time
- _regexp = re.compile(r'(?P\d+)[:h]?(?P\d+)([:m](?P\d+))?')
- kwargs = {'hour': 'hh', 'minute': 'mm', 'second': 'ss'}
-
- def __init__(self, selector=None, default=_NO_DEFAULT):
- super(Time, self).__init__(selector, default=default)
-
- @debug()
- def filter(self, txt):
- m = self._regexp.search(txt)
- if m:
- kwargs = {}
- for key, index in self.kwargs.items():
- kwargs[key] = int(m.groupdict()[index] or 0)
- return self.klass(**kwargs)
-
- return self.default_or_raise(FormatError('Unable to find time in %r' % txt))
-
-
-from weboob.browser.filters.standard import Duration as _Duration
-class Duration(_Duration):
- """Parse a duration as timedelta."""
-
- klass = datetime.timedelta
- _regexp = re.compile(r'((?P\d+)[:;])?(?P\d+)[;:](?P\d+)')
- kwargs = {'hours': 'hh', 'minutes': 'mm', 'seconds': 'ss'}
-
-
-from weboob.browser.filters.standard import MultiFilter as _MultiFilter
-class MultiFilter(_MultiFilter):
- def __init__(self, *args, **kwargs):
- default = kwargs.pop('default', _NO_DEFAULT)
- super(MultiFilter, self).__init__(args, default)
-
- def __call__(self, item):
- values = [self.select(selector, item) for selector in self.selector]
- return self.filter(tuple(values))
-
- def filter(self, values):
- raise NotImplementedError()
-
-
-from weboob.browser.filters.standard import CombineDate as _CombineDate
-class CombineDate(_CombineDate):
- """Combine separate Date and Time filters into a single datetime."""
-
- def __init__(self, date, time):
- """
- :type date: filter
- :type time: filter
- """
- super(CombineDate, self).__init__(date, time)
-
- @debug()
- def filter(self, values):
- return datetime.datetime.combine(values[0], values[1])
-
-
-from weboob.browser.filters.standard import Format as _Format
-class Format(_Format):
- """Combine multiple filters with string-format.
-
- Example::
-
- obj_title = Format('%s (%s)', CleanText('//h1'), CleanText('//h2'))
-
- will concatenate the text from all ```` and all ```` (but put
- the latter between parentheses).
- """
-
- def __init__(self, fmt, *args):
- """
- :param fmt: string format suitable for "%"-formatting
- :type fmt: str
- :param args: other filters to insert in `fmt` string.
- There should be as many args as there are "%" in `fmt`.
- """
- super(Format, self).__init__(*args)
- self.fmt = fmt
-
- @debug()
- def filter(self, values):
- return self.fmt % values
-
-
-from weboob.browser.filters.standard import BrowserURL as _BrowserURL
-class BrowserURL(_BrowserURL):
- def __init__(self, url_name, **kwargs):
- super(BrowserURL, self).__init__(*kwargs.values())
- self.url_name = url_name
- self.keys = list(kwargs.keys())
-
- def __call__(self, item):
- values = super(BrowserURL, self).__call__(item)
- url = getattr(item.page.browser, self.url_name)
- assert isinstance(url, URL), "%s.%s must be an URL object" % (type(item.page.browser).__name__, self.url_name)
- return url.build(**dict(zip(self.keys, values)))
-
- @debug()
- def filter(self, values):
- return values
-
-
-from weboob.browser.filters.standard import Join as _Join
-class Join(_Join):
- def __init__(self, pattern, selector=None, textCleaner=CleanText, newline=False, addBefore='', addAfter=''):
- super(Join, self).__init__(selector)
- self.pattern = pattern
- self.textCleaner = textCleaner
- self.newline = newline
- self.addBefore = addBefore
- self.addAfter = addAfter
-
- @debug()
- def filter(self, el):
- items = [self.textCleaner.clean(e) for e in el]
- items = [item for item in items if item]
-
- if self.newline:
- items = ['%s\r\n' % item for item in items]
-
- result = self.pattern.join(items)
-
- if self.addBefore:
- result = '%s%s' % (self.addBefore, result)
-
- if self.addAfter:
- result = '%s%s' % (result, self.addAfter)
-
- return result
-
-
-from weboob.browser.filters.standard import Eval as _Eval
-class Eval(_Eval):
- """
- Evaluate a function with given 'deferred' arguments.
-
- >>> F = Field; Eval(lambda a, b, c: a * b + c, F('foo'), F('bar'), F('baz')) # doctest: +SKIP
- >>> Eval(lambda x, y: x * y + 1).filter([3, 7])
- 22
-
- Example::
-
- obj_ratio = Eval(lambda x: x / 100, Env('percentage'))
- """
-
- def __init__(self, func, *args):
- """
- :param func: function to apply to all filters. The function should
- accept as many args as there are filters passed to
- Eval.
- """
- super(Eval, self).__init__(*args)
- self.func = func
-
- @debug()
- def filter(self, values):
- return self.func(*values)
-
-
-from weboob.browser.filters.standard import QueryValue as _QueryValue
-class QueryValue(_QueryValue):
- """
- Extract the value of a parameter from an URL with a query string.
-
- >>> from lxml.html import etree
- >>> from .html import Link
- >>> f = QueryValue(Link('//a'), 'id')
- >>> f(etree.fromstring('')) == u'1234'
- True
- """
- def __init__(self, selector, key, default=_NO_DEFAULT):
- super(QueryValue, self).__init__(selector, default=default)
- self.querykey = key
-
- @debug()
- def filter(self, url):
- qs = parse_qs(urlparse(url).query)
- if not qs.get(self.querykey):
- return self.default_or_raise(ItemNotFound('Key %s not found' % self.querykey))
- if len(qs[self.querykey]) > 1:
- raise FilterError('More than one value for key %s' % self.querykey)
- return qs[self.querykey][0]
-
-
-class Coalesce(MultiFilter):
- """
- Returns the first value that is not falsy,
- or default if all values are falsy.
- """
- @debug()
- def filter(self, values):
- for value in values:
- if value:
- return value
- return self.default_or_raise(FilterError('All falsy and no default.'))
-
-
-def test_CleanText():
- # This test works poorly under a doctest, or would be hard to read
- assert CleanText().filter(u' coucou \n\théhé') == u'coucou héhé'
- assert CleanText().filter('coucou\xa0coucou') == CleanText().filter(u'coucou\xa0coucou') == u'coucou coucou'
-
- # Unicode normalization
- assert CleanText().filter(u'Éçã') == u'Éçã'
- assert CleanText(normalize='NFKC').filter(u'…') == u'...'
- assert CleanText().filter(u'…') == u'…'
- # Diacritical mark (dakuten)
- assert CleanText().filter(u'\u3053\u3099') == u'\u3054'
- assert CleanText(normalize='NFD').filter(u'\u3053\u3099') == u'\u3053\u3099'
- assert CleanText(normalize='NFD').filter(u'\u3054') == u'\u3053\u3099'
- assert CleanText(normalize=False).filter(u'\u3053\u3099') == u'\u3053\u3099'
-
-
-def assert_raises(exc_class, func, *args, **kwargs):
- try:
- func(*args, **kwargs)
- except exc_class:
- pass
- else:
- assert False, 'did not raise %s' % exc_class
-
-
-def test_CleanDecimal_strict():
- assert CleanDecimal.US().filter('123') == Decimal('123')
- assert CleanDecimal.US().filter('foo + 123 bar') == Decimal('123')
- assert CleanDecimal.US().filter('foo +123 bar') == Decimal('123')
- assert CleanDecimal.US().filter('foo 123.45 bar') == Decimal('123.45')
- assert CleanDecimal.US().filter('foo 12,345.67 bar') == Decimal('12345.67')
- assert CleanDecimal.US().filter('foo 123,456,789 bar') == Decimal('123456789')
- assert CleanDecimal.US().filter('foo - 123,456,789.1 bar') == Decimal('-123456789.1')
- assert CleanDecimal.US().filter('foo -123,456,789.1 bar') == Decimal('-123456789.1')
- assert CleanDecimal.US().filter('foo - .1 bar') == Decimal('-0.1')
- assert CleanDecimal.US().filter('foo -.1 bar') == Decimal('-0.1')
- assert_raises(NumberFormatError, CleanDecimal.US().filter, 'foo 12 345.67 bar')
- assert_raises(NumberFormatError, CleanDecimal.US().filter, 'foo 123 bar 456')
- assert_raises(NumberFormatError, CleanDecimal.US().filter, 'foo 123.456.789 bar')
- assert_raises(NumberFormatError, CleanDecimal.US().filter, 'foo 12,3456 bar')
- assert_raises(NumberFormatError, CleanDecimal.US().filter, 'foo 123-456 bar')
-
- assert CleanDecimal.French().filter('123') == Decimal('123')
- assert CleanDecimal.French().filter('foo + 123 bar') == Decimal('123')
- assert CleanDecimal.French().filter('foo +123 bar') == Decimal('123')
- assert CleanDecimal.French().filter('foo 123,45 bar') == Decimal('123.45')
- assert CleanDecimal.French().filter('foo 12 345,67 bar') == Decimal('12345.67')
- assert CleanDecimal.French().filter('foo - 123 456 789 bar') == Decimal('-123456789')
- assert CleanDecimal.French().filter('foo -123 456 789 bar') == Decimal('-123456789')
- assert_raises(NumberFormatError, CleanDecimal.French().filter, 'foo 123.45 bar')
- assert_raises(NumberFormatError, CleanDecimal.French().filter, 'foo 123 bar 456')
- assert_raises(NumberFormatError, CleanDecimal.French().filter, 'foo 123,456,789')
- assert_raises(NumberFormatError, CleanDecimal.French().filter, 'foo 12 3456 bar')
- assert_raises(NumberFormatError, CleanDecimal.French().filter, 'foo 123-456 bar')
-
- assert CleanDecimal.SI().filter('123') == Decimal('123')
- assert CleanDecimal.SI().filter('foo + 123 bar') == Decimal('123')
- assert CleanDecimal.SI().filter('foo +123 bar') == Decimal('123')
- assert CleanDecimal.SI().filter('foo 123.45 bar') == Decimal('123.45')
- assert CleanDecimal.SI().filter('foo 12 345.67 bar') == Decimal('12345.67')
- assert CleanDecimal.SI().filter('foo 123 456 789 bar') == Decimal('123456789')
- assert CleanDecimal.SI().filter('foo - 123 456 789 bar') == Decimal('-123456789')
- assert CleanDecimal.SI().filter('foo -123 456 789 bar') == Decimal('-123456789')
- assert_raises(NumberFormatError, CleanDecimal.SI().filter, 'foo 123,45 bar')
- assert_raises(NumberFormatError, CleanDecimal.SI().filter, 'foo 123 bar 456')
- assert_raises(NumberFormatError, CleanDecimal.SI().filter, 'foo 123,456,789')
- assert_raises(NumberFormatError, CleanDecimal.SI().filter, 'foo 12 3456 bar')
- assert_raises(NumberFormatError, CleanDecimal.SI().filter, 'foo 123-456 bar')
-
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/cragr/api/pages.py b/modules/cragr/api/pages.py
index 27cb8fd4ecd73a929f9371b2a6dd3b2e1219edfe..0ec8bc22f5b4baef46daf8768a9f110cadc84dde 100644
--- a/modules/cragr/api/pages.py
+++ b/modules/cragr/api/pages.py
@@ -34,7 +34,7 @@
from weboob.capabilities.profile import Person, Company
from weboob.capabilities.contact import Advisor
from weboob.browser.elements import DictElement, ItemElement, method
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
CleanText, CleanDecimal, Currency as CleanCurrency, Format, Field, Map, Eval, Env, Regexp, Date,
)
from weboob.browser.filters.html import Attr
diff --git a/modules/cragr/api/transfer_pages.py b/modules/cragr/api/transfer_pages.py
index 4447d38b2849125d15db978840da57bf7ea2e083..aaf4e313b460bb60c7f2045bdf256982c4700b8e 100644
--- a/modules/cragr/api/transfer_pages.py
+++ b/modules/cragr/api/transfer_pages.py
@@ -77,6 +77,7 @@ def condition(self):
obj_category = 'Interne'
obj_enabled_at = date.today()
obj__is_recipient = Dict('recipientOfTransfert', default=False)
+ obj__owner_name = CleanText(Dict('accountHolderLongDesignation'))
@method
class iter_external_recipient(DictElement):
@@ -90,7 +91,7 @@ def condition(self):
klass = Recipient
obj_id = obj_iban = Dict('ibanCode')
- obj_label = Dict('recipientName')
+ obj_label = CleanText(Dict('recipientName'))
obj_category = 'Externe'
obj_enabled_at = date.today()
@@ -123,8 +124,12 @@ def handle_response(self, transfer):
t.account_iban = Dict('currentDebitIbanCode')(self.doc)
t.account_label = Dict('typeCompte')(self.doc)
+ t.recipient_label = CleanText(Dict('currentCreditAccountName'))(self.doc)
t.recipient_id = t.recipient_iban = Dict('currentCreditIbanCode')(self.doc)
- t.recipient_label = Dict('currentCreditAccountName')(self.doc)
+
+ # Internal transfer
+ if not Dict('isExternalTransfer')(self.doc):
+ t.recipient_id = Dict('currentCreditAccountNumber')(self.doc)
return t
diff --git a/modules/cragr/web/browser.py b/modules/cragr/web/browser.py
index 5fe416e43f9b3b36ba287e4641180ee43a7afb4b..b9c5019b5c28c5d6288f9897f4dff5f507bff214 100644
--- a/modules/cragr/web/browser.py
+++ b/modules/cragr/web/browser.py
@@ -30,13 +30,13 @@
)
from weboob.capabilities.base import find_object, empty
from weboob.capabilities.profile import ProfileMissing
-from weboob.browser import LoginBrowser, URL, need_login, StatesMixin
+from weboob.browser.browsers import LoginBrowser, URL, need_login, StatesMixin
from weboob.browser.switch import SiteSwitch
from weboob.browser.pages import FormNotFound
from weboob.exceptions import BrowserIncorrectPassword, BrowserUnavailable
from weboob.tools.date import ChaoticDateGuesser, LinearDateGuesser
from weboob.exceptions import BrowserHTTPError, ActionNeeded
-from weboob.browser.filters.standard import CleanText
+from .compat.weboob_browser_filters_standard import CleanText
from weboob.tools.value import Value
from weboob.tools.compat import urlparse, urljoin, basestring
from weboob.tools.capabilities.bank.iban import is_iban_valid
diff --git a/modules/cragr/web/compat/weboob_browser_filters_standard.py b/modules/cragr/web/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/cragr/web/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/cragr/web/pages.py b/modules/cragr/web/pages.py
index 8153266bd9ba39d087663b09280b0854b2bff39b..464047da38fb47aafacdfdd22c870a1edd1c5445 100644
--- a/modules/cragr/web/pages.py
+++ b/modules/cragr/web/pages.py
@@ -38,7 +38,7 @@
from weboob.tools.date import parse_french_date, LinearDateGuesser
from weboob.tools.compat import urlparse, urljoin, unicode
from weboob.browser.elements import ListElement, TableElement, ItemElement, method
-from weboob.browser.filters.standard import Date, CleanText, CleanDecimal, Currency as CleanCurrency, \
+from .compat.weboob_browser_filters_standard import Date, CleanText, CleanDecimal, Currency as CleanCurrency, \
Regexp, Format, Field
from weboob.browser.filters.html import Link, TableCell, ColumnNotFound, Attr
diff --git a/modules/creditdunord/browser.py b/modules/creditdunord/browser.py
index 73e2f520fb2301c03a6a71f602da96ebc17a44cb..21f676498693d69eee372927d5056aa0ffb219a2 100644
--- a/modules/creditdunord/browser.py
+++ b/modules/creditdunord/browser.py
@@ -36,6 +36,7 @@ class CreditDuNordBrowser(LoginBrowser):
login = URL('$',
'/.*\?.*_pageLabel=page_erreur_connexion',
+ '/.*\?.*_pageLabel=reinitialisation_mot_de_passe',
LoginPage)
redirect = URL('/swm/redirectCDN.html', RedirectPage)
entrypage = URL('/icd/zco/#zco', EntryPage)
@@ -69,21 +70,20 @@ def do_login(self):
if expired_error:
raise BrowserPasswordExpired(expired_error)
- if self.login.is_here():
+ # Force redirection to entry page if the redirect page does not contain an url
+ if self.redirect.is_here():
+ self.entrypage.go()
+
+ if self.entrypage.is_here() or self.login.is_here():
error = self.page.get_error()
if error:
+ if 'code confidentiel à la première connexion' in error:
+ raise BrowserPasswordExpired(error)
raise BrowserIncorrectPassword(error)
- else:
- # in case we are still on login without error message
- # we'll check what's happening.
- assert False, "Still on login page."
if not self.logged:
raise BrowserIncorrectPassword()
- if self.page.doc.xpath('//head[title="Authentification"]/script[contains(text(), "_pageLabel=reinitialisation_mot_de_passe")]'):
- raise BrowserPasswordExpired()
-
def _iter_accounts(self):
self.loans.go(account_type=self.account_type, loans_page_label=self.loans_page_label)
for a in self.page.get_list():
diff --git a/modules/creditdunord/compat/weboob_browser_filters_standard.py b/modules/creditdunord/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/creditdunord/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/creditdunord/pages.py b/modules/creditdunord/pages.py
index d677c133939feac2cc58539298276003530b14fa..70b99df03af1b76d97b97f33e4e5566354190b1d 100755
--- a/modules/creditdunord/pages.py
+++ b/modules/creditdunord/pages.py
@@ -29,7 +29,7 @@
from weboob.browser.pages import HTMLPage, LoggedPage, JsonPage
from weboob.browser.elements import method, ItemElement, TableElement
-from weboob.browser.filters.standard import CleanText, Date, CleanDecimal, Regexp, Format, Field, Eval, Lower
+from .compat.weboob_browser_filters_standard import CleanText, Date, CleanDecimal, Regexp, Format, Field, Eval, Lower
from weboob.browser.filters.json import Dict
from weboob.browser.filters.html import Attr, TableCell
from weboob.exceptions import ActionNeeded, BrowserIncorrectPassword, BrowserUnavailable, BrowserPasswordExpired
@@ -97,15 +97,26 @@ def get_string_code(self, string):
return ','.join(res)
+class HTMLErrorPage(HTMLPage):
+ def get_error(self):
+ # No Coalesce here as both can be empty
+ return CleanText('//b[has-class("x-attentionErreurLigneHaut")]')(self.doc) or \
+ CleanText('//div[has-class("x-attentionErreur")]/b')(self.doc)
+
+
+
class RedirectPage(HTMLPage):
- pass
+ def on_load(self):
+ link = Regexp(CleanText('//script'), 'href="(.*)"', default='')(self.doc)
+ if link:
+ self.browser.location(link)
-class EntryPage(LoggedPage, HTMLPage):
+class EntryPage(LoggedPage, HTMLErrorPage):
pass
-class LoginPage(HTMLPage):
+class LoginPage(HTMLErrorPage):
VIRTUALKEYBOARD = CDNVirtKeyboard
def login(self, username, password):
@@ -147,9 +158,6 @@ def classic_login(self, username, password):
}
self.browser.location('/saga/authentification', data=data)
- def get_error(self):
- return CleanText('//b[has-class("x-attentionErreurLigneHaut")]', default="")(self.doc)
-
class AccountTypePage(LoggedPage, JsonPage):
def get_account_type(self):
diff --git a/modules/creditdunordpee/compat/weboob_browser_filters_standard.py b/modules/creditdunordpee/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/creditdunordpee/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/creditdunordpee/compat/weboob_tools_captcha_virtkeyboard.py b/modules/creditdunordpee/compat/weboob_tools_captcha_virtkeyboard.py
deleted file mode 100644
index 3f29ddc260e32a22d2ef82d8d15e13bc7f9e6add..0000000000000000000000000000000000000000
--- a/modules/creditdunordpee/compat/weboob_tools_captcha_virtkeyboard.py
+++ /dev/null
@@ -1,196 +0,0 @@
-
-import weboob.tools.captcha.virtkeyboard as OLD
-
-# can't import *, __all__ is incomplete...
-for attr in dir(OLD):
- globals()[attr] = getattr(OLD, attr)
-
-
-try:
- __all__ = OLD.__all__
-except AttributeError:
- pass
-
-
-class SimpleVirtualKeyboard(object):
- """Handle a virtual keyboard where "keys" are distributed on a simple grid.
-
- Parameters:
- :param cols: Column count of the grid
- :type cols: int
- :param rows: Row count of the grid
- :type rows: int
- :param image: File-like object to be used as data source
- :type image: file
- :param convert: Mode to which convert color of pixels, see
- :meth:`Image.Image.convert` for more information
- :param matching_symbols: symbol that match all case of image grid from left to right and top
- to down, European reading way.
- :type matching_symbols: iterable
- :param matching_symbols_coords: dict mapping matching website symbols to their image coords
- (x0, y0, x1, y1) on grid image from left to right and top to
- down, European reading way. It's not symbols in the image.
- :type matching_symbols_coords: dict[str:4-tuple(int)]
- :param browser: Browser of weboob session.
- Allow to dump tiles files in same directory than session folder
- :type browser: obj(Browser)
-
- Attributes:
- :attribute codesep: Output separator between matching symbols
- :type codesep: str
- :param margin: Useless image pixel to cut.
- See :func:`cut_margin`.
- :type margin: 4-tuple(int), same as HTML margin: (top, right, bottom, left).
- or 2-tuple(int), (top = bottom, right = left),
- or int, top = right = bottom = left
- :attribute tile_margin: Useless tile pixel to cut.
- See :func:`cut_margin`.
- :attribute symbols: Association table between image symbols and md5s
- :type symbols: dict[str:str] or dict[str:n-tuple(str)]
- :attribute convert: Mode to which convert color of pixels, see
- :meth:`Image.Image.convert` for more information
- :attribute alter: Allow custom main image alteration. Then overwrite :func:`alter_image`.
- :type alter: boolean
- """
-
- codesep = ''
- margin = None
- tile_margin = None
- symbols = None
- convert = None
-
- def __init__(self, file, cols, rows, matching_symbols=None, matching_symbols_coords=None, browser=None):
- self.cols = cols
- self.rows = rows
-
- # Needed even if init is overwrite
- self.path = self.build_path(browser)
-
- # Get self.image
- self.load_image(file, self.margin, self.convert)
-
- # Get self.tiles
- self.get_tiles( matching_symbols=matching_symbols,
- matching_symbols_coords=matching_symbols_coords)
-
- # Tiles processing
- self.cut_tiles(self.tile_margin)
- self.hash_md5_tiles()
-
- def build_path(self, browser=None):
- if browser and browser.responses_dirname:
- return browser.responses_dirname
- else:
- return tempfile.mkdtemp(prefix='weboob_session_')
-
- def load_image(self, file, margin=None, convert=None):
- self.image = Image.open(file)
- # Resize image if margin is given
- if margin:
- self.image = self.cut_margin(self.image, margin)
- if convert:
- self.image = self.image.convert(convert)
- # Give possibility to alter image before get tiles, overwrite :func:`alter_image`.
- self.alter_image()
- self.width, self.height = self.image.size
-
- def alter_image(self):
- pass
-
- def cut_margin(self, image, margin):
- width, height = image.size
-
- # Verify the magin value format
- if type(margin) is int:
- margin = (margin, margin, margin, margin)
- elif len(margin) == 2:
- margin = (margin[0], margin[1], margin[0], margin[1])
- elif len(margin) == 4:
- margin = margin
- else:
- assert (len(margin) == 3) & (len(margin) > 4), \
- "Margin format is wrong."
-
- assert ((margin[0] + margin[2]) < height) & ((margin[1] + margin[3]) < width), \
- "Margin is too high, there is not enough pixel to cut."
-
- image = image.crop((0 + margin[3],
- 0 + margin[0],
- width - margin[1],
- height - margin[2]
- ))
- return image
-
- def get_tiles(self, matching_symbols=None, matching_symbols_coords=None):
- self.tiles = []
-
- # Tiles coords are given
- if matching_symbols_coords:
- for matching_symbol in matching_symbols_coords:
- self.tiles.append(Tile( matching_symbol=matching_symbol,
- coords=matching_symbols_coords[matching_symbol]
- ))
- return
-
- assert (not self.width%self.cols) & (not self.height%self.rows), \
- "Image width and height are not multiple of cols and rows. Please resize image with attribute `margin`."
-
- # Tiles coords aren't given, calculate them
- self.tileW = self.width // self.cols
- self.tileH = self.height // self.rows
-
- # Matching symbols aren't given, default value is range(columns*rows)
- if not matching_symbols:
- matching_symbols = ['%s' % i for i in range(self.cols*self.rows)]
-
- assert len(matching_symbols) == (self.cols*self.rows), \
- "Number of website matching symbols is not equal to the number of cases on the image."
-
- # Calculate tiles coords for each matching symbol from 1-dimension to 2-dimensions
- for index, matching_symbol in enumerate(matching_symbols):
- coords = self.get_tile_coords_in_grid(index)
- self.tiles.append(Tile(matching_symbol=matching_symbol, coords=coords))
-
- def get_tile_coords_in_grid(self, case_index):
- # Get the top left pixel coords of the tile
- x0 = (case_index % self.cols) * self.tileW
- y0 = (case_index // self.cols) * self.tileH
-
- # Get the bottom right coords of the tile
- x1 = x0 + self.tileW
- y1 = y0 + self.tileH
-
- coords = (x0, y0, x1, y1)
- return(coords)
-
- def cut_tiles(self, tile_margin=None):
- for tile in self.tiles:
- tile.image = self.image.crop(tile.coords)
-
- # Resize tile if margin is given
- if tile_margin:
- for tile in self.tiles:
- tile.image = self.cut_margin(tile.image, tile_margin)
-
- def hash_md5_tiles(self):
- for tile in self.tiles:
- tile.md5 = hashlib.md5(tile.image.tobytes()).hexdigest()
-
- def dump_tiles(self, path):
- for tile in self.tiles:
- tile.image.save('{}/{}.png'.format(path, tile.md5))
-
- def get_string_code(self, password):
- word = []
-
- for digit in password:
- for tile in self.tiles:
- if tile.md5 in self.symbols[digit]:
- word.append(tile.matching_symbol)
- break
- else:
- # Dump file only if the symbol is not found
- self.dump_tiles(self.path)
- raise VirtKeyboardError("Symbol '%s' not found; all symbol hashes are available in %s"
- % (digit, self.path))
- return self.codesep.join(word)
diff --git a/modules/creditdunordpee/pages.py b/modules/creditdunordpee/pages.py
index 0382f3f4d71ecbc323e84f7f9eb5e0860ab13cf7..e54ea1b56a680847c764e43b79a06e3adfe2e7e6 100644
--- a/modules/creditdunordpee/pages.py
+++ b/modules/creditdunordpee/pages.py
@@ -25,7 +25,7 @@
from weboob.browser.pages import HTMLPage, LoggedPage
from .compat.weboob_tools_captcha_virtkeyboard import MappedVirtKeyboard
from weboob.browser.elements import ItemElement, TableElement, method
-from weboob.browser.filters.standard import CleanText, CleanDecimal, Format, Regexp, Date, Env, Currency, Eval
+from .compat.weboob_browser_filters_standard import CleanText, CleanDecimal, Format, Regexp, Date, Env, Currency, Eval
from weboob.browser.filters.html import CleanHTML, TableCell
from weboob.capabilities.bank import Account, Transaction, Investment
from weboob.capabilities.base import NotAvailable
diff --git a/modules/creditmutuel/browser.py b/modules/creditmutuel/browser.py
index 80710eec78918cd936c823b3378f381d33d3aa1d..be2e24cf7c54269c2e5b390e020c9fa6dcbe724e 100644
--- a/modules/creditmutuel/browser.py
+++ b/modules/creditmutuel/browser.py
@@ -421,6 +421,7 @@ def get_history(self, account):
history = self.page.get_history(date=self.tr_date)
for tr in history:
+ # For regrouped transaction, we have to go through each one to get details
if tr._regroup:
self.location(tr._regroup)
for tr2 in self.page.get_tr_merged():
diff --git a/modules/creditmutuel/compat/__init__.py b/modules/creditmutuel/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/creditmutuel/compat/weboob_browser_filters_standard.py b/modules/creditmutuel/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/creditmutuel/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/creditmutuel/pages.py b/modules/creditmutuel/pages.py
index f311e236e44367d5425b03cb57e2ed1059d20a27..bd08936f29f5bdcabd48017841bf68bde1b4ca86 100644
--- a/modules/creditmutuel/pages.py
+++ b/modules/creditmutuel/pages.py
@@ -30,7 +30,7 @@
from weboob.browser.pages import HTMLPage, FormNotFound, LoggedPage, pagination, XMLPage
from weboob.browser.elements import ListElement, ItemElement, SkipItem, method, TableElement
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
Filter, Env, CleanText, CleanDecimal, Field, Regexp, Async, AsyncLoad, Date, Format, Type, Currency,
)
from weboob.browser.filters.html import Link, Attr, TableCell, ColumnNotFound
@@ -725,7 +725,7 @@ class item(Transaction.TransactionElement):
obj_original_amount = CleanDecimal(TableCell('original_amount'), default=NotAvailable, replace_dots=True)
obj_original_currency = FrenchTransaction.Currency(TableCell('original_amount'))
obj_type = Transaction.TYPE_DEFERRED_CARD
- obj_rdate = Transaction.Date(TableCell('date'))
+ obj_rdate = obj_bdate = Transaction.Date(TableCell('date'))
obj_date = obj_vdate = Env('date')
obj__is_coming = Env('_is_coming')
@@ -905,7 +905,7 @@ def condition(self):
return len(self.el.xpath('./td')) >= 4 and not CleanText(TableCell('commerce'))(self).startswith('RETRAIT CB')
obj_raw = Transaction.Raw(Format("%s %s", CleanText(TableCell('commerce')), CleanText(TableCell('ville'))))
- obj_rdate = Field('vdate')
+ obj_rdate = obj_bdate = Field('vdate')
obj_date = Env('date')
def obj_type(self):
@@ -933,6 +933,8 @@ def obj__is_coming(self):
return True
return False
+ # Some payment made on the same organization are regrouped,
+ # we have to get the detail for each one later
def obj__regroup(self):
if "Regroupement" in CleanText('./td')(self):
return Link('./td/span/a')(self)
@@ -959,6 +961,10 @@ def obj_type(self):
return Transaction.TYPE_DEFERRED_CARD
return Transaction.TYPE_CARD_SUMMARY
+ def obj_bdate(self):
+ if Field('type')(self) == Transaction.TYPE_DEFERRED_CARD:
+ return Transaction.Date(TableCell('date'))(self)
+
def has_more_operations(self):
xp = CleanText(self.doc.xpath('//div[@class="ei_blocpaginb"]/a'))(self)
if xp == 'Suite des opérations':
@@ -985,7 +991,7 @@ def condition(self):
return not CleanText(TableCell('commerce'))(self).startswith('RETRAIT CB')
obj_raw = Transaction.Raw(Format("%s %s", CleanText(TableCell('commerce')), CleanText(TableCell('ville'))))
- obj_rdate = Field('vdate')
+ obj_rdate = obj_bdate = Field('vdate')
obj_date = Env('date')
def obj_type(self):
@@ -1162,9 +1168,11 @@ def obj_code(self):
class PorPage(LoggedPage, HTMLPage):
- TYPES = {"PLAN D'EPARGNE EN ACTIONS": Account.TYPE_PEA,
- 'P.E.A': Account.TYPE_PEA
- }
+ TYPES = {
+ "PLAN D'EPARGNE EN ACTIONS": Account.TYPE_PEA,
+ 'P.E.A': Account.TYPE_PEA,
+ 'PEA': Account.TYPE_PEA,
+ }
def get_type(self, label):
for pattern, actype in self.TYPES.items():
@@ -1539,10 +1547,7 @@ def parse(self, el):
self.env['origin_account']._external_recipients.add(Field('id')(self))
def get_transfer_form(self):
- # internal and external transfer form are differents
- if self.IS_PRO_PAGE:
- return self.get_form(id='P2:F', submit='//input[@type="submit" and contains(@value, "Valider")]')
- return self.get_form(id='P1:F', submit='//input[@type="submit" and contains(@value, "Valider")]')
+ return self.get_form(xpath='//form[@id="P1:F"] | //form[@id="P2:F"]', submit='//input[@type="submit" and contains(@value, "Valider")]')
class VerifCodePage(LoggedPage, HTMLPage):
HASHES = {
diff --git a/modules/cuisineaz/compat/__init__.py b/modules/cuisineaz/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/cuisineaz/compat/weboob_browser_filters_standard.py b/modules/cuisineaz/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/cuisineaz/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/cuisineaz/pages.py b/modules/cuisineaz/pages.py
index 73099f175722133db2118831bb345c273aa5f9f1..fc06f6157ed02c0f181910ab5cf918935ecbd764 100644
--- a/modules/cuisineaz/pages.py
+++ b/modules/cuisineaz/pages.py
@@ -23,7 +23,7 @@
from weboob.capabilities.image import BaseImage, Thumbnail
from weboob.browser.pages import HTMLPage, pagination
from weboob.browser.elements import ItemElement, method, ListElement
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
CleanText, Regexp, Env, Time, Join, Format, Eval,
)
from weboob.browser.filters.html import XPath
diff --git a/modules/dailymotion/compat/__init__.py b/modules/dailymotion/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/dailymotion/compat/weboob_browser_filters_standard.py b/modules/dailymotion/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/dailymotion/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/dailymotion/pages.py b/modules/dailymotion/pages.py
index 01d72772c5544760e409ffe8c12bc8c0999ef24c..d131dfc4ea5c79944bbc7c5460b69aa3fc2a1cf7 100644
--- a/modules/dailymotion/pages.py
+++ b/modules/dailymotion/pages.py
@@ -19,7 +19,7 @@
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.browser.pages import HTMLPage, pagination
-from weboob.browser.filters.standard import CleanText, Regexp, Env, Duration, DateTime
+from .compat.weboob_browser_filters_standard import CleanText, Regexp, Env, Duration, DateTime
from weboob.browser.filters.html import Link
from weboob.capabilities.base import NotAvailable
diff --git a/modules/delubac/compat/weboob_browser_filters_standard.py b/modules/delubac/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/delubac/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/delubac/pages.py b/modules/delubac/pages.py
index df85bd16616c3abfd84a16d1685aed9fb38ff3e4..ea7702742eba9e20f217f400ab8829f4fe7f445d 100644
--- a/modules/delubac/pages.py
+++ b/modules/delubac/pages.py
@@ -23,7 +23,7 @@
from weboob.browser.pages import HTMLPage, LoggedPage
from weboob.exceptions import ParseError, ActionNeeded
from .compat.weboob_tools_captcha_virtkeyboard import GridVirtKeyboard
-from weboob.browser.filters.standard import CleanText
+from .compat.weboob_browser_filters_standard import CleanText
class DelubacVirtKeyboard(GridVirtKeyboard):
diff --git a/modules/dlfp/pages/compat/__init__.py b/modules/dlfp/pages/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/dlfp/pages/compat/weboob_browser_filters_standard.py b/modules/dlfp/pages/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/dlfp/pages/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/dlfp/pages/wiki.py b/modules/dlfp/pages/wiki.py
index 4709640589399cb3c685face1ca771cb2406df95..a4bd2a94310eed5c85c1805e73e3c0b580beeb2f 100644
--- a/modules/dlfp/pages/wiki.py
+++ b/modules/dlfp/pages/wiki.py
@@ -19,7 +19,7 @@
import lxml.html
-from weboob.browser.filters.standard import CleanText
+from .compat.weboob_browser_filters_standard import CleanText
from .index import DLFPPage
diff --git a/modules/dresdenwetter/compat/__init__.py b/modules/dresdenwetter/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/dresdenwetter/compat/weboob_browser_filters_standard.py b/modules/dresdenwetter/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/dresdenwetter/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/dresdenwetter/pages.py b/modules/dresdenwetter/pages.py
index af113d2aa3d94bb94603cca7fe6ccba9ca1a0fbe..017bfdc8c964eb48d8277aee63232c4861586afc 100644
--- a/modules/dresdenwetter/pages.py
+++ b/modules/dresdenwetter/pages.py
@@ -19,7 +19,7 @@
from weboob.browser.pages import HTMLPage
from weboob.browser.elements import ListElement, ItemElement, method
-from weboob.browser.filters.standard import CleanText, Regexp, Field, Filter, debug
+from .compat.weboob_browser_filters_standard import CleanText, Regexp, Field, Filter, debug
from weboob.capabilities.gauge import GaugeMeasure, GaugeSensor
from weboob.capabilities.base import NotAvailable
diff --git a/modules/edf/module.py b/modules/edf/module.py
index d13f26613a775cf39bfca997564455027f20c9f4..1cb24c4edcdbe9763a54aa458f67ceec6de5220c 100644
--- a/modules/edf/module.py
+++ b/modules/edf/module.py
@@ -42,7 +42,7 @@ class EdfModule(Module, CapDocument, CapProfile):
ValueBackendPassword('password', label='Mot de passe'),
Value('website', label='Type de compte', default='par',
choices={'par': 'Particulier', 'pro': 'Entreprise'}),
- Value('captcha_response', label='Reponse Captcha', required=False, default=''))
+ Value('otp', label='Entrez le code reçu par SMS', required=False))
accepted_document_types = (DocumentTypes.BILL,)
diff --git a/modules/edf/par/browser.py b/modules/edf/par/browser.py
index 557ecb1512202c80127b20fa0df74feadc157f3f..8d3cb0580a4be07458b5573aa228404c161f2de4 100644
--- a/modules/edf/par/browser.py
+++ b/modules/edf/par/browser.py
@@ -20,13 +20,13 @@
from time import time
-from weboob.browser import LoginBrowser, URL, need_login
-from weboob.browser.exceptions import ClientError
-from weboob.exceptions import BrowserIncorrectPassword, NocaptchaQuestion
+from weboob.browser import LoginBrowser, URL, need_login, StatesMixin
+from weboob.exceptions import BrowserIncorrectPassword, BrowserQuestion
from weboob.tools.decorators import retry
from weboob.tools.json import json
+from weboob.tools.value import Value
from .pages import (
- HomePage, AuthenticatePage, AuthorizePage, CheckAuthenticatePage, ProfilPage,
+ HomePage, AuthenticatePage, AuthorizePage, WrongPasswordPage, CheckAuthenticatePage, ProfilPage,
DocumentsPage, WelcomePage, UnLoggedPage, ProfilePage, BillDownload,
)
@@ -35,13 +35,15 @@ class BrokenPageError(Exception):
pass
-class EdfBrowser(LoginBrowser):
+class EdfBrowser(LoginBrowser, StatesMixin):
BASEURL = 'https://particulier.edf.fr'
home = URL('/fr/accueil/contrat-et-conso/mon-compte-edf.html', HomePage)
authenticate = URL(r'https://espace-client.edf.fr/sso/json/authenticate', AuthenticatePage)
authorize = URL(r'https://espace-client.edf.fr/sso/oauth2/INTERNET/authorize', AuthorizePage)
+ wrong_password = URL(r'https://espace-client.edf.fr/connexion/mon-espace-client/templates/openam/authn/PasswordAuth2.html', WrongPasswordPage)
check_authenticate = URL('/services/rest/openid/checkAuthenticate', CheckAuthenticatePage)
+ user_status = URL('/services/rest/checkuserstatus/getUserStatus')
not_connected = URL('/fr/accueil/connexion/mon-espace-client.html', UnLoggedPage)
connected = URL('/fr/accueil/espace-client/tableau-de-bord.html', WelcomePage)
profil = URL('/services/rest/authenticate/getListContracts', ProfilPage)
@@ -54,52 +56,96 @@ class EdfBrowser(LoginBrowser):
r'&di=(?P.*)&bn=(?P.*)&an=(?P.*)', BillDownload)
profile = URL('/services/rest/context/getCustomerContext', ProfilePage)
+ __states__ = ['id_token1']
+
def __init__(self, config, *args, **kwargs):
self.config = config
- self.authId = None
+ self.otp_data = None
+ self.otp_url = None
+ self.id_token1 = None
kwargs['username'] = self.config['login'].get()
kwargs['password'] = self.config['password'].get()
super(EdfBrowser, self).__init__(*args, **kwargs)
+ def locate_browser(self, state):
+ pass
+
def do_login(self):
+ # ********** admire how login works on edf par website **********
+ # login part on edf particulier website is very tricky
+ # FIRST time we connect we have an otp, BUT not password, we can't know if it is wrong at this moment
+ # SECOND time we use password, and not otp
auth_params = {'realm': '/INTERNET'}
- if self.config['captcha_response'].get() and self.authId:
+
+ if self.config['otp'].get():
+ self.otp_data['callbacks'][0]['input'][0]['value'] = self.config['otp'].get()
+ self.authenticate.go(json=self.otp_data, params=auth_params)
+ self.id_token1 = self.page.get_data()['callbacks'][1]['output'][0]['value']
+ # id_token1 is VERY important, we keep it indefinitely, without it edf will ask again otp
+ else:
+ self.location('/bin/edf_rc/servlets/sasServlet', params={'processus': 'TDB'})
+ if self.connected.is_here():
+ # we are already logged
+ # sometimes even if password is wrong, you can be logged if you retry
+ self.logger.info('already logged')
+ return
+
+ self.otp_url = self.url
self.authenticate.go(method='POST', params=auth_params)
data = self.page.get_data()
- data['authId'] = self.authId
data['callbacks'][0]['input'][0]['value'] = self.username
- data['callbacks'][1]['input'][0]['value'] = self.password
- data['callbacks'][2]['input'][0]['value'] = self.config['captcha_response'].get()
- data['callbacks'][3]['input'][0]['value'] = '0'
-
- try:
- self.authenticate.go(json=data, params=auth_params)
- except ClientError as error:
- resp = error.response
- if resp.status_code == 401:
- raise BrowserIncorrectPassword(resp.json()['message'])
- raise
-
- self.session.cookies['ivoiream'] = self.page.get_data()['tokenId']
-
- # go to this url will auto submit a form which will finalize login
- self.connected.go()
-
- """
- call check_authenticate url before get subscription in profil, or we'll get an error 'invalid session'
- we do nothing with this response (which contains false btw)
- but edf website expect we call it before or will reject us
- """
- self.check_authenticate.go()
- else:
- self.authenticate.go(method='POST', params=auth_params)
- if self.page.has_captcha_request():
- data = self.page.get_data()
- website_key = data['callbacks'][4]['output'][0]['value']
- website_url = "https://espace-client.edf.fr/sso/XUI/#login/&realm=%2FINTERNET"
- self.authId = data['authId']
- raise NocaptchaQuestion(website_key=website_key, website_url=website_url)
+ self.authenticate.go(json=data, params=auth_params)
+ data = self.page.get_data() # yes, we have to get response and send it again, beautiful isn't it ?
+ if data['stage'] == 'UsernameAuth2':
+ # username is wrong
+ raise BrowserIncorrectPassword(data['callbacks'][1]['output'][0]['value'])
+
+ if self.id_token1:
+ data['callbacks'][0]['input'][0]['value'] = self.id_token1
+ else:
+ # the FIRST time we connect, we don't have id_token1, we have no choice, we'll receive an otp
+ data['callbacks'][0]['input'][0]['value'] = ' '
+
+ self.authenticate.go(json=data, params=auth_params)
+ data = self.page.get_data()
+
+ assert data['stage'] in ('HOTPcust3', 'PasswordAuth2'), 'stage is %s' % data['stage']
+
+ if data['stage'] == 'HOTPcust3': # OTP part
+ if self.id_token1:
+ # this shouldn't happen except if id_token1 expire one day, who knows...
+ self.logger.warning('id_token1 is not null but edf ask again for otp')
+
+ # a legend say this url is the answer to life the universe and everything, because it is use EVERYWHERE in login
+ self.authenticate.go(json=self.page.get_data(), params=auth_params)
+ self.otp_data = self.page.get_data()
+ label = self.otp_data['callbacks'][0]['output'][0]['value']
+ raise BrowserQuestion(Value('otp', label=label))
+
+ if data['stage'] == 'PasswordAuth2': # password part
+ data['callbacks'][0]['input'][0]['value'] = self.password
+ self.authenticate.go(json=self.page.get_data(), params=auth_params)
+
+ # should be SetPasAuth2 if password is ok
+ if self.page.get_data()['stage'] == 'PasswordAuth2':
+ attempt_number = self.page.get_data()['callbacks'][1]['output'][0]['value']
+ # attempt_number is the number of wrong password
+ msg = self.wrong_password.go().get_wrongpass_message(attempt_number)
+ raise BrowserIncorrectPassword(msg)
+
+ data = self.page.get_data()
+ # yes, send previous data again, i know i know
+ self.authenticate.go(json=data, params=auth_params)
+ self.session.cookies['ivoiream'] = self.page.get_token()
+ self.user_status.go()
+
+ """
+ call check_authenticate url before get subscription in profil, or we'll get an error 'invalid session'
+ we do nothing with this response (which contains false btw)
+ but edf website expect we call it before or will reject us
+ """
+ self.check_authenticate.go()
def get_csrf_token(self):
return self.csrf_token.go(timestamp=int(time())).get_token()
diff --git a/modules/edf/par/compat/__init__.py b/modules/edf/par/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/edf/par/compat/weboob_browser_filters_standard.py b/modules/edf/par/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/edf/par/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/edf/par/pages.py b/modules/edf/par/pages.py
index 7cbe5fd7bc03c4b41be80e7617371f2d7560f028..768fef16813fb676d0fe5ea6ae2272e355eb783e 100644
--- a/modules/edf/par/pages.py
+++ b/modules/edf/par/pages.py
@@ -24,7 +24,7 @@
from weboob.browser.filters.html import Attr
from weboob.browser.pages import LoggedPage, JsonPage, HTMLPage, RawPage
-from weboob.browser.filters.standard import Env, Format, Date, Eval
+from .compat.weboob_browser_filters_standard import Env, Format, Date, Eval, CleanText, Regexp
from weboob.browser.elements import ItemElement, DictElement, method
from weboob.browser.filters.json import Dict
from weboob.capabilities.bill import DocumentTypes, Bill, Subscription
@@ -43,6 +43,9 @@ def has_captcha_request(self):
def get_data(self):
return self.doc
+ def get_token(self):
+ return self.doc['tokenId']
+
class AuthorizePage(HTMLPage):
def on_load(self):
@@ -50,6 +53,20 @@ def on_load(self):
self.get_form().submit()
+class WrongPasswordPage(HTMLPage):
+ def get_wrongpass_message(self, attempt_number):
+ # edf website block access after 5 wrong password, and user will have to change his password
+ # this is very important because it can tell to user how much attempt it remains
+ script = CleanText('//script[contains(text(), "Mot de passe incorrect")]')
+
+ if attempt_number > 0:
+ return Format('%s %s %s',
+ Regexp(script, r">(Mot de passe incorrect.*?)<"),
+ CleanText('//div[@class="arrow_box--content"]', children=False), int(attempt_number))(self.doc)
+ return Regexp(script, r">(Vous avez atteint.*?)<")(self.doc)
+
+
+
class WelcomePage(LoggedPage, HTMLPage):
pass
@@ -62,7 +79,11 @@ class UnLoggedPage(HTMLPage):
pass
-class ProfilPage(LoggedPage, JsonPage):
+class ProfilPage(JsonPage):
+ @property
+ def logged(self):
+ return self.doc['errorCode'] == 0
+
@method
class iter_subscriptions(DictElement):
item_xpath = 'customerAccordContracts'
diff --git a/modules/edf/pro/compat/__init__.py b/modules/edf/pro/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/edf/pro/compat/weboob_browser_filters_standard.py b/modules/edf/pro/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/edf/pro/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/edf/pro/pages.py b/modules/edf/pro/pages.py
index 1476b20206474ff3250ab41e621db105458c5156..b85c23ea4f3c802fefeaa9c46e515f3f0d252cc6 100644
--- a/modules/edf/pro/pages.py
+++ b/modules/edf/pro/pages.py
@@ -23,7 +23,7 @@
from weboob.browser.pages import JsonPage, HTMLPage, RawPage, LoggedPage
from weboob.browser.elements import DictElement, ItemElement, method
-from weboob.browser.filters.standard import CleanDecimal, CleanText
+from .compat.weboob_browser_filters_standard import CleanDecimal, CleanText
from weboob.browser.filters.json import Dict
from weboob.capabilities.bill import DocumentTypes, Subscription, Bill
from weboob.exceptions import ActionNeeded
diff --git a/modules/ekwateur/compat/__init__.py b/modules/ekwateur/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/ekwateur/compat/weboob_browser_filters_standard.py b/modules/ekwateur/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/ekwateur/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/ekwateur/pages.py b/modules/ekwateur/pages.py
index 0bfcee0f957bd720621337ac89f6bf92c65f1553..2832fdcb4c60d2b191930c14b662e4b4432f451c 100644
--- a/modules/ekwateur/pages.py
+++ b/modules/ekwateur/pages.py
@@ -24,7 +24,7 @@
ItemElement, ListElement, TableElement, method
)
from weboob.browser.pages import HTMLPage
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
Date, CleanDecimal, CleanText, Currency, Env, Format, Regexp, Slugify,
TableCell
)
diff --git a/modules/ensap/compat/__init__.py b/modules/ensap/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/ensap/compat/weboob_browser_filters_standard.py b/modules/ensap/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/ensap/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/ensap/pages.py b/modules/ensap/pages.py
index 9518296caba8a91d215777bed27073c93308bbbd..fcc08e451f8c1fd6b41c7b69f47bb10b76df9bcf 100644
--- a/modules/ensap/pages.py
+++ b/modules/ensap/pages.py
@@ -24,7 +24,7 @@
from weboob.browser.elements import ItemElement, DictElement, method
from weboob.browser.filters.json import Dict
from weboob.capabilities.bill import Subscription, Document
-from weboob.browser.filters.standard import Date, CleanText, Format, Regexp
+from .compat.weboob_browser_filters_standard import Date, CleanText, Format, Regexp
class LoginPage(HTMLPage):
diff --git a/modules/entreparticuliers/compat/__init__.py b/modules/entreparticuliers/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/entreparticuliers/compat/weboob_browser_filters_standard.py b/modules/entreparticuliers/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/entreparticuliers/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/entreparticuliers/pages.py b/modules/entreparticuliers/pages.py
index a0748bfca993c11cbf5199e12f43780a166b584a..52b668c814017be721a0cba0b0d0881d8587b7fb 100644
--- a/modules/entreparticuliers/pages.py
+++ b/modules/entreparticuliers/pages.py
@@ -22,7 +22,7 @@
from weboob.browser.pages import JsonPage, XMLPage
from weboob.browser.elements import ItemElement, DictElement, method
from weboob.browser.filters.json import Dict
-from weboob.browser.filters.standard import CleanText, CleanDecimal, Env, Format, Filter, DateTime
+from .compat.weboob_browser_filters_standard import CleanText, CleanDecimal, Env, Format, Filter, DateTime
from weboob.capabilities.housing import (Housing, HousingPhoto, City, UTILITIES, ENERGY_CLASS, ADVERT_TYPES)
from weboob.tools.capabilities.housing.housing import PricePerMeterFilter
from weboob.capabilities.base import NotAvailable, Currency, empty
diff --git a/modules/explorimmo/compat/__init__.py b/modules/explorimmo/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/explorimmo/compat/weboob_browser_filters_standard.py b/modules/explorimmo/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/explorimmo/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/explorimmo/pages.py b/modules/explorimmo/pages.py
index 35631b889b9ec19d4cffa8e160436072eb644be1..dcbd37d5716e34025792cb363a676d1e339f7471 100644
--- a/modules/explorimmo/pages.py
+++ b/modules/explorimmo/pages.py
@@ -26,7 +26,7 @@
from weboob.browser.filters.json import Dict
from weboob.browser.elements import ItemElement, ListElement, DictElement, method
from weboob.browser.pages import JsonPage, HTMLPage, pagination
-from weboob.browser.filters.standard import (CleanText, CleanDecimal, Currency,
+from .compat.weboob_browser_filters_standard import (CleanText, CleanDecimal, Currency,
Regexp, Env, BrowserURL, Filter,
Format)
from weboob.browser.filters.html import Attr, CleanHTML, XPath
diff --git a/modules/feedly/compat/__init__.py b/modules/feedly/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/feedly/compat/weboob_browser_filters_standard.py b/modules/feedly/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/feedly/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/feedly/pages.py b/modules/feedly/pages.py
index 41a4abfc08b25e137814e6fc04f4bf70dd67acd0..fb79d8724f5e99e0372a61c3f66d2db355ec7edc 100644
--- a/modules/feedly/pages.py
+++ b/modules/feedly/pages.py
@@ -23,7 +23,7 @@
from weboob.capabilities.collection import Collection
from weboob.browser.pages import JsonPage, LoggedPage
from weboob.browser.elements import ItemElement, DictElement, method
-from weboob.browser.filters.standard import CleanText, Format
+from .compat.weboob_browser_filters_standard import CleanText, Format
from weboob.browser.filters.json import Dict
from weboob.browser.filters.html import CleanHTML
diff --git a/modules/foncia/browser.py b/modules/foncia/browser.py
index ea1e27643811d442b2a0a6ae188a419477c5f365..ce1255812a12d0c130b3530543cd312545c1e9d6 100644
--- a/modules/foncia/browser.py
+++ b/modules/foncia/browser.py
@@ -30,7 +30,7 @@ class FonciaBrowser(PagesBrowser):
BASEURL = 'https://fr.foncia.com'
cities = URL(r'/recherche/autocomplete\?term=(?P.+)', CitiesPage)
- housing = URL(r'/(?P[^/]+)/.*/\d+.htm', HousingPage)
+ housing = URL(r'/(?P[^/]+)/.*\d+.htm', HousingPage)
search_results = URL(r'/(?P[^/]+)/.*', SearchResultsPage)
search = URL(r'/(?P.+)', SearchPage)
diff --git a/modules/foncia/compat/__init__.py b/modules/foncia/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/foncia/compat/weboob_browser_filters_standard.py b/modules/foncia/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/foncia/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/foncia/constants.py b/modules/foncia/constants.py
index 5b74c23b273701f96bb9fd519b03ebd5a7f52ef3..404f2af848759961b91efca0119a9a34c9d3a51c 100644
--- a/modules/foncia/constants.py
+++ b/modules/foncia/constants.py
@@ -11,7 +11,7 @@
HOUSE_TYPES.HOUSE: ['maison'],
HOUSE_TYPES.PARKING: ['parking'],
HOUSE_TYPES.LAND: ['terrain'],
- HOUSE_TYPES.OTHER: ['chambre',
+ HOUSE_TYPES.OTHER: ['chambre', 'programme-neuf',
'local-commercial', 'immeuble']
}
@@ -19,6 +19,6 @@
POSTS_TYPES.RENT: ['appartement', 'maison', 'parking', 'chambre',
'local-commercial'],
POSTS_TYPES.SALE: ['appartement', 'maison', 'parking', 'local-commercial',
- 'terrain', 'immeuble'],
+ 'terrain', 'immeuble', 'programme-neuf'],
POSTS_TYPES.FURNISHED_RENT: ['appartement-meuble']
}
diff --git a/modules/foncia/pages.py b/modules/foncia/pages.py
index 98ab18fe96a7a5b8542eec5afc7d9db2d4b03d89..1e997bf0ce6cf60ebd45e5e1cf5d90cb5a178fb4 100644
--- a/modules/foncia/pages.py
+++ b/modules/foncia/pages.py
@@ -22,7 +22,7 @@
import datetime
from weboob.browser.pages import JsonPage, HTMLPage, pagination
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
CleanDecimal, CleanText, Currency, Date, Env, Format, Regexp, RegexpError
)
from weboob.browser.filters.html import AbsoluteLink, Attr, Link, XPathNotFound
@@ -91,15 +91,18 @@ def obj_house_type(self):
CleanText(
'//div[has-class("MiniData")]//p[has-class("MiniData-item")][1]'
),
- r'(\d*\.*\d*) .*'
- )
+ r'(\d*\.*\d*) .*',
+ default=NotAvailable
+ ),
+ default=NotAvailable
)
obj_cost = CleanDecimal(
- '//p[has-class("OfferTop-price")]'
+ '//span[has-class("OfferTop-price")]',
+ default=NotAvailable
)
obj_price_per_meter = PricePerMeterFilter()
obj_currency = Currency(
- '//p[has-class("OfferTop-price")]'
+ '//span[has-class("OfferTop-price")]'
)
obj_location = Format(
'%s - %s',
@@ -302,8 +305,10 @@ def obj_house_type(self):
CleanText(
'.//div[has-class("MiniData")]//p[@data-behat="surfaceDesBiens"]'
),
- r'(\d*\.*\d*) .*'
- )
+ r'(\d*\.*\d*) .*',
+ default=NotAvailable
+ ),
+ default=NotAvailable
)
obj_cost = CleanDecimal(
'.//strong[has-class("TeaserOffer-price-num")]'
diff --git a/modules/fortuneo/pages/accounts_list.py b/modules/fortuneo/pages/accounts_list.py
index 9ae95a975a37dcf9ced68058948422681ca9e299..86f2d729066b6d7668b162ad6cfbe317cd71773f 100644
--- a/modules/fortuneo/pages/accounts_list.py
+++ b/modules/fortuneo/pages/accounts_list.py
@@ -29,7 +29,7 @@
from weboob.browser.elements import method, ItemElement
from weboob.browser.filters.html import Link, Attr
-from weboob.browser.filters.standard import CleanText, CleanDecimal, RawText, Regexp, Date
+from .compat.weboob_browser_filters_standard import CleanText, CleanDecimal, RawText, Regexp, Date
from weboob.capabilities import NotAvailable
from weboob.capabilities.bank import Account, Investment, Loan
from weboob.capabilities.profile import Person
diff --git a/modules/fortuneo/pages/compat/__init__.py b/modules/fortuneo/pages/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/fortuneo/pages/compat/weboob_browser_filters_standard.py b/modules/fortuneo/pages/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/fortuneo/pages/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/fortuneo/pages/login.py b/modules/fortuneo/pages/login.py
index 3b177a59bea48cf0693ddfdf20e70cef8aca0b09..e034cf49cb57fe1fd4672fa60615c34b7e771b32 100644
--- a/modules/fortuneo/pages/login.py
+++ b/modules/fortuneo/pages/login.py
@@ -19,7 +19,7 @@
from weboob.browser.pages import HTMLPage
-from weboob.browser.filters.standard import CleanText
+from .compat.weboob_browser_filters_standard import CleanText
from weboob.exceptions import BrowserUnavailable
diff --git a/modules/fortuneo/pages/transfer.py b/modules/fortuneo/pages/transfer.py
index 85170e1673393708cbd64497d59c1ee6debacce2..60a12e0a57b6e93a1c12354e97b4424bfc128571 100644
--- a/modules/fortuneo/pages/transfer.py
+++ b/modules/fortuneo/pages/transfer.py
@@ -24,7 +24,7 @@
from weboob.browser.pages import HTMLPage, PartialHTMLPage, LoggedPage
from weboob.browser.elements import method, ListElement, ItemElement, SkipItem
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
CleanText, Date, Regexp, CleanDecimal, Currency, Field, Env,
)
from weboob.capabilities.bank import Recipient, Transfer, TransferBankError, AddRecipientBankError
diff --git a/modules/francetelevisions/compat/__init__.py b/modules/francetelevisions/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/francetelevisions/compat/weboob_browser_filters_standard.py b/modules/francetelevisions/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/francetelevisions/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/francetelevisions/pages.py b/modules/francetelevisions/pages.py
index 8ac50651c99a8f73261865762584602a6ad23a36..c29ce845d47d24aed2a58d485e1d6614c9e552da 100644
--- a/modules/francetelevisions/pages.py
+++ b/modules/francetelevisions/pages.py
@@ -27,7 +27,7 @@
from weboob.browser.pages import HTMLPage, JsonPage
from weboob.browser.elements import ItemElement, ListElement, method, DictElement
-from weboob.browser.filters.standard import CleanText, Regexp, Format, Field, Env
+from .compat.weboob_browser_filters_standard import CleanText, Regexp, Format, Field, Env
from weboob.browser.filters.html import CleanHTML
from weboob.browser.filters.json import Dict
diff --git a/modules/freemobile/pages/compat/__init__.py b/modules/freemobile/pages/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/freemobile/pages/compat/weboob_browser_filters_standard.py b/modules/freemobile/pages/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/freemobile/pages/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/freemobile/pages/history.py b/modules/freemobile/pages/history.py
index ab890caa2fad8f15ae51501785de5e3b7664da8a..6878af25ad93e27b7fa990b32b7b414a5cfc6c28 100644
--- a/modules/freemobile/pages/history.py
+++ b/modules/freemobile/pages/history.py
@@ -24,7 +24,7 @@
from weboob.browser.pages import HTMLPage, LoggedPage
from weboob.browser.elements import ItemElement, ListElement, method
-from weboob.browser.filters.standard import Date, CleanText, Filter,\
+from .compat.weboob_browser_filters_standard import Date, CleanText, Filter,\
CleanDecimal, Currency, Regexp, Field, DateTime, Format, Env
from weboob.browser.filters.html import AbsoluteLink, Attr
from weboob.capabilities.bill import DocumentTypes, Detail, Bill
diff --git a/modules/freemobile/pages/homepage.py b/modules/freemobile/pages/homepage.py
index 5117d82c8de1826e452708c65b639b0ecca9522f..adabe17d3f20ca30ed54714a3bff888a67dc68f8 100644
--- a/modules/freemobile/pages/homepage.py
+++ b/modules/freemobile/pages/homepage.py
@@ -20,7 +20,7 @@
from .history import BadUTF8Page
from weboob.capabilities.bill import Subscription
from weboob.browser.elements import ListElement, ItemElement, method
-from weboob.browser.filters.standard import CleanText, Field, Format
+from .compat.weboob_browser_filters_standard import CleanText, Field, Format
class HomePage(BadUTF8Page):
diff --git a/modules/freemobile/pages/profile.py b/modules/freemobile/pages/profile.py
index 999a4a4debb5042bfe023970e41179705dbe3a60..613b06198e0688b4bf0382075f8a591d0f2c3451 100644
--- a/modules/freemobile/pages/profile.py
+++ b/modules/freemobile/pages/profile.py
@@ -21,7 +21,7 @@
from weboob.browser.pages import HTMLPage, LoggedPage
from weboob.capabilities.profile import Profile
-from weboob.browser.filters.standard import CleanText, Regexp
+from .compat.weboob_browser_filters_standard import CleanText, Regexp
class ProfilePage(LoggedPage, HTMLPage):
diff --git a/modules/freeteknomusic/compat/__init__.py b/modules/freeteknomusic/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/freeteknomusic/compat/weboob_browser_filters_standard.py b/modules/freeteknomusic/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/freeteknomusic/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/freeteknomusic/pages.py b/modules/freeteknomusic/pages.py
index 7416392aa754a269e6da67c5ecef3115a5dbdcb8..619317eda7ab5530cf9257ee4f6d4c62d37a84ce 100644
--- a/modules/freeteknomusic/pages.py
+++ b/modules/freeteknomusic/pages.py
@@ -21,7 +21,7 @@
from weboob.browser.pages import HTMLPage
from weboob.browser.elements import ListElement, ItemElement, method
-from weboob.browser.filters.standard import CleanText, Regexp, Field, Decode
+from .compat.weboob_browser_filters_standard import CleanText, Regexp, Field, Decode
from weboob.browser.filters.html import AbsoluteLink
from weboob.capabilities.collection import Collection
from weboob.capabilities.audio import BaseAudio
diff --git a/modules/funmooc/compat/__init__.py b/modules/funmooc/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/funmooc/compat/weboob_browser_filters_standard.py b/modules/funmooc/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/funmooc/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/funmooc/pages.py b/modules/funmooc/pages.py
index 840347e21becc1c2d942f460062a95f114ca486e..3972906e1c0e79fbde9b228994b74a78f3cc7761 100644
--- a/modules/funmooc/pages.py
+++ b/modules/funmooc/pages.py
@@ -26,7 +26,7 @@
from weboob.browser.pages import HTMLPage, LoggedPage
from weboob.browser.elements import method, ListElement, ItemElement, SkipItem
from weboob.capabilities.collection import Collection
-from weboob.browser.filters.standard import CleanText
+from .compat.weboob_browser_filters_standard import CleanText
class PageLogin(HTMLPage):
diff --git a/modules/genericnewspaper/compat/weboob_browser_filters_standard.py b/modules/genericnewspaper/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/genericnewspaper/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/genericnewspaper/pages.py b/modules/genericnewspaper/pages.py
index 6bd10c1876ae29199b4b351ea06d05a62bb1b48e..acdfa8567cc3778b04bea00aa0f55625d2f1b2df 100644
--- a/modules/genericnewspaper/pages.py
+++ b/modules/genericnewspaper/pages.py
@@ -19,7 +19,7 @@
from weboob.browser.pages import HTMLPage
from weboob.browser.filters.html import XPath, XPathNotFound
-from weboob.browser.filters.standard import CleanText
+from .compat.weboob_browser_filters_standard import CleanText
from lxml.etree import Comment
diff --git a/modules/gmf/compat/__init__.py b/modules/gmf/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/gmf/compat/weboob_browser_filters_standard.py b/modules/gmf/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/gmf/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/gmf/pages.py b/modules/gmf/pages.py
index f7d509f1cb7b686d05c33367a38aaec53a6e9304..387d1caeb4056e4563e121ecab2498131fb98195 100644
--- a/modules/gmf/pages.py
+++ b/modules/gmf/pages.py
@@ -24,7 +24,7 @@
from weboob.browser.pages import FormNotFound, HTMLPage, LoggedPage, XMLPage
from weboob.browser.elements import ItemElement, method, ListElement, TableElement
from weboob.capabilities.bank import Account, Investment
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
CleanText, CleanDecimal, Currency, Date, Eval, Field, Regexp,
)
from weboob.browser.filters.html import Attr, TableCell
diff --git a/modules/groupama/compat/__init__.py b/modules/groupama/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/groupama/compat/weboob_browser_filters_standard.py b/modules/groupama/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/groupama/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/groupama/pages.py b/modules/groupama/pages.py
index ecbaeac01094eb410649ce3153c5fc15581e4a20..eb58cf5bb28baf1840cecfb1a1f8dc00e78ceb5f 100644
--- a/modules/groupama/pages.py
+++ b/modules/groupama/pages.py
@@ -27,7 +27,7 @@
from weboob.browser.pages import HTMLPage, pagination, LoggedPage, FormNotFound, JsonPage
from weboob.browser.elements import method, TableElement, ItemElement
-from weboob.browser.filters.standard import Env, CleanDecimal, CleanText, Date, Regexp, Eval, Field
+from .compat.weboob_browser_filters_standard import Env, CleanDecimal, CleanText, Date, Regexp, Eval, Field
from weboob.browser.filters.html import Attr, Link, TableCell
from weboob.browser.filters.javascript import JSVar
from weboob.capabilities.bank import Account, Investment
diff --git a/modules/happn/browser.py b/modules/happn/browser.py
index 88af5e5a58c3ac84c247d4b65b4e162999f0b872..56cca8196386909507ef21100df1410f21caa542 100644
--- a/modules/happn/browser.py
+++ b/modules/happn/browser.py
@@ -23,7 +23,7 @@
from weboob.browser.browsers import DomainBrowser
from weboob.browser.profiles import IPhone
from weboob.browser.pages import HTMLPage
-from weboob.browser.filters.standard import CleanText
+from .compat.weboob_browser_filters_standard import CleanText
from weboob.exceptions import BrowserIncorrectPassword, ParseError
from weboob.tools.json import json
diff --git a/modules/happn/compat/weboob_browser_filters_standard.py b/modules/happn/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/happn/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/hds/compat/__init__.py b/modules/hds/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/hds/compat/weboob_browser_filters_standard.py b/modules/hds/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/hds/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/hds/pages.py b/modules/hds/pages.py
index 225c5b134dbe7b9294ac635f18176d983f9d71e9..43d94b0483effbf68fc73bd85f65de83b2d0326a 100644
--- a/modules/hds/pages.py
+++ b/modules/hds/pages.py
@@ -20,7 +20,7 @@
from weboob.browser.pages import HTMLPage
from weboob.browser.elements import method, ListElement, ItemElement
-from weboob.browser.filters.standard import CleanText, Regexp, Date, Env, Filter
+from .compat.weboob_browser_filters_standard import CleanText, Regexp, Date, Env, Filter
from weboob.browser.filters.html import XPath, Link
diff --git a/modules/hsbc/browser.py b/modules/hsbc/browser.py
index 9e1c2c24431e7769d0cdba6e812e517b92cf1138..66be84e87bdc0c61c8581e8aa6278714f92e08f7 100644
--- a/modules/hsbc/browser.py
+++ b/modules/hsbc/browser.py
@@ -20,7 +20,6 @@
from __future__ import unicode_literals
import re
-import ssl
from datetime import timedelta, date
from lxml.etree import XMLSyntaxError
from collections import OrderedDict
@@ -132,14 +131,6 @@ def __init__(self, username, password, secret, *args, **kwargs):
def load_state(self, state):
return
- def prepare_request(self, req):
- preq = super(HSBC, self).prepare_request(req)
-
- conn = self.session.adapters['https://'].get_connection(preq.url)
- conn.ssl_version = ssl.PROTOCOL_TLSv1
-
- return preq
-
def do_login(self):
self.session.cookies.clear()
diff --git a/modules/hsbc/pages/account_pages.py b/modules/hsbc/pages/account_pages.py
index f923b66f69761e37735cdad0ea1d3df961a370c3..4cef4ab322e7975099a143715b26cba9a3045a68 100644
--- a/modules/hsbc/pages/account_pages.py
+++ b/modules/hsbc/pages/account_pages.py
@@ -28,7 +28,7 @@
from weboob.exceptions import BrowserIncorrectPassword, BrowserUnavailable, ActionNeeded
from weboob.browser.elements import ListElement, ItemElement, method, TableElement
from weboob.browser.pages import HTMLPage, pagination, LoggedPage
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
Filter, Env, CleanText, CleanDecimal, Field, DateGuesser, Regexp, Currency, Format, Date
)
from weboob.browser.filters.html import AbsoluteLink, TableCell
diff --git a/modules/hsbc/pages/compat/__init__.py b/modules/hsbc/pages/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/hsbc/pages/compat/weboob_browser_filters_standard.py b/modules/hsbc/pages/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/hsbc/pages/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/hsbc/pages/investments.py b/modules/hsbc/pages/investments.py
index 63147b3d73a0bf83b4e7233a41f065f477d519ac..66a7276dcbd93197a1b914aa4b65054ca937ccbc 100644
--- a/modules/hsbc/pages/investments.py
+++ b/modules/hsbc/pages/investments.py
@@ -13,7 +13,7 @@
from weboob.browser.elements import ItemElement, TableElement, DictElement, method
from weboob.browser.pages import HTMLPage, JsonPage, LoggedPage
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
CleanText, CleanDecimal, Regexp, Currency, Field, Env,
)
from weboob.browser.filters.html import TableCell, Link
diff --git a/modules/hsbc/pages/landing_pages.py b/modules/hsbc/pages/landing_pages.py
index 0b1c2856cfcb80a77854054ad9a4c613d881f65d..907660c470adf507087d3d90fb4fbcdb9345a192 100644
--- a/modules/hsbc/pages/landing_pages.py
+++ b/modules/hsbc/pages/landing_pages.py
@@ -1,7 +1,7 @@
from __future__ import unicode_literals
from weboob.browser.pages import HTMLPage, LoggedPage
-from weboob.browser.filters.standard import CleanText, Regexp
+from .compat.weboob_browser_filters_standard import CleanText, Regexp
from weboob.browser.filters.html import Link
diff --git a/modules/hsbc/pages/life_insurances.py b/modules/hsbc/pages/life_insurances.py
index 49ab713c8966fa06a7485bc4be59685de9633a46..97c8e266405f49103dd93eada5fe14c8d42e6b4f 100644
--- a/modules/hsbc/pages/life_insurances.py
+++ b/modules/hsbc/pages/life_insurances.py
@@ -10,7 +10,7 @@
from weboob.browser.elements import TableElement, ItemElement, method
from weboob.browser.pages import HTMLPage, LoggedPage, FormNotFound
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
CleanText, CleanDecimal, Field, Regexp, Eval, Date
)
from weboob.browser.filters.html import Link, XPathNotFound, TableCell
diff --git a/modules/hybride/compat/__init__.py b/modules/hybride/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/hybride/compat/weboob_browser_filters_standard.py b/modules/hybride/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/hybride/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/hybride/pages.py b/modules/hybride/pages.py
index 997ac6b834a05acbc511383ffde8b77fff4c8bc6..c9b51420f3a798fac502a7b449a7571c5c015874 100644
--- a/modules/hybride/pages.py
+++ b/modules/hybride/pages.py
@@ -23,7 +23,7 @@
from weboob.browser.pages import HTMLPage
from weboob.browser.elements import ItemElement, ListElement, method
-from weboob.browser.filters.standard import Filter, CleanText, Env, Format, BrowserURL, Regexp, Decode
+from .compat.weboob_browser_filters_standard import Filter, CleanText, Env, Format, BrowserURL, Regexp, Decode
from weboob.browser.filters.html import CleanHTML
from weboob.browser.filters.html import Link
diff --git a/modules/ilmatieteenlaitos/compat/__init__.py b/modules/ilmatieteenlaitos/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/ilmatieteenlaitos/compat/weboob_browser_filters_standard.py b/modules/ilmatieteenlaitos/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/ilmatieteenlaitos/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/ilmatieteenlaitos/pages.py b/modules/ilmatieteenlaitos/pages.py
index ad8390357c70890ec0ea1378dfbafe1bcab35d47..67acf1d18f5500c56c004592d47fbb8de0e7e791 100644
--- a/modules/ilmatieteenlaitos/pages.py
+++ b/modules/ilmatieteenlaitos/pages.py
@@ -24,7 +24,7 @@
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.capabilities.weather import Forecast, Current, City, Temperature
from weboob.browser.filters.json import Dict
-from weboob.browser.filters.standard import Filter, CleanText
+from .compat.weboob_browser_filters_standard import Filter, CleanText
class Id(Filter):
diff --git a/modules/ina/compat/__init__.py b/modules/ina/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/ina/compat/weboob_browser_filters_standard.py b/modules/ina/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/ina/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/ina/pages.py b/modules/ina/pages.py
index a79907f5dbdbb50fbcbbf453532340c7855eb756..0e174105dce02c34523d3ab9b68081f72de2c865 100644
--- a/modules/ina/pages.py
+++ b/modules/ina/pages.py
@@ -24,7 +24,7 @@
from weboob.browser.pages import JsonPage, HTMLPage, XMLPage, pagination
from weboob.browser.elements import ItemElement, ListElement, method
-from weboob.browser.filters.standard import CleanText, Regexp, Duration, Date, BrowserURL, Env
+from .compat.weboob_browser_filters_standard import CleanText, Regexp, Duration, Date, BrowserURL, Env
from weboob.capabilities.audio import BaseAudio
from weboob.capabilities.video import BaseVideo
diff --git a/modules/indeed/compat/__init__.py b/modules/indeed/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/indeed/compat/weboob_browser_filters_standard.py b/modules/indeed/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/indeed/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/indeed/pages.py b/modules/indeed/pages.py
index 00efd00786b44f4b61b359cdebf47c841d57b639..68eba2a64d6e8a4eb668d315f31032ebfe19873f 100644
--- a/modules/indeed/pages.py
+++ b/modules/indeed/pages.py
@@ -21,7 +21,7 @@
import re
from weboob.browser.pages import HTMLPage, pagination
from weboob.browser.elements import ListElement, ItemElement, method
-from weboob.browser.filters.standard import Filter, CleanText, Regexp, Format, Env
+from .compat.weboob_browser_filters_standard import Filter, CleanText, Regexp, Format, Env
from weboob.browser.filters.html import CleanHTML, Attr
from weboob.capabilities.job import BaseJobAdvert
diff --git a/modules/infomaniak/compat/__init__.py b/modules/infomaniak/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/infomaniak/compat/weboob_browser_filters_standard.py b/modules/infomaniak/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/infomaniak/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/infomaniak/pages.py b/modules/infomaniak/pages.py
index 91dac5ac654a18055b925e731526e98e12ce6cae..9e4ebd144fdd89271bfe2174f2833f480346c1b3 100644
--- a/modules/infomaniak/pages.py
+++ b/modules/infomaniak/pages.py
@@ -23,7 +23,7 @@
from weboob.browser.pages import LoggedPage, JsonPage
from weboob.browser.elements import ItemElement, method, DictElement
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
CleanDecimal, Env, Regexp, Format, Currency, Field, Eval,
)
from weboob.browser.filters.json import Dict
diff --git a/modules/ing/api/accounts_page.py b/modules/ing/api/accounts_page.py
index 20f4367cec10fede14677756afd8fa88143f96c1..bf04caad730ff9c957d35749604ee32b5fd3062a 100644
--- a/modules/ing/api/accounts_page.py
+++ b/modules/ing/api/accounts_page.py
@@ -24,7 +24,7 @@
from weboob.browser.pages import LoggedPage, JsonPage
from weboob.browser.elements import method, DictElement, ItemElement
from weboob.browser.filters.json import Dict
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
CleanText, CleanDecimal, Date, Eval, Lower, Format, Field, Map, Upper,
)
from weboob.capabilities.bank import Account
diff --git a/modules/ing/api/compat/weboob_browser_filters_standard.py b/modules/ing/api/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/ing/api/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/ing/api/profile_page.py b/modules/ing/api/profile_page.py
index 4472f386bfcd925a77af8b2b74ad6eee59ac9a9c..21a8661c4235715a8bd27b292ef8c2e7d81c2dd5 100644
--- a/modules/ing/api/profile_page.py
+++ b/modules/ing/api/profile_page.py
@@ -21,7 +21,7 @@
from weboob.browser.pages import LoggedPage, JsonPage
from weboob.browser.filters.json import Dict
-from weboob.browser.filters.standard import CleanText, Format
+from .compat.weboob_browser_filters_standard import CleanText, Format
from weboob.browser.elements import ItemElement, method
from weboob.capabilities.profile import Profile
from weboob.capabilities.base import NotAvailable
diff --git a/modules/ing/api/transfer_page.py b/modules/ing/api/transfer_page.py
index c9349bca105419f74cda2a6ae8abbd0150987223..c3dfb0def0bd3c08c2398b28262d19e00494f902 100644
--- a/modules/ing/api/transfer_page.py
+++ b/modules/ing/api/transfer_page.py
@@ -25,7 +25,7 @@
from weboob.browser.pages import LoggedPage, JsonPage
from weboob.browser.elements import method, DictElement, ItemElement
from weboob.browser.filters.json import Dict
-from weboob.browser.filters.standard import Env, Field, Date
+from .compat.weboob_browser_filters_standard import Env, Field, Date
from weboob.capabilities.bank import Recipient
from .login import INGVirtKeyboard
diff --git a/modules/ing/pages/accounts_list.py b/modules/ing/pages/accounts_list.py
index 3e5fbd5a022f20e929114973a989a1e0b5fb7e31..416969c81e2a56abcd89c45b9d719663f7e1d6d0 100644
--- a/modules/ing/pages/accounts_list.py
+++ b/modules/ing/pages/accounts_list.py
@@ -28,7 +28,7 @@
from weboob.capabilities.profile import Person
from weboob.browser.pages import HTMLPage, LoggedPage, JsonPage
from weboob.browser.elements import ListElement, TableElement, ItemElement, method, DataError
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
CleanText, CleanDecimal, Eval, Filter, Field, MultiFilter, Date,
Lower, Async, AsyncLoad, Format, Env,
Regexp,
diff --git a/modules/ing/pages/bills.py b/modules/ing/pages/bills.py
index 41fd423380dd5e626c503edec3ea83c5ccc2bea6..0f24474da94e697ea58e640e019d1567deb714bf 100644
--- a/modules/ing/pages/bills.py
+++ b/modules/ing/pages/bills.py
@@ -21,7 +21,7 @@
from weboob.capabilities.bill import DocumentTypes, Bill, Subscription
from weboob.browser.pages import HTMLPage, LoggedPage, pagination, Form
-from weboob.browser.filters.standard import Filter, CleanText, Format, Field, Env, Date
+from .compat.weboob_browser_filters_standard import Filter, CleanText, Format, Field, Env, Date
from weboob.browser.filters.html import Attr
from weboob.browser.elements import ListElement, ItemElement, method
from weboob.tools.date import parse_french_date
diff --git a/modules/ing/pages/compat/weboob_browser_filters_standard.py b/modules/ing/pages/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/ing/pages/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/ing/pages/compat/weboob_tools_captcha_virtkeyboard.py b/modules/ing/pages/compat/weboob_tools_captcha_virtkeyboard.py
deleted file mode 100644
index 3f29ddc260e32a22d2ef82d8d15e13bc7f9e6add..0000000000000000000000000000000000000000
--- a/modules/ing/pages/compat/weboob_tools_captcha_virtkeyboard.py
+++ /dev/null
@@ -1,196 +0,0 @@
-
-import weboob.tools.captcha.virtkeyboard as OLD
-
-# can't import *, __all__ is incomplete...
-for attr in dir(OLD):
- globals()[attr] = getattr(OLD, attr)
-
-
-try:
- __all__ = OLD.__all__
-except AttributeError:
- pass
-
-
-class SimpleVirtualKeyboard(object):
- """Handle a virtual keyboard where "keys" are distributed on a simple grid.
-
- Parameters:
- :param cols: Column count of the grid
- :type cols: int
- :param rows: Row count of the grid
- :type rows: int
- :param image: File-like object to be used as data source
- :type image: file
- :param convert: Mode to which convert color of pixels, see
- :meth:`Image.Image.convert` for more information
- :param matching_symbols: symbol that match all case of image grid from left to right and top
- to down, European reading way.
- :type matching_symbols: iterable
- :param matching_symbols_coords: dict mapping matching website symbols to their image coords
- (x0, y0, x1, y1) on grid image from left to right and top to
- down, European reading way. It's not symbols in the image.
- :type matching_symbols_coords: dict[str:4-tuple(int)]
- :param browser: Browser of weboob session.
- Allow to dump tiles files in same directory than session folder
- :type browser: obj(Browser)
-
- Attributes:
- :attribute codesep: Output separator between matching symbols
- :type codesep: str
- :param margin: Useless image pixel to cut.
- See :func:`cut_margin`.
- :type margin: 4-tuple(int), same as HTML margin: (top, right, bottom, left).
- or 2-tuple(int), (top = bottom, right = left),
- or int, top = right = bottom = left
- :attribute tile_margin: Useless tile pixel to cut.
- See :func:`cut_margin`.
- :attribute symbols: Association table between image symbols and md5s
- :type symbols: dict[str:str] or dict[str:n-tuple(str)]
- :attribute convert: Mode to which convert color of pixels, see
- :meth:`Image.Image.convert` for more information
- :attribute alter: Allow custom main image alteration. Then overwrite :func:`alter_image`.
- :type alter: boolean
- """
-
- codesep = ''
- margin = None
- tile_margin = None
- symbols = None
- convert = None
-
- def __init__(self, file, cols, rows, matching_symbols=None, matching_symbols_coords=None, browser=None):
- self.cols = cols
- self.rows = rows
-
- # Needed even if init is overwrite
- self.path = self.build_path(browser)
-
- # Get self.image
- self.load_image(file, self.margin, self.convert)
-
- # Get self.tiles
- self.get_tiles( matching_symbols=matching_symbols,
- matching_symbols_coords=matching_symbols_coords)
-
- # Tiles processing
- self.cut_tiles(self.tile_margin)
- self.hash_md5_tiles()
-
- def build_path(self, browser=None):
- if browser and browser.responses_dirname:
- return browser.responses_dirname
- else:
- return tempfile.mkdtemp(prefix='weboob_session_')
-
- def load_image(self, file, margin=None, convert=None):
- self.image = Image.open(file)
- # Resize image if margin is given
- if margin:
- self.image = self.cut_margin(self.image, margin)
- if convert:
- self.image = self.image.convert(convert)
- # Give possibility to alter image before get tiles, overwrite :func:`alter_image`.
- self.alter_image()
- self.width, self.height = self.image.size
-
- def alter_image(self):
- pass
-
- def cut_margin(self, image, margin):
- width, height = image.size
-
- # Verify the magin value format
- if type(margin) is int:
- margin = (margin, margin, margin, margin)
- elif len(margin) == 2:
- margin = (margin[0], margin[1], margin[0], margin[1])
- elif len(margin) == 4:
- margin = margin
- else:
- assert (len(margin) == 3) & (len(margin) > 4), \
- "Margin format is wrong."
-
- assert ((margin[0] + margin[2]) < height) & ((margin[1] + margin[3]) < width), \
- "Margin is too high, there is not enough pixel to cut."
-
- image = image.crop((0 + margin[3],
- 0 + margin[0],
- width - margin[1],
- height - margin[2]
- ))
- return image
-
- def get_tiles(self, matching_symbols=None, matching_symbols_coords=None):
- self.tiles = []
-
- # Tiles coords are given
- if matching_symbols_coords:
- for matching_symbol in matching_symbols_coords:
- self.tiles.append(Tile( matching_symbol=matching_symbol,
- coords=matching_symbols_coords[matching_symbol]
- ))
- return
-
- assert (not self.width%self.cols) & (not self.height%self.rows), \
- "Image width and height are not multiple of cols and rows. Please resize image with attribute `margin`."
-
- # Tiles coords aren't given, calculate them
- self.tileW = self.width // self.cols
- self.tileH = self.height // self.rows
-
- # Matching symbols aren't given, default value is range(columns*rows)
- if not matching_symbols:
- matching_symbols = ['%s' % i for i in range(self.cols*self.rows)]
-
- assert len(matching_symbols) == (self.cols*self.rows), \
- "Number of website matching symbols is not equal to the number of cases on the image."
-
- # Calculate tiles coords for each matching symbol from 1-dimension to 2-dimensions
- for index, matching_symbol in enumerate(matching_symbols):
- coords = self.get_tile_coords_in_grid(index)
- self.tiles.append(Tile(matching_symbol=matching_symbol, coords=coords))
-
- def get_tile_coords_in_grid(self, case_index):
- # Get the top left pixel coords of the tile
- x0 = (case_index % self.cols) * self.tileW
- y0 = (case_index // self.cols) * self.tileH
-
- # Get the bottom right coords of the tile
- x1 = x0 + self.tileW
- y1 = y0 + self.tileH
-
- coords = (x0, y0, x1, y1)
- return(coords)
-
- def cut_tiles(self, tile_margin=None):
- for tile in self.tiles:
- tile.image = self.image.crop(tile.coords)
-
- # Resize tile if margin is given
- if tile_margin:
- for tile in self.tiles:
- tile.image = self.cut_margin(tile.image, tile_margin)
-
- def hash_md5_tiles(self):
- for tile in self.tiles:
- tile.md5 = hashlib.md5(tile.image.tobytes()).hexdigest()
-
- def dump_tiles(self, path):
- for tile in self.tiles:
- tile.image.save('{}/{}.png'.format(path, tile.md5))
-
- def get_string_code(self, password):
- word = []
-
- for digit in password:
- for tile in self.tiles:
- if tile.md5 in self.symbols[digit]:
- word.append(tile.matching_symbol)
- break
- else:
- # Dump file only if the symbol is not found
- self.dump_tiles(self.path)
- raise VirtKeyboardError("Symbol '%s' not found; all symbol hashes are available in %s"
- % (digit, self.path))
- return self.codesep.join(word)
diff --git a/modules/ing/pages/login.py b/modules/ing/pages/login.py
index d0879f5b45db2c60e73504aebef6097cd32854d5..1be8b6388086a3e5b6c9444aa8dabef068627456 100644
--- a/modules/ing/pages/login.py
+++ b/modules/ing/pages/login.py
@@ -23,7 +23,7 @@
from .compat.weboob_tools_captcha_virtkeyboard import VirtKeyboard
from weboob.browser.pages import HTMLPage, LoggedPage
from weboob.browser.filters.html import Attr
-from weboob.browser.filters.standard import CleanText
+from .compat.weboob_browser_filters_standard import CleanText
class INGVirtKeyboard(VirtKeyboard):
diff --git a/modules/ing/pages/titre.py b/modules/ing/pages/titre.py
index bb02e8b047f93ccc371ec4f9b73fe27fa57cea5c..9278d9e62d50ff2a3613e39fdd6e9d46bbcfa6ef 100644
--- a/modules/ing/pages/titre.py
+++ b/modules/ing/pages/titre.py
@@ -26,7 +26,7 @@
from weboob.capabilities.bank import Investment
from weboob.browser.pages import RawPage, HTMLPage, LoggedPage, pagination
from weboob.browser.elements import ListElement, TableElement, ItemElement, method
-from weboob.browser.filters.standard import CleanDecimal, CleanText, Date, Regexp, Env
+from .compat.weboob_browser_filters_standard import CleanDecimal, CleanText, Date, Regexp, Env
from weboob.browser.filters.html import Link, Attr, TableCell
from weboob.tools.capabilities.bank.transactions import FrenchTransaction
from weboob.tools.capabilities.bank.investments import create_french_liquidity
diff --git a/modules/ing/pages/transfer.py b/modules/ing/pages/transfer.py
index 452c6a92afe2405b608edabb5ec420c564c3bc5f..8864b44148cafa37af85762788f3d8279d0b31df 100644
--- a/modules/ing/pages/transfer.py
+++ b/modules/ing/pages/transfer.py
@@ -23,7 +23,7 @@
from weboob.capabilities import NotAvailable
from weboob.browser.pages import HTMLPage, LoggedPage
from weboob.browser.elements import ListElement, ItemElement, method
-from weboob.browser.filters.standard import CleanText, CleanDecimal, Env
+from .compat.weboob_browser_filters_standard import CleanText, CleanDecimal, Env
from weboob.browser.filters.html import Attr
from weboob.tools.capabilities.bank.transactions import FrenchTransaction
from weboob.tools.capabilities.bank.iban import is_iban_valid
diff --git a/modules/ing/web/accounts_list.py b/modules/ing/web/accounts_list.py
index 01ed8c84b4660b8497ddb5578976fe1eba651cdc..1bfd94eef440293fbe2cecda982820b8c00dcf6d 100644
--- a/modules/ing/web/accounts_list.py
+++ b/modules/ing/web/accounts_list.py
@@ -28,7 +28,7 @@
from weboob.capabilities.profile import Person
from weboob.browser.pages import HTMLPage, LoggedPage, JsonPage
from weboob.browser.elements import ListElement, TableElement, ItemElement, method, DataError
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
CleanText, CleanDecimal, Eval, Filter, Field, MultiFilter, Date,
Lower, Async, AsyncLoad, Format, Env,
Regexp,
diff --git a/modules/ing/web/bills.py b/modules/ing/web/bills.py
index 0a2dcbea693699a501a0ffce258c97b3ffe8ebfd..9896e285fbe9897f8cec0e1177d1eff968659da0 100644
--- a/modules/ing/web/bills.py
+++ b/modules/ing/web/bills.py
@@ -21,7 +21,7 @@
from weboob.capabilities.bill import DocumentTypes, Bill, Subscription
from weboob.browser.pages import HTMLPage, LoggedPage, pagination, Form
-from weboob.browser.filters.standard import Filter, CleanText, Format, Field, Env, Date
+from .compat.weboob_browser_filters_standard import Filter, CleanText, Format, Field, Env, Date
from weboob.browser.filters.html import Attr
from weboob.browser.elements import ListElement, ItemElement, method
from weboob.tools.date import parse_french_date
diff --git a/modules/ing/web/compat/__init__.py b/modules/ing/web/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/ing/web/compat/weboob_browser_filters_standard.py b/modules/ing/web/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/ing/web/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/ing/web/login.py b/modules/ing/web/login.py
index 4d0234009d71dc338a74cf2c5eff2c8eb09e6d2d..e55dc1b07bac37774256a034a2a4bd06ca458c28 100644
--- a/modules/ing/web/login.py
+++ b/modules/ing/web/login.py
@@ -20,7 +20,7 @@
from weboob.exceptions import ActionNeeded
from weboob.browser.pages import HTMLPage, LoggedPage
-from weboob.browser.filters.standard import CleanText
+from .compat.weboob_browser_filters_standard import CleanText
class ActionNeededPage(HTMLPage):
diff --git a/modules/ing/web/titre.py b/modules/ing/web/titre.py
index a1fb39e4b1033d2fd49abce31294891d7d4fbd84..ffd7a20c9d2255e40d5c1818326a89dbebe186a4 100644
--- a/modules/ing/web/titre.py
+++ b/modules/ing/web/titre.py
@@ -26,7 +26,7 @@
from weboob.capabilities.bank import Investment
from weboob.browser.pages import RawPage, HTMLPage, LoggedPage, pagination
from weboob.browser.elements import ListElement, TableElement, ItemElement, method
-from weboob.browser.filters.standard import CleanDecimal, CleanText, Date, Regexp, Env
+from .compat.weboob_browser_filters_standard import CleanDecimal, CleanText, Date, Regexp, Env
from weboob.browser.filters.html import Link, Attr, TableCell
from weboob.tools.capabilities.bank.transactions import FrenchTransaction
from weboob.tools.capabilities.bank.investments import create_french_liquidity
diff --git a/modules/ipinfodb/compat/__init__.py b/modules/ipinfodb/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/ipinfodb/compat/weboob_browser_filters_standard.py b/modules/ipinfodb/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/ipinfodb/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/ipinfodb/pages.py b/modules/ipinfodb/pages.py
index 0a81526f2a1aae990841e109fb6c1dc63dcc18bb..9808c53d81bc11f37c5ec5c6f3cee9ffe9b8c983 100644
--- a/modules/ipinfodb/pages.py
+++ b/modules/ipinfodb/pages.py
@@ -21,7 +21,7 @@
from weboob.browser.pages import HTMLPage
from weboob.browser.elements import ItemElement, method
from weboob.capabilities.geolocip import IpLocation
-from weboob.browser.filters.standard import Regexp, CleanText, Type
+from .compat.weboob_browser_filters_standard import Regexp, CleanText, Type
from weboob.capabilities.base import NotAvailable
diff --git a/modules/journaldesfemmes/compat/__init__.py b/modules/journaldesfemmes/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/journaldesfemmes/compat/weboob_browser_filters_standard.py b/modules/journaldesfemmes/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/journaldesfemmes/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/journaldesfemmes/pages.py b/modules/journaldesfemmes/pages.py
index c0b3a36f84895f5616edb4320dcf99fc4038d5f0..b7e79488073b9d90844e3817a6c47ae0139624a9 100644
--- a/modules/journaldesfemmes/pages.py
+++ b/modules/journaldesfemmes/pages.py
@@ -21,7 +21,7 @@
from weboob.browser.elements import ItemElement, ListElement, method
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
CleanText, CleanDecimal, Env, Regexp, Eval,
)
from weboob.browser.filters.html import Attr, Link, XPath
diff --git a/modules/kickass/compat/__init__.py b/modules/kickass/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/kickass/compat/weboob_browser_filters_standard.py b/modules/kickass/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/kickass/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/kickass/pages.py b/modules/kickass/pages.py
index 5a17debdf7f8647c9beff9cb5a822e93893ee5e4..0290f3d2df373c96a20f7d78f7099509649fbe3c 100644
--- a/modules/kickass/pages.py
+++ b/modules/kickass/pages.py
@@ -24,7 +24,7 @@
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.browser.pages import HTMLPage
-from weboob.browser.filters.standard import Regexp, CleanText, Type
+from .compat.weboob_browser_filters_standard import Regexp, CleanText, Type
class SearchPage(HTMLPage):
diff --git a/modules/lacentrale/compat/__init__.py b/modules/lacentrale/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/lacentrale/compat/weboob_browser_filters_standard.py b/modules/lacentrale/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/lacentrale/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/lacentrale/pages.py b/modules/lacentrale/pages.py
index 05a89372529a51319f595cff4eea006949578ce8..483e4fd438c3f8a35e5ac6102416b2435159401f 100644
--- a/modules/lacentrale/pages.py
+++ b/modules/lacentrale/pages.py
@@ -20,7 +20,7 @@
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.browser.pages import HTMLPage, pagination
-from weboob.browser.filters.standard import CleanText, Regexp, CleanDecimal, Format, Env, BrowserURL
+from .compat.weboob_browser_filters_standard import CleanText, Regexp, CleanDecimal, Format, Env, BrowserURL
from weboob.browser.filters.javascript import JSVar
from weboob.browser.filters.html import Link
from weboob.capabilities.pricecomparison import Price, Shop
diff --git a/modules/lameteoagricole/compat/__init__.py b/modules/lameteoagricole/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/lameteoagricole/compat/weboob_browser_filters_standard.py b/modules/lameteoagricole/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/lameteoagricole/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/lameteoagricole/pages.py b/modules/lameteoagricole/pages.py
index 6281b1e20d74166e3a09c1408cb4874bbb40fc34..aa2992205358a87d1b8ed370dbeb54b2c250ce7a 100644
--- a/modules/lameteoagricole/pages.py
+++ b/modules/lameteoagricole/pages.py
@@ -22,7 +22,7 @@
from datetime import date, time, datetime, timedelta
from weboob.browser.elements import method, ListElement, ItemElement
-from weboob.browser.filters.standard import CleanText, Field
+from .compat.weboob_browser_filters_standard import CleanText, Field
from weboob.browser.pages import HTMLPage
from weboob.capabilities.weather import City, Forecast, Temperature, Current, Direction
from weboob.tools.compat import quote
diff --git a/modules/lampiris/compat/__init__.py b/modules/lampiris/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/lampiris/compat/weboob_browser_filters_standard.py b/modules/lampiris/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/lampiris/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/lampiris/pages.py b/modules/lampiris/pages.py
index 5e46c80132e453c9ec326091741704b7e73634e4..d69af4c47dfe801142379ab90631c151bfc42a69 100644
--- a/modules/lampiris/pages.py
+++ b/modules/lampiris/pages.py
@@ -22,7 +22,7 @@
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.browser.filters.html import Attr, CleanHTML, Link, XPathNotFound
-from weboob.browser.filters.standard import CleanDecimal, CleanText, Date, Format
+from .compat.weboob_browser_filters_standard import CleanDecimal, CleanText, Date, Format
from weboob.browser.pages import HTMLPage
from weboob.capabilities.base import NotAvailable, Currency
from weboob.capabilities.bill import Bill, Subscription
diff --git a/modules/larousse/compat/__init__.py b/modules/larousse/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/larousse/compat/weboob_browser_filters_standard.py b/modules/larousse/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/larousse/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/larousse/pages.py b/modules/larousse/pages.py
index 4698364d84af0c83816f5b4d705437725084d3c0..fbf47ba683b99d478c13c71c17fe467f89672b80 100644
--- a/modules/larousse/pages.py
+++ b/modules/larousse/pages.py
@@ -23,7 +23,7 @@
from weboob.capabilities.translate import Translation
from weboob.browser.elements import method, ListElement, ItemElement
-from weboob.browser.filters.standard import Env, CleanText
+from .compat.weboob_browser_filters_standard import Env, CleanText
from weboob.browser.pages import HTMLPage
CODES = {
diff --git a/modules/lcl/browser.py b/modules/lcl/browser.py
index 7813ca0dafab38e1ebf15b3c8f684fbe27c6e92a..bd6175510424d396f53468afadd0e5211a533a10 100644
--- a/modules/lcl/browser.py
+++ b/modules/lcl/browser.py
@@ -49,7 +49,7 @@ class LCLBrowser(LoginBrowser, StatesMixin):
BASEURL = 'https://particuliers.secure.lcl.fr'
STATE_DURATION = 15
- login = URL('/outil/UAUT/Authentication/authenticate',
+ login = URL('/outil/UAUT\?from=/outil/UWHO/Accueil/',
'/outil/UAUT\?from=.*',
'/outil/UWER/Accueil/majicER',
'/outil/UWER/Enregistrement/forwardAcc',
@@ -153,7 +153,8 @@ def do_login(self):
# we force the browser to go to login page so it's work even
# if the session expire
- self.login.go()
+ # Must set the referer to avoid redirection to the home page
+ self.login.go(headers={"Referer": "https://www.lcl.fr/"})
if not self.page.login(self.username, self.password) or \
(self.login.is_here() and self.page.is_error()):
diff --git a/modules/lcl/compat/weboob_browser_filters_standard.py b/modules/lcl/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/lcl/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/lcl/enterprise/compat/__init__.py b/modules/lcl/enterprise/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/lcl/enterprise/compat/weboob_browser_filters_standard.py b/modules/lcl/enterprise/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/lcl/enterprise/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/lcl/enterprise/pages.py b/modules/lcl/enterprise/pages.py
index 147ada6e5cce7559d5f505e09a9c7a9890d7a39e..a1579de84e3433588799bd70e1f58d599a578327 100644
--- a/modules/lcl/enterprise/pages.py
+++ b/modules/lcl/enterprise/pages.py
@@ -22,7 +22,7 @@
from weboob.browser.pages import HTMLPage, LoggedPage, pagination
from weboob.browser.elements import ListElement, ItemElement, TableElement, method
-from weboob.browser.filters.standard import CleanText, Date, CleanDecimal, Env
+from .compat.weboob_browser_filters_standard import CleanText, Date, CleanDecimal, Env
from weboob.browser.filters.html import Link, TableCell
from weboob.capabilities.bank import Account
from weboob.capabilities.profile import Profile
diff --git a/modules/lcl/pages.py b/modules/lcl/pages.py
index 1e3526d951138dcdd296163181d18d877fe83bae..28379ea1a9e28e7a97abb5ef5a237258efb27663 100644
--- a/modules/lcl/pages.py
+++ b/modules/lcl/pages.py
@@ -40,7 +40,7 @@
from weboob.browser.exceptions import ServerError
from weboob.browser.pages import LoggedPage, HTMLPage, JsonPage, FormNotFound, pagination
from weboob.browser.filters.html import Attr, Link, TableCell, AttributeNotFound
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
CleanText, Field, Regexp, Format, Date, CleanDecimal, Map, AsyncLoad, Async, Env, Slugify, BrowserURL, Eval,
)
from weboob.browser.filters.json import Dict
diff --git a/modules/ldlc/compat/__init__.py b/modules/ldlc/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/ldlc/compat/weboob_browser_filters_standard.py b/modules/ldlc/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/ldlc/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/ldlc/pages.py b/modules/ldlc/pages.py
index 9e0003bf8c60e1e5c739131deea63db7a435130e..977a0ab3436d2dcc26157e87c24bf216ac5ddfc6 100644
--- a/modules/ldlc/pages.py
+++ b/modules/ldlc/pages.py
@@ -20,7 +20,7 @@
from __future__ import unicode_literals
from weboob.browser.pages import HTMLPage, LoggedPage
-from weboob.browser.filters.standard import CleanDecimal, CleanText, Env, Format, QueryValue, TableCell, Currency
+from .compat.weboob_browser_filters_standard import CleanDecimal, CleanText, Env, Format, QueryValue, TableCell, Currency
from weboob.browser.elements import ListElement, ItemElement, method, TableElement
from weboob.browser.filters.html import Attr
from weboob.capabilities.bill import Bill, Subscription
diff --git a/modules/leboncoin/compat/__init__.py b/modules/leboncoin/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/leboncoin/compat/weboob_browser_filters_standard.py b/modules/leboncoin/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/leboncoin/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/leboncoin/pages.py b/modules/leboncoin/pages.py
index 9005f464ee39510c49b2a55822a5b7c3d710cbcc..7f09fde875d21cf6a9a636200df6d8ffea216cf6 100644
--- a/modules/leboncoin/pages.py
+++ b/modules/leboncoin/pages.py
@@ -23,7 +23,7 @@
from weboob.browser.pages import HTMLPage, JsonPage, pagination
from weboob.browser.elements import ItemElement, ListElement, method, DictElement
from weboob.capabilities.base import Currency as BaseCurrency
-from weboob.browser.filters.standard import (CleanText, CleanDecimal, _Filter,
+from .compat.weboob_browser_filters_standard import (CleanText, CleanDecimal, _Filter,
Env, DateTime, Format)
from weboob.browser.filters.json import Dict
from weboob.capabilities.housing import (City, Housing, HousingPhoto,
diff --git a/modules/lefigaro/compat/__init__.py b/modules/lefigaro/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/lefigaro/compat/weboob_browser_filters_standard.py b/modules/lefigaro/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/lefigaro/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/lefigaro/pages.py b/modules/lefigaro/pages.py
index 483abd12a846668b9abf00f0aed09666d070b00c..8867e73ec9f3d2ef98fef4e35699dd4b5f22a284 100644
--- a/modules/lefigaro/pages.py
+++ b/modules/lefigaro/pages.py
@@ -19,7 +19,7 @@
# along with this weboob module. If not, see .
from weboob.browser.pages import AbstractPage
from weboob.browser.filters.html import CSS
-from weboob.browser.filters.standard import CleanText
+from .compat.weboob_browser_filters_standard import CleanText
class ArticlePage(AbstractPage):
diff --git a/modules/liberation/compat/__init__.py b/modules/liberation/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/liberation/compat/weboob_browser_filters_standard.py b/modules/liberation/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/liberation/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/liberation/pages.py b/modules/liberation/pages.py
index 79df9bfdad1ba12587a4d1dca496cf2ffe234c7d..09012ee172bc74a6cd2b66f5ea3226a7c3328aa9 100644
--- a/modules/liberation/pages.py
+++ b/modules/liberation/pages.py
@@ -19,7 +19,7 @@
from weboob.browser.pages import AbstractPage
from weboob.browser.filters.html import XPathNotFound, CSS
-from weboob.browser.filters.standard import CleanText
+from .compat.weboob_browser_filters_standard import CleanText
class ArticlePage(AbstractPage):
diff --git a/modules/limetorrents/compat/__init__.py b/modules/limetorrents/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/limetorrents/compat/weboob_browser_filters_standard.py b/modules/limetorrents/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/limetorrents/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/limetorrents/pages.py b/modules/limetorrents/pages.py
index dc48030a587707dd54d1a28cc71670f491c10f8e..b85487ab1261bd1c69724f28ffdb64ff07d7d842 100644
--- a/modules/limetorrents/pages.py
+++ b/modules/limetorrents/pages.py
@@ -23,7 +23,7 @@
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.browser.pages import HTMLPage, pagination
-from weboob.browser.filters.standard import Regexp, CleanText, CleanDecimal, Format
+from .compat.weboob_browser_filters_standard import Regexp, CleanText, CleanDecimal, Format
from weboob.browser.filters.html import AbsoluteLink
diff --git a/modules/linebourse/api/compat/__init__.py b/modules/linebourse/api/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/linebourse/api/compat/weboob_browser_filters_standard.py b/modules/linebourse/api/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/linebourse/api/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/linebourse/api/pages.py b/modules/linebourse/api/pages.py
index b0ec69defafe5410c97c636049cea0e37a5b010f..9f26d7660f29a52c818629a784fa4c830cf6e68e 100644
--- a/modules/linebourse/api/pages.py
+++ b/modules/linebourse/api/pages.py
@@ -21,7 +21,7 @@
from weboob.browser.elements import method, DictElement, ItemElement
from weboob.browser.filters.json import Dict
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
Date, CleanDecimal, Eval, Field, Env, Regexp, Format,
)
from weboob.browser.pages import JsonPage, HTMLPage, LoggedPage
diff --git a/modules/linebourse/compat/__init__.py b/modules/linebourse/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/linebourse/compat/weboob_browser_filters_standard.py b/modules/linebourse/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/linebourse/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/linebourse/pages.py b/modules/linebourse/pages.py
index 679bcaf0ec077e954c7e24baa0b7e048e80b73ba..c1fdf50e2d5229578ac036c1c928ce249d90a14b 100644
--- a/modules/linebourse/pages.py
+++ b/modules/linebourse/pages.py
@@ -23,7 +23,7 @@
from weboob.browser.pages import HTMLPage, LoggedPage
from weboob.browser.elements import method, TableElement, ItemElement
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
CleanText, Date, CleanDecimal, Regexp, Eval, Field
)
from weboob.browser.filters.html import TableCell
diff --git a/modules/linuxjobs/compat/__init__.py b/modules/linuxjobs/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/linuxjobs/compat/weboob_browser_filters_standard.py b/modules/linuxjobs/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/linuxjobs/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/linuxjobs/pages.py b/modules/linuxjobs/pages.py
index 5545be5cd76cfce57a2506b039b639abecb0f8b0..c5c1bc6ef50b24ead57e6af43a6e520e8aa4a0ac 100644
--- a/modules/linuxjobs/pages.py
+++ b/modules/linuxjobs/pages.py
@@ -21,7 +21,7 @@
from weboob.capabilities.job import BaseJobAdvert
from weboob.browser.pages import HTMLPage
from weboob.browser.elements import ItemElement, ListElement, method
-from weboob.browser.filters.standard import Regexp, CleanText, Date, Env, BrowserURL
+from .compat.weboob_browser_filters_standard import Regexp, CleanText, Date, Env, BrowserURL
from weboob.browser.filters.html import Link, CleanHTML
from weboob.tools.date import parse_french_date
diff --git a/modules/logicimmo/compat/__init__.py b/modules/logicimmo/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/logicimmo/compat/weboob_browser_filters_standard.py b/modules/logicimmo/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/logicimmo/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/logicimmo/pages.py b/modules/logicimmo/pages.py
index 37edf68c46388707cdf6da6a737dfce9690d573c..9d147977dd8a44bb1f07ed2179a20c4934b21ee3 100644
--- a/modules/logicimmo/pages.py
+++ b/modules/logicimmo/pages.py
@@ -22,7 +22,7 @@
from weboob.browser.pages import HTMLPage, JsonPage
from weboob.browser.elements import ItemElement, ListElement, DictElement, method
from weboob.browser.filters.json import Dict
-from weboob.browser.filters.standard import (Currency, Format, CleanText,
+from .compat.weboob_browser_filters_standard import (Currency, Format, CleanText,
Regexp, CleanDecimal, Date, Env,
BrowserURL)
from weboob.browser.filters.html import Attr, XPath, CleanHTML
diff --git a/modules/lolix/compat/__init__.py b/modules/lolix/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/lolix/compat/weboob_browser_filters_standard.py b/modules/lolix/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/lolix/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/lolix/pages.py b/modules/lolix/pages.py
index b394c12de1231f4ce4b2c3ee3fcd3ade47dea16d..7693c8c8af5e8242a571458b9e77e62a0c4eeda2 100644
--- a/modules/lolix/pages.py
+++ b/modules/lolix/pages.py
@@ -20,7 +20,7 @@
from weboob.browser.pages import HTMLPage
from weboob.browser.elements import TableElement, ItemElement, method
-from weboob.browser.filters.standard import CleanText, Regexp, Date, Env, BrowserURL, Join, Format
+from .compat.weboob_browser_filters_standard import CleanText, Regexp, Date, Env, BrowserURL, Join, Format
from weboob.browser.filters.html import CleanHTML, TableCell
from weboob.capabilities.job import BaseJobAdvert
diff --git a/modules/lyricsdotcom/compat/__init__.py b/modules/lyricsdotcom/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/lyricsdotcom/compat/weboob_browser_filters_standard.py b/modules/lyricsdotcom/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/lyricsdotcom/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/lyricsdotcom/pages.py b/modules/lyricsdotcom/pages.py
index 3e60de6213c08fe8d0bd14999022110b642ed695..4b9b93f1e0c545856d4cee79323f34c4a48a85b3 100644
--- a/modules/lyricsdotcom/pages.py
+++ b/modules/lyricsdotcom/pages.py
@@ -23,7 +23,7 @@
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.browser.pages import HTMLPage
-from weboob.browser.filters.standard import Regexp, CleanText, Env, BrowserURL
+from .compat.weboob_browser_filters_standard import Regexp, CleanText, Env, BrowserURL
from weboob.browser.filters.html import CleanHTML, XPath
diff --git a/modules/lyricsmode/compat/__init__.py b/modules/lyricsmode/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/lyricsmode/compat/weboob_browser_filters_standard.py b/modules/lyricsmode/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/lyricsmode/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/lyricsmode/pages.py b/modules/lyricsmode/pages.py
index c7a3ee8b8c240e393c2b1f5df6f1941710b547b0..655ef00aed5af3b6a2b40bcff69de7ef1ab2f588 100644
--- a/modules/lyricsmode/pages.py
+++ b/modules/lyricsmode/pages.py
@@ -23,7 +23,7 @@
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.browser.pages import HTMLPage
-from weboob.browser.filters.standard import Regexp, CleanText
+from .compat.weboob_browser_filters_standard import Regexp, CleanText
from weboob.browser.filters.html import CleanHTML
diff --git a/modules/lyricsplanet/compat/__init__.py b/modules/lyricsplanet/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/lyricsplanet/compat/weboob_browser_filters_standard.py b/modules/lyricsplanet/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/lyricsplanet/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/lyricsplanet/pages.py b/modules/lyricsplanet/pages.py
index 6c997b808b8b922ba65e33b9a87a23a41ac9f0ee..5dbcc10c6d90b729463e73abfd1e6b202527dab1 100644
--- a/modules/lyricsplanet/pages.py
+++ b/modules/lyricsplanet/pages.py
@@ -23,7 +23,7 @@
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.browser.pages import HTMLPage
-from weboob.browser.filters.standard import Regexp, CleanText
+from .compat.weboob_browser_filters_standard import Regexp, CleanText
from weboob.browser.filters.html import CleanHTML
diff --git a/modules/manpower/compat/__init__.py b/modules/manpower/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/manpower/compat/weboob_browser_filters_standard.py b/modules/manpower/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/manpower/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/manpower/pages.py b/modules/manpower/pages.py
index fd2744c6901a66392ad84093b074fa7ee01724a3..e6a2a1c1bf5d13554fea45caf06beb2bfea67419 100644
--- a/modules/manpower/pages.py
+++ b/modules/manpower/pages.py
@@ -20,7 +20,7 @@
from weboob.browser.pages import HTMLPage
from weboob.browser.elements import ItemElement, ListElement, method
-from weboob.browser.filters.standard import CleanText, Regexp, Env, BrowserURL, Date, Format
+from .compat.weboob_browser_filters_standard import CleanText, Regexp, Env, BrowserURL, Date, Format
from weboob.browser.filters.html import CleanHTML
from weboob.capabilities.job import BaseJobAdvert
from weboob.capabilities.base import NotAvailable
diff --git a/modules/mareeinfo/compat/__init__.py b/modules/mareeinfo/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/mareeinfo/compat/weboob_browser_filters_standard.py b/modules/mareeinfo/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/mareeinfo/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/mareeinfo/pages.py b/modules/mareeinfo/pages.py
index d7957aebef674324ae13046583df2b5c29428777..123b57b6241bfaae9ec74b7af41b3dab1e5850ff 100644
--- a/modules/mareeinfo/pages.py
+++ b/modules/mareeinfo/pages.py
@@ -19,7 +19,7 @@
from weboob.browser.pages import HTMLPage
from weboob.browser.elements import ListElement, ItemElement, method
-from weboob.browser.filters.standard import CleanText, DateTime, CleanDecimal, Regexp
+from .compat.weboob_browser_filters_standard import CleanText, DateTime, CleanDecimal, Regexp
from weboob.browser.filters.html import Link, XPath
from weboob.capabilities.gauge import Gauge, GaugeMeasure, GaugeSensor
from datetime import timedelta
diff --git a/modules/marmiton/compat/__init__.py b/modules/marmiton/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/marmiton/compat/weboob_browser_filters_standard.py b/modules/marmiton/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/marmiton/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/marmiton/pages.py b/modules/marmiton/pages.py
index 64797d2420407a080b7fd560c11ea23ecdeefdb5..7d6ec24392fbde493bb30d12fc508c81b5b12b95 100644
--- a/modules/marmiton/pages.py
+++ b/modules/marmiton/pages.py
@@ -19,7 +19,7 @@
from weboob.browser.pages import HTMLPage, pagination
from weboob.browser.elements import ItemElement, ListElement, method
-from weboob.browser.filters.standard import Regexp, CleanText, Format, Env, CleanDecimal, Eval
+from .compat.weboob_browser_filters_standard import Regexp, CleanText, Format, Env, CleanDecimal, Eval
from weboob.browser.filters.html import XPath
from weboob.browser.filters.json import Dict
from weboob.capabilities.recipe import Recipe, Comment
diff --git a/modules/materielnet/compat/__init__.py b/modules/materielnet/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/materielnet/compat/weboob_browser_filters_standard.py b/modules/materielnet/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/materielnet/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/materielnet/pages.py b/modules/materielnet/pages.py
index 36f0fb09ed2884925e96516d813d4af0ea45c079..129b7582d3a850d3ccc4485c6b0f72a537d76525 100644
--- a/modules/materielnet/pages.py
+++ b/modules/materielnet/pages.py
@@ -22,7 +22,7 @@
import re
from weboob.browser.pages import HTMLPage, LoggedPage, PartialHTMLPage
-from weboob.browser.filters.standard import CleanText, CleanDecimal, Env, Format, Date, Async, Filter, Regexp, Field
+from .compat.weboob_browser_filters_standard import CleanText, CleanDecimal, Env, Format, Date, Async, Filter, Regexp, Field
from weboob.browser.elements import ListElement, ItemElement, method
from weboob.browser.filters.html import Attr, Link
from weboob.capabilities.bill import DocumentTypes, Bill, Subscription
diff --git a/modules/meslieuxparis/compat/__init__.py b/modules/meslieuxparis/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/meslieuxparis/compat/weboob_browser_filters_standard.py b/modules/meslieuxparis/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/meslieuxparis/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/meslieuxparis/pages.py b/modules/meslieuxparis/pages.py
index 3f193b1b3d32b3383f6c380cc15080612422e562..db9b724efddcbccb3a9880824111fc3282c57ddb 100644
--- a/modules/meslieuxparis/pages.py
+++ b/modules/meslieuxparis/pages.py
@@ -23,7 +23,7 @@
from dateutil import rrule
from weboob.browser.elements import method, ItemElement, DictElement
-from weboob.browser.filters.standard import CleanText, Regexp
+from .compat.weboob_browser_filters_standard import CleanText, Regexp
from weboob.browser.filters.json import Dict
from weboob.browser.pages import JsonPage
from weboob.capabilities.base import NotAvailable
diff --git a/modules/meteofrance/compat/__init__.py b/modules/meteofrance/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/meteofrance/compat/weboob_browser_filters_standard.py b/modules/meteofrance/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/meteofrance/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/meteofrance/pages.py b/modules/meteofrance/pages.py
index 7954d933ae51f20346e156ed48c701a55f3220f8..2c88b9b8ef5a22b1b23fa73bfc93e71110603bf1 100644
--- a/modules/meteofrance/pages.py
+++ b/modules/meteofrance/pages.py
@@ -25,7 +25,7 @@
from weboob.capabilities.base import NotAvailable
from weboob.capabilities.weather import Forecast, Current, City, Temperature
from weboob.browser.filters.json import Dict
-from weboob.browser.filters.standard import CleanText, CleanDecimal, Regexp, Format, Eval
+from .compat.weboob_browser_filters_standard import CleanText, CleanDecimal, Regexp, Format, Eval
class SearchCitiesPage(JsonPage):
diff --git a/modules/minutes20/compat/__init__.py b/modules/minutes20/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/minutes20/compat/weboob_browser_filters_standard.py b/modules/minutes20/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/minutes20/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/minutes20/pages.py b/modules/minutes20/pages.py
index c882938ca896227e2c5fed2e5104d09f6456af63..ee2ad9b2e27242816f1b1a7f6461871f9fd71cb6 100644
--- a/modules/minutes20/pages.py
+++ b/modules/minutes20/pages.py
@@ -20,7 +20,7 @@
# along with this weboob module. If not, see .
from weboob.browser.pages import AbstractPage
-from weboob.browser.filters.standard import CleanText
+from .compat.weboob_browser_filters_standard import CleanText
from weboob.browser.filters.html import CSS
diff --git a/modules/monster/compat/__init__.py b/modules/monster/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/monster/compat/weboob_browser_filters_standard.py b/modules/monster/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/monster/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/monster/pages.py b/modules/monster/pages.py
index bbe59009bbceafcf04e311746a62aac3f923476f..9d2499aa3edc9ba768b74475ce59ba4294b895c4 100644
--- a/modules/monster/pages.py
+++ b/modules/monster/pages.py
@@ -23,7 +23,7 @@
from weboob.browser.pages import HTMLPage, pagination
from weboob.browser.elements import ItemElement, ListElement, method
-from weboob.browser.filters.standard import CleanText, Regexp, Filter, Env, BrowserURL, Format, DateTime
+from .compat.weboob_browser_filters_standard import CleanText, Regexp, Filter, Env, BrowserURL, Format, DateTime
from weboob.browser.filters.html import CleanHTML
from weboob.capabilities.job import BaseJobAdvert
from weboob.capabilities.base import NotAvailable
diff --git a/modules/myedenred/browser.py b/modules/myedenred/browser.py
index 696ffba9e3b410c95ba26ef8c8e6dbbc0d735c89..3267f375cf14b6154a6e2e868ff1c8714edbf0b5 100644
--- a/modules/myedenred/browser.py
+++ b/modules/myedenred/browser.py
@@ -22,7 +22,7 @@
from weboob.browser import LoginBrowser, URL, need_login
from weboob.exceptions import BrowserIncorrectPassword
from weboob.tools.capabilities.bank.transactions import merge_iterators
-from .pages import LoginPage, AccountsPage, TransactionsPage
+from .pages import LoginPage, AccountsPage, AccountDetailsPage, TransactionsPage
class MyedenredBrowser(LoginBrowser):
@@ -31,6 +31,7 @@ class MyedenredBrowser(LoginBrowser):
login = URL(r'/ctr\?Length=7',
r'/ExtendedAccount/Logon', LoginPage)
accounts = URL(r'/$', AccountsPage)
+ accounts_details = URL(r'/ExtendedHome/ProductLine\?benId=(?P\d+)', AccountDetailsPage)
transactions = URL('/Card/TransactionSet', TransactionsPage)
def __init__(self, *args, **kwargs):
@@ -46,8 +47,11 @@ def do_login(self):
raise BrowserIncorrectPassword
@need_login
- def get_accounts_list(self):
- return self.accounts.stay_or_go().iter_accounts()
+ def iter_accounts(self):
+ for acc_id in self.accounts.stay_or_go().get_accounts_id():
+ yield self.accounts_details.go(headers={'X-Requested-With': 'XMLHttpRequest'},
+ token=acc_id).get_account()
+
@need_login
def iter_history(self, account):
diff --git a/modules/myedenred/compat/__init__.py b/modules/myedenred/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/myedenred/compat/weboob_browser_filters_standard.py b/modules/myedenred/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/myedenred/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/myedenred/module.py b/modules/myedenred/module.py
index 256ff9ab185db4515276ecfb150d0fbea07ff625..e62cb3e2b55c5f87c647602fb152065e584f5d35 100644
--- a/modules/myedenred/module.py
+++ b/modules/myedenred/module.py
@@ -47,7 +47,7 @@ def create_default_browser(self):
return self.create_browser(self.config['login'].get(), self.config['password'].get())
def iter_accounts(self):
- return self.browser.get_accounts_list()
+ return self.browser.iter_accounts()
def get_account(self, id):
return find_object(self.iter_accounts(), id=id, error=AccountNotFound)
diff --git a/modules/myedenred/pages.py b/modules/myedenred/pages.py
index 3372f2a574e2b8fd81aee09a5d1670e890317171..e77b4561317f32d5771126d4f16ed070b23c206b 100644
--- a/modules/myedenred/pages.py
+++ b/modules/myedenred/pages.py
@@ -20,9 +20,9 @@
from __future__ import unicode_literals
-from weboob.browser.pages import HTMLPage, LoggedPage
+from weboob.browser.pages import HTMLPage, PartialHTMLPage, LoggedPage
from weboob.browser.elements import ItemElement, method, ListElement
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
CleanText, CleanDecimal,
Regexp, DateGuesser, Field
)
@@ -43,22 +43,26 @@ def get_error(self):
class AccountsPage(LoggedPage, HTMLPage):
+ def get_accounts_id(self):
+ for e in self.doc.xpath('//ul[@id="navSideProducts"]//strong[contains(text(), "Restaurant")]/ancestor::li'):
+ yield e.attrib['id'].split('_')[-1]
+
+
+class AccountDetailsPage(LoggedPage, PartialHTMLPage):
@method
- class iter_accounts(ListElement):
- item_xpath = '//ul[@id="navSideProducts"]/li'
+ class get_account(ItemElement):
+ klass = Account
- class item(ItemElement):
- klass = Account
+ obj_type = Account.TYPE_CARD
+ obj_id = CleanText('//p[contains(text(), "Identifiant")]/a')
+ obj_label = obj_id
+ obj_currency = u'EUR'
+ obj_balance = MyDecimal('//p[@class="num"]/a')
- obj_type = Account.TYPE_CARD
- obj_id = CleanText('./a/p', replace=[('N° ', '')])
- obj_label = obj_id
- obj_currency = u'EUR'
- obj_balance = MyDecimal(u'//p[@class="num"]//strong')
+ # Every subscription a product token and a type ex: card = 240
+ obj__product_token = Regexp(CleanText('//div[contains(@id, "product")]/@id'), r'productLine_(\d*)')
+ obj__product_type = Regexp(CleanText('(//div[@class="logo"])[1]//img/@src'), "/img/product_(\d*).png")
- # Every subscription a product token and a type ex: card = 240
- obj__product_token = Regexp(CleanText('./@id'), r'navSideProduct_(\d*)')
- obj__product_type = Regexp(CleanText('(//div[@class="logo"])[1]//img/@src'), "/img/product_(\d*).png")
class TransactionsPage(LoggedPage, HTMLPage):
@@ -73,6 +77,7 @@ class item(ItemElement):
obj_label = CleanText('.//h3/strong')
obj_raw = Field('label')
obj_amount = MyDecimal('./td[@class="al-r"]/div/span[has-class("badge")]')
+
def obj_type(self):
amount = Field('amount')(self)
if amount < 0:
diff --git a/modules/myfoncia/compat/__init__.py b/modules/myfoncia/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/myfoncia/compat/weboob_browser_filters_standard.py b/modules/myfoncia/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/myfoncia/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/myfoncia/pages.py b/modules/myfoncia/pages.py
index b8c63f2b90576327c40134ccb2a41fa09e1b7917..2fe5a9ff0c5b84a6214a4d912d69e8b36e71698d 100644
--- a/modules/myfoncia/pages.py
+++ b/modules/myfoncia/pages.py
@@ -20,7 +20,7 @@
from __future__ import unicode_literals
from weboob.browser.pages import HTMLPage
-from weboob.browser.filters.standard import CleanDecimal, CleanText, Date, Env, Format
+from .compat.weboob_browser_filters_standard import CleanDecimal, CleanText, Date, Env, Format
from weboob.browser.filters.html import Attr, Link, XPathNotFound
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.capabilities.base import NotAvailable
diff --git a/modules/n26/browser.py b/modules/n26/browser.py
index 74f437db64efc4cf9f03f372ec00a9a02b74325f..4d99bd5cb27a5a3084332926abf49563ebc6ebfa 100644
--- a/modules/n26/browser.py
+++ b/modules/n26/browser.py
@@ -24,7 +24,7 @@
from weboob.browser.browsers import DomainBrowser
from weboob.capabilities.base import find_object, NotAvailable
from weboob.capabilities.bank import Account, Transaction, AccountNotFound
-from weboob.browser.filters.standard import CleanText
+from .compat.weboob_browser_filters_standard import CleanText
from weboob.exceptions import BrowserIncorrectPassword, BrowserUnavailable
from weboob.browser.exceptions import ClientError
diff --git a/modules/n26/compat/__init__.py b/modules/n26/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/n26/compat/weboob_browser_filters_standard.py b/modules/n26/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/n26/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/nalo/compat/__init__.py b/modules/nalo/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/nalo/compat/weboob_browser_filters_standard.py b/modules/nalo/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/nalo/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/nalo/pages.py b/modules/nalo/pages.py
index 77ee206a87e53b07a746a9b53f564b955a44e00d..a7639d3111e0e9030db375fab0185dac660a6191 100644
--- a/modules/nalo/pages.py
+++ b/modules/nalo/pages.py
@@ -24,7 +24,7 @@
from weboob.browser.pages import LoggedPage, JsonPage
from weboob.browser.elements import method, DictElement, ItemElement
from weboob.browser.filters.json import Dict
-from weboob.browser.filters.standard import Eval
+from .compat.weboob_browser_filters_standard import Eval
from weboob.capabilities.bank import Account
diff --git a/modules/nef/compat/__init__.py b/modules/nef/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/nef/compat/weboob_browser_filters_standard.py b/modules/nef/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/nef/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/nef/pages.py b/modules/nef/pages.py
index 2e2b1d18809f986db0e61d827a2023f2258d5f3b..4bda84aeeff27441db26d8b3959ae3ab3957a534 100644
--- a/modules/nef/pages.py
+++ b/modules/nef/pages.py
@@ -22,7 +22,7 @@
import re
from weboob.browser.elements import ListElement, DictElement, ItemElement, method, TableElement
-from weboob.browser.filters.standard import CleanText, CleanDecimal, Regexp, Field, Date
+from .compat.weboob_browser_filters_standard import CleanText, CleanDecimal, Regexp, Field, Date
from weboob.browser.pages import HTMLPage, PartialHTMLPage, CsvPage, LoggedPage
from weboob.browser.filters.json import Dict
from weboob.browser.filters.html import Attr, TableCell
diff --git a/modules/netfinca/compat/__init__.py b/modules/netfinca/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/netfinca/compat/weboob_browser_filters_standard.py b/modules/netfinca/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/netfinca/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/netfinca/module.py b/modules/netfinca/module.py
index 6987162d165d51fd6a5c46b970ba2ed11a549421..ef4382bbe9bcfc196ad784dbd7ea3b1cc515a0ff 100644
--- a/modules/netfinca/module.py
+++ b/modules/netfinca/module.py
@@ -20,6 +20,7 @@
from __future__ import unicode_literals
+from weboob.capabilities.bank import CapBank
from weboob.tools.backend import Module
from .browser import NetfincaBrowser
@@ -27,7 +28,7 @@
__all__ = ['NetfincaModule']
-class NetfincaModule(Module):
+class NetfincaModule(Module, CapBank):
NAME = 'netfinca'
DESCRIPTION = 'netfinca website'
MAINTAINER = 'Martin Sicot'
diff --git a/modules/netfinca/pages.py b/modules/netfinca/pages.py
index f40ce72cf649f2cae01e0913e28666dd373e02bb..1b9b39e9afecd5705da1f611b500c55d7007c68a 100644
--- a/modules/netfinca/pages.py
+++ b/modules/netfinca/pages.py
@@ -25,7 +25,7 @@
from weboob.browser.pages import HTMLPage, LoggedPage
from weboob.browser.elements import method, ItemElement, TableElement
-from weboob.browser.filters.standard import CleanText, CleanDecimal, Currency
+from .compat.weboob_browser_filters_standard import CleanText, CleanDecimal, Currency
from weboob.browser.filters.html import TableCell, Attr
from weboob.capabilities.bank import Investment, Account
from weboob.capabilities.base import NotAvailable
diff --git a/modules/oney/browser.py b/modules/oney/browser.py
index 15db5e63789fb5e78a8a8b25d2af8f1b0e6f8f4f..a7f5ee4f532146e391507887673803ffd31f97cb 100644
--- a/modules/oney/browser.py
+++ b/modules/oney/browser.py
@@ -17,7 +17,9 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this weboob module. If not, see .
-from datetime import date
+from datetime import date, timedelta
+from dateutil.relativedelta import relativedelta
+from itertools import chain
from weboob.exceptions import BrowserIncorrectPassword
from weboob.browser import LoginBrowser, URL, need_login
@@ -107,15 +109,29 @@ def get_accounts_list(self):
return accounts
- def _build_hist_form(self):
+ def _build_hist_form(self, last_months=False):
form = {}
d = date.today()
- form['jourDebut'] = '1'
- form['moisDebut'] = '1'
- form['anneeDebut'] = '2016'
- form['jourFin'] = str(d.day)
- form['moisFin'] = str(d.month)
- form['anneeFin'] = str(d.year)
+
+ if not last_months:
+ # before the last two months
+ end = d.replace(day=1) + relativedelta(months=-1, days=-1)
+ form['jourDebut'] = '1'
+ form['moisDebut'] = '1'
+ form['anneeDebut'] = '2016'
+ form['jourFin'] = str(end.day)
+ form['moisFin'] = str(end.month)
+ form['anneeFin'] = str(end.year)
+ else:
+ # the last two months
+ start = d.replace(day=1) - timedelta(days=1)
+ form['jourDebut'] = '1'
+ form['moisDebut'] = str(start.month)
+ form['anneeDebut'] = str(start.year)
+ form['jourFin'] = str(d.day)
+ form['moisFin'] = str(d.month)
+ form['anneeFin'] = str(d.year)
+
form['typeOpe'] = 'deux'
form['formatFichier'] = 'xls' # or pdf... great choice
return form
@@ -134,9 +150,17 @@ def iter_history(self, account):
elif account._site == 'other':
if self.last_hist.go().has_transactions():
- self.credit_hist.go(params=self._build_hist_form())
- d = date.today().replace(day=1) # TODO is it the right date?
- for tr in self.page.iter_history():
+ # transactions are missing from the xls from 2016 to today
+ # so two requests are needed
+ d = date.today()
+ page_before = self.credit_hist.open(
+ params=self._build_hist_form(last_months=True)
+ )
+ page_today = self.credit_hist.go(
+ params=self._build_hist_form()
+ )
+
+ for tr in chain(page_before.iter_history(), page_today.iter_history()):
if new_date(tr.date) < d:
yield tr
diff --git a/modules/oney/compat/weboob_browser_filters_standard.py b/modules/oney/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/oney/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/oney/pages.py b/modules/oney/pages.py
index 4acfaca27e541105c68d75ebad7cf9ecc1a50b29..094b50d90419b7b9730bd8cf369a5b7e99e34404 100644
--- a/modules/oney/pages.py
+++ b/modules/oney/pages.py
@@ -31,7 +31,7 @@
from weboob.tools.date import parse_french_date
from weboob.browser.pages import HTMLPage, LoggedPage, pagination, XLSPage, PartialHTMLPage
from weboob.browser.elements import ListElement, ItemElement, method
-from weboob.browser.filters.standard import Env, CleanDecimal, CleanText, Field, Format, Currency
+from .compat.weboob_browser_filters_standard import Env, CleanDecimal, CleanText, Field, Format, Currency
from weboob.browser.filters.html import Attr
from weboob.exceptions import BrowserIncorrectPassword
diff --git a/modules/onlinenet/compat/__init__.py b/modules/onlinenet/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/onlinenet/compat/weboob_browser_filters_standard.py b/modules/onlinenet/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/onlinenet/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/onlinenet/pages.py b/modules/onlinenet/pages.py
index b19d79998ac7e4cfc01cc7db3153ee1dbd9242bc..b483774d9e84a292c20f661ad778b6724e88968c 100644
--- a/modules/onlinenet/pages.py
+++ b/modules/onlinenet/pages.py
@@ -21,7 +21,7 @@
import re
from weboob.browser.pages import HTMLPage, LoggedPage
-from weboob.browser.filters.standard import CleanText, CleanDecimal, Env, Format, Date
+from .compat.weboob_browser_filters_standard import CleanText, CleanDecimal, Env, Format, Date
from weboob.browser.filters.html import Attr, TableCell
from weboob.browser.elements import ListElement, ItemElement, TableElement, method
from weboob.capabilities.bill import DocumentTypes, Bill, Document, Subscription
diff --git a/modules/opensubtitles/compat/__init__.py b/modules/opensubtitles/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/opensubtitles/compat/weboob_browser_filters_standard.py b/modules/opensubtitles/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/opensubtitles/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/opensubtitles/pages.py b/modules/opensubtitles/pages.py
index 7ec3fecd804bea4868747b922369cb5e326f62a2..045dd7d084da845f71aa8287ce802fdb46a883b2 100644
--- a/modules/opensubtitles/pages.py
+++ b/modules/opensubtitles/pages.py
@@ -22,7 +22,7 @@
from weboob.browser.pages import HTMLPage, pagination
from weboob.browser.elements import TableElement, ItemElement, method
from weboob.browser.filters.html import Attr, Link, AbsoluteLink
-from weboob.browser.filters.standard import Regexp, CleanText, CleanDecimal
+from .compat.weboob_browser_filters_standard import Regexp, CleanText, CleanDecimal
class SearchPage(HTMLPage):
diff --git a/modules/orange/pages/bills.py b/modules/orange/pages/bills.py
index d9cc37c47edb486c201e542762e94d3a6ab4ec8f..08eaef6a000f480e1551f538cbb517c5eddc9f31 100644
--- a/modules/orange/pages/bills.py
+++ b/modules/orange/pages/bills.py
@@ -28,7 +28,7 @@
from weboob.browser.pages import HTMLPage, LoggedPage, JsonPage
from weboob.capabilities.bill import Subscription
from weboob.browser.elements import DictElement, ListElement, ItemElement, method, TableElement
-from weboob.browser.filters.standard import CleanDecimal, CleanText, Env, Field, Regexp, Date, Currency, BrowserURL, Format
+from .compat.weboob_browser_filters_standard import CleanDecimal, CleanText, Env, Field, Regexp, Date, Currency, BrowserURL, Format
from weboob.browser.filters.html import Link, TableCell
from weboob.browser.filters.javascript import JSValue
from weboob.browser.filters.json import Dict
diff --git a/modules/orange/pages/compat/__init__.py b/modules/orange/pages/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/orange/pages/compat/weboob_browser_filters_standard.py b/modules/orange/pages/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/orange/pages/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/orange/pages/login.py b/modules/orange/pages/login.py
index 76aae259a283795c32ad26a6b837a404bdef61bb..bc3365d703394a08bd763e9a9a536b070ebf1805 100644
--- a/modules/orange/pages/login.py
+++ b/modules/orange/pages/login.py
@@ -20,7 +20,7 @@
from weboob.browser.pages import HTMLPage, LoggedPage
from weboob.tools.json import json
-from weboob.browser.filters.standard import CleanText, Format
+from .compat.weboob_browser_filters_standard import CleanText, Format
class LoginPage(HTMLPage):
diff --git a/modules/orange/pages/profile.py b/modules/orange/pages/profile.py
index 8fe600f3cf94d3f5029bc025d3b5b4ba6130bd95..52a2a34439a0b9199f6709ba06ec76e9b68ed249 100644
--- a/modules/orange/pages/profile.py
+++ b/modules/orange/pages/profile.py
@@ -21,7 +21,7 @@
from weboob.browser.pages import HTMLPage, LoggedPage
from weboob.capabilities.profile import Profile
-from weboob.browser.filters.standard import CleanText, Format
+from .compat.weboob_browser_filters_standard import CleanText, Format
class ProfilePage(LoggedPage, HTMLPage):
diff --git a/modules/ovh/compat/__init__.py b/modules/ovh/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/ovh/compat/weboob_browser_filters_standard.py b/modules/ovh/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/ovh/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/ovh/pages.py b/modules/ovh/pages.py
index 376c9a3199d4010c53d0adca8bd27135b541bc98..66e58a0a49fd9d4a751bbfc875b6a3561b23fd49 100644
--- a/modules/ovh/pages.py
+++ b/modules/ovh/pages.py
@@ -20,7 +20,7 @@
from weboob.capabilities.bill import DocumentTypes, Bill, Subscription
from weboob.browser.pages import HTMLPage, LoggedPage, JsonPage
-from weboob.browser.filters.standard import CleanDecimal, CleanText, Env, Format, Date
+from .compat.weboob_browser_filters_standard import CleanDecimal, CleanText, Env, Format, Date
from weboob.browser.filters.html import Attr
from weboob.browser.filters.json import Dict
from weboob.browser.elements import ListElement, ItemElement, method, DictElement
diff --git a/modules/pagesjaunes/compat/__init__.py b/modules/pagesjaunes/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/pagesjaunes/compat/weboob_browser_filters_standard.py b/modules/pagesjaunes/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/pagesjaunes/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/pagesjaunes/pages.py b/modules/pagesjaunes/pages.py
index db6b79833e3db291e9e5cb9bea41797c06e26f46..98680612760ed9f042a1c624413fceff28622a38 100644
--- a/modules/pagesjaunes/pages.py
+++ b/modules/pagesjaunes/pages.py
@@ -24,7 +24,7 @@
from dateutil import rrule
from weboob.browser.elements import method, ListElement, ItemElement
-from weboob.browser.filters.standard import CleanText, Regexp
+from .compat.weboob_browser_filters_standard import CleanText, Regexp
from weboob.browser.filters.html import AbsoluteLink, HasElement
from weboob.browser.pages import HTMLPage
from weboob.capabilities.base import NotLoaded, NotAvailable
@@ -41,7 +41,10 @@ class item(ItemElement):
obj_name = CleanText('.//a[has-class("denomination-links")]')
obj_address = CleanText('.//a[has-class("adresse")]')
- obj_phone = Regexp(CleanText('.//strong[@class="num"]', replace=[(' ', '')]), r'^0(\d{9})$', r'+33\1')
+ obj_phone = Regexp(
+ CleanText(
+ './/div[has-class("tel-zone")][span[contains(text(),"Tél")]]//strong[@class="num"]',
+ replace=[(' ', '')]), r'^0(\d{9})$', r'+33\1')
obj_url = AbsoluteLink('.//a[has-class("denomination-links")]')
obj_opening = HasElement('.//span[text()="Horaires"]', NotLoaded, NotAvailable)
diff --git a/modules/pap/compat/__init__.py b/modules/pap/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/pap/compat/weboob_browser_filters_standard.py b/modules/pap/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/pap/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/pap/pages.py b/modules/pap/pages.py
index 6eb6783712e52d993685c0aa2f9f1eddd3caf666..792260046b6a152e777bfe72657512a22862e2d2 100644
--- a/modules/pap/pages.py
+++ b/modules/pap/pages.py
@@ -22,7 +22,7 @@
from weboob.tools.date import parse_french_date
from weboob.browser.pages import HTMLPage, JsonPage, pagination
from weboob.browser.elements import ItemElement, ListElement, DictElement, method
-from weboob.browser.filters.standard import (CleanText, CleanDecimal, Regexp,
+from .compat.weboob_browser_filters_standard import (CleanText, CleanDecimal, Regexp,
Env, BrowserURL, Format, Currency)
from weboob.browser.filters.html import Attr, Link, XPath, CleanHTML
from weboob.browser.filters.json import Dict
diff --git a/modules/paroles2chansons/compat/__init__.py b/modules/paroles2chansons/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/paroles2chansons/compat/weboob_browser_filters_standard.py b/modules/paroles2chansons/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/paroles2chansons/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/paroles2chansons/pages.py b/modules/paroles2chansons/pages.py
index 7f5339dd07dbf18874c99b8c2f1f79e5c3ac20be..6023cbdd54d0098dd9b8d52097f30f6d47f79bd6 100644
--- a/modules/paroles2chansons/pages.py
+++ b/modules/paroles2chansons/pages.py
@@ -24,7 +24,7 @@
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.browser.pages import HTMLPage
-from weboob.browser.filters.standard import Regexp, CleanText
+from .compat.weboob_browser_filters_standard import Regexp, CleanText
from weboob.browser.filters.html import CleanHTML
diff --git a/modules/parolesmania/compat/__init__.py b/modules/parolesmania/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/parolesmania/compat/weboob_browser_filters_standard.py b/modules/parolesmania/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/parolesmania/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/parolesmania/pages.py b/modules/parolesmania/pages.py
index 15afecfe62507f8fa983595a958220d30dd6d6a6..0c896d13413f3827f6f3b08851a96865fec2644c 100644
--- a/modules/parolesmania/pages.py
+++ b/modules/parolesmania/pages.py
@@ -23,7 +23,7 @@
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.browser.pages import HTMLPage
-from weboob.browser.filters.standard import Regexp, CleanText
+from .compat.weboob_browser_filters_standard import Regexp, CleanText
from weboob.browser.filters.html import CleanHTML
diff --git a/modules/parolesmusique/compat/__init__.py b/modules/parolesmusique/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/parolesmusique/compat/weboob_browser_filters_standard.py b/modules/parolesmusique/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/parolesmusique/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/parolesmusique/pages.py b/modules/parolesmusique/pages.py
index b027a120bd813321d57bf329d16b531cda82e7cd..c9d057d295c2bcc7546b683051a379e32ff0d5b7 100644
--- a/modules/parolesmusique/pages.py
+++ b/modules/parolesmusique/pages.py
@@ -23,7 +23,7 @@
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.browser.pages import HTMLPage
-from weboob.browser.filters.standard import Regexp, CleanText, Format
+from .compat.weboob_browser_filters_standard import Regexp, CleanText, Format
from weboob.browser.filters.html import CleanHTML
import random
diff --git a/modules/parolesnet/compat/__init__.py b/modules/parolesnet/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/parolesnet/compat/weboob_browser_filters_standard.py b/modules/parolesnet/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/parolesnet/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/parolesnet/pages.py b/modules/parolesnet/pages.py
index df4423af3ef5b5937ad993aed1f6da3484bd8195..d9f0e9bc094e42b22311a4055f69d69b76efd1f4 100644
--- a/modules/parolesnet/pages.py
+++ b/modules/parolesnet/pages.py
@@ -23,7 +23,7 @@
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.browser.pages import HTMLPage
-from weboob.browser.filters.standard import Regexp, CleanText
+from .compat.weboob_browser_filters_standard import Regexp, CleanText
from weboob.browser.filters.html import CleanHTML
diff --git a/modules/pastealacon/browser.py b/modules/pastealacon/browser.py
index 65af6fb265e567e6d7c3d6944804de9073438778..bab99587f793c41dd9975293dfb24c6a55173f0e 100644
--- a/modules/pastealacon/browser.py
+++ b/modules/pastealacon/browser.py
@@ -20,7 +20,7 @@
import re
from weboob.capabilities.paste import BasePaste, PasteNotFound
-from weboob.browser.filters.standard import BrowserURL, CleanText, DateTime, Env, Field, RawText, Regexp
+from .compat.weboob_browser_filters_standard import BrowserURL, CleanText, DateTime, Env, Field, RawText, Regexp
from weboob.browser.pages import HTMLPage
from weboob.browser.browsers import PagesBrowser
from weboob.browser.url import URL
diff --git a/modules/pastealacon/compat/__init__.py b/modules/pastealacon/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/pastealacon/compat/weboob_browser_filters_standard.py b/modules/pastealacon/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/pastealacon/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/pastebin/browser.py b/modules/pastebin/browser.py
index 42214cdccd629f9feb88abafe45f314a34cce663..81d0c87bb75892179ad6c63674625998851e4659 100644
--- a/modules/pastebin/browser.py
+++ b/modules/pastebin/browser.py
@@ -20,10 +20,10 @@
import re
-from weboob.browser import URL, LoginBrowser, need_login
+from weboob.browser.browsers import URL, LoginBrowser, need_login
from weboob.browser.elements import ItemElement, method
from weboob.browser.filters.html import Attr
-from weboob.browser.filters.standard import Base, BrowserURL, CleanText, DateTime, Env, Field, Filter, FilterError, RawText
+from .compat.weboob_browser_filters_standard import Base, BrowserURL, CleanText, DateTime, Env, Field, Filter, FilterError, RawText
from weboob.browser.pages import HTMLPage, RawPage
from weboob.capabilities.paste import BasePaste, PasteNotFound
from weboob.exceptions import BrowserHTTPNotFound, BrowserIncorrectPassword, BrowserUnavailable
diff --git a/modules/pastebin/compat/__init__.py b/modules/pastebin/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/pastebin/compat/weboob_browser_filters_standard.py b/modules/pastebin/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/pastebin/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/paypal/compat/__init__.py b/modules/paypal/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/paypal/compat/weboob_browser_filters_standard.py b/modules/paypal/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/paypal/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/paypal/pages.py b/modules/paypal/pages.py
index 00bb95426c01cb9aeca405025e11ef087d12e078..f62e0031f5f2c5e695246bdec8a7dfa8990d23e1 100644
--- a/modules/paypal/pages.py
+++ b/modules/paypal/pages.py
@@ -27,7 +27,7 @@
from weboob.exceptions import BrowserUnavailable, ActionNeeded
from weboob.browser.exceptions import ServerError
from weboob.browser.pages import HTMLPage, JsonPage, LoggedPage
-from weboob.browser.filters.standard import CleanText, CleanDecimal
+from .compat.weboob_browser_filters_standard import CleanText, CleanDecimal
from weboob.tools.capabilities.bank.transactions import FrenchTransaction
from weboob.tools.date import parse_french_date
from weboob.tools.js import Javascript
diff --git a/modules/phpbb/pages/compat/__init__.py b/modules/phpbb/pages/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/phpbb/pages/compat/weboob_browser_filters_standard.py b/modules/phpbb/pages/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/phpbb/pages/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/phpbb/pages/forum.py b/modules/phpbb/pages/forum.py
index 17a0833013e8e0205bd82610a4165c48e6302ccd..d0aafdf50abb156f10de944c2e8d8b34edf0b950 100644
--- a/modules/phpbb/pages/forum.py
+++ b/modules/phpbb/pages/forum.py
@@ -20,7 +20,7 @@
from time import sleep
-from weboob.browser.filters.standard import CleanText
+from .compat.weboob_browser_filters_standard import CleanText
from weboob.tools.compat import urlsplit, parse_qs
from .index import PhpBBPage
diff --git a/modules/piratebay/pages/compat/__init__.py b/modules/piratebay/pages/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/piratebay/pages/compat/weboob_browser_filters_standard.py b/modules/piratebay/pages/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/piratebay/pages/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/piratebay/pages/torrents.py b/modules/piratebay/pages/torrents.py
index e01000c0c9355e761129739e56758c35123f6874..aee74ed6eda007860a7b4c0ceb2f10cdda1fb3b0 100644
--- a/modules/piratebay/pages/torrents.py
+++ b/modules/piratebay/pages/torrents.py
@@ -22,7 +22,7 @@
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.capabilities.torrent import Torrent
from weboob.capabilities.base import NotAvailable
-from weboob.browser.filters.standard import RawText, CleanText, Regexp, Date, Type
+from .compat.weboob_browser_filters_standard import RawText, CleanText, Regexp, Date, Type
class TorrentsPage(HTMLPage):
diff --git a/modules/podnapisi/compat/__init__.py b/modules/podnapisi/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/podnapisi/compat/weboob_browser_filters_standard.py b/modules/podnapisi/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/podnapisi/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/podnapisi/pages.py b/modules/podnapisi/pages.py
index 7313c07143d64bc528b206163e8d3a00f0fd0dc0..fb94557a2caf22f8dad576ac240479784bbc5648 100644
--- a/modules/podnapisi/pages.py
+++ b/modules/podnapisi/pages.py
@@ -21,7 +21,7 @@
from weboob.browser.elements import TableElement, ItemElement, method
from weboob.browser.pages import HTMLPage, pagination
from weboob.browser.filters.html import TableCell, AbsoluteLink, Attr
-from weboob.browser.filters.standard import CleanText, Field, Type, Regexp
+from .compat.weboob_browser_filters_standard import CleanText, Field, Type, Regexp
from weboob.capabilities.subtitle import Subtitle
from weboob.tools.compat import urljoin
diff --git a/modules/poivy/compat/__init__.py b/modules/poivy/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/poivy/compat/weboob_browser_filters_standard.py b/modules/poivy/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/poivy/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/poivy/pages.py b/modules/poivy/pages.py
index d7ae47d70dcf1a48fad450b6c1dc8392ccb6a859..d95190020fc847069e9acc8cc596e112e0aeca12 100644
--- a/modules/poivy/pages.py
+++ b/modules/poivy/pages.py
@@ -20,7 +20,7 @@
from weboob.exceptions import BrowserBanned
from weboob.browser.pages import HTMLPage, LoggedPage, pagination
from weboob.browser.elements import ListElement, ItemElement, method
-from weboob.browser.filters.standard import CleanText, CleanDecimal, Field, DateTime, Format
+from .compat.weboob_browser_filters_standard import CleanText, CleanDecimal, Field, DateTime, Format
from weboob.browser.filters.html import Attr, Link
from weboob.capabilities.bill import Subscription, Detail
diff --git a/modules/popolemploi/compat/__init__.py b/modules/popolemploi/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/popolemploi/compat/weboob_browser_filters_standard.py b/modules/popolemploi/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/popolemploi/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/popolemploi/pages.py b/modules/popolemploi/pages.py
index db8dedb9133d73361d566d0eba6ef3a95c9ffa74..4102088fdf86d024c02d3eac1d63b0a55b754929 100644
--- a/modules/popolemploi/pages.py
+++ b/modules/popolemploi/pages.py
@@ -20,7 +20,7 @@
from weboob.capabilities.job import BaseJobAdvert
from weboob.browser.pages import HTMLPage
from weboob.browser.elements import ItemElement, ListElement, method
-from weboob.browser.filters.standard import Regexp, CleanText, Env, BrowserURL, Filter, Join
+from .compat.weboob_browser_filters_standard import Regexp, CleanText, Env, BrowserURL, Filter, Join
from weboob.browser.filters.html import XPath
diff --git a/modules/pornhub/compat/__init__.py b/modules/pornhub/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/pornhub/compat/weboob_browser_filters_standard.py b/modules/pornhub/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/pornhub/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/pornhub/pages.py b/modules/pornhub/pages.py
index b13adaf2fdba1ca0b8e3cdf818382bc6ef123457..e0b8624ceaf94602bb10ebe85f615b3656849358 100644
--- a/modules/pornhub/pages.py
+++ b/modules/pornhub/pages.py
@@ -20,7 +20,7 @@
from weboob.browser.elements import ListElement, ItemElement, method
from weboob.browser.filters.html import Link, CSS, Attr
-from weboob.browser.filters.standard import CleanText, Duration, Regexp, Env
+from .compat.weboob_browser_filters_standard import CleanText, Duration, Regexp, Env
from weboob.browser.pages import HTMLPage, pagination
from weboob.capabilities.base import NotAvailable
from weboob.capabilities.image import Thumbnail
diff --git a/modules/prixcarburants/compat/__init__.py b/modules/prixcarburants/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/prixcarburants/compat/weboob_browser_filters_standard.py b/modules/prixcarburants/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/prixcarburants/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/prixcarburants/pages.py b/modules/prixcarburants/pages.py
index cdc9f195ef7be9cf7070ee76fb44f4022b6dc6e1..47958201c4be3a25d695e57343bd97bd8c4b7163 100644
--- a/modules/prixcarburants/pages.py
+++ b/modules/prixcarburants/pages.py
@@ -18,7 +18,7 @@
# along with this weboob module. If not, see .
from weboob.browser.pages import HTMLPage
-from weboob.browser.filters.standard import CleanText, Env, Field, CleanDecimal, Date, Format
+from .compat.weboob_browser_filters_standard import CleanText, Env, Field, CleanDecimal, Date, Format
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.capabilities.pricecomparison import Product, Shop, Price
diff --git a/modules/radiofrance/compat/__init__.py b/modules/radiofrance/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/radiofrance/compat/weboob_browser_filters_standard.py b/modules/radiofrance/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/radiofrance/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/radiofrance/pages.py b/modules/radiofrance/pages.py
index 80b89611e6d62bf5f00627a2863a11591d2d600a..74766d825cad1b58aa1c27c52e3b4f03b1490af8 100644
--- a/modules/radiofrance/pages.py
+++ b/modules/radiofrance/pages.py
@@ -21,7 +21,7 @@
from weboob.browser.pages import HTMLPage, JsonPage, XMLPage
from weboob.browser.filters.json import Dict
from weboob.browser.filters.html import XPath
-from weboob.browser.filters.standard import Format, CleanText, Join, Env, Regexp, Duration, Time
+from .compat.weboob_browser_filters_standard import Format, CleanText, Join, Env, Regexp, Duration, Time
from weboob.capabilities.audio import BaseAudio
from weboob.tools.capabilities.audio.audio import BaseAudioIdFilter
from weboob.capabilities.image import Thumbnail
diff --git a/modules/ratp/compat/__init__.py b/modules/ratp/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/ratp/compat/weboob_browser_filters_standard.py b/modules/ratp/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/ratp/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/ratp/pages.py b/modules/ratp/pages.py
index e2c2e25164da8146dd63195e08e78d559a3d4f49..bcd325a25ff9c35b84904398156ef2d384718038 100644
--- a/modules/ratp/pages.py
+++ b/modules/ratp/pages.py
@@ -21,7 +21,7 @@
from weboob.browser.elements import method, ItemElement, ListElement
from weboob.browser.filters.html import Attr
-from weboob.browser.filters.standard import CleanText, Eval
+from .compat.weboob_browser_filters_standard import CleanText, Eval
from weboob.browser.pages import HTMLPage
from weboob.capabilities.gauge import Gauge, GaugeMeasure
diff --git a/modules/razibus/compat/__init__.py b/modules/razibus/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/razibus/compat/weboob_browser_filters_standard.py b/modules/razibus/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/razibus/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/razibus/pages.py b/modules/razibus/pages.py
index ea62cc7514d5637d2265de5b29074efeef2f5269..73fb2dde59f918f6c43cc63d11fffea8ff105f05 100644
--- a/modules/razibus/pages.py
+++ b/modules/razibus/pages.py
@@ -24,7 +24,7 @@
from weboob.browser.pages import HTMLPage
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.browser.filters.html import CleanHTML, Link
-from weboob.browser.filters.standard import Regexp, CleanText, DateTime, CombineDate, Filter, Env
+from .compat.weboob_browser_filters_standard import Regexp, CleanText, DateTime, CombineDate, Filter, Env
class EndTime(Filter):
diff --git a/modules/reddit/compat/__init__.py b/modules/reddit/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/reddit/compat/weboob_browser_filters_standard.py b/modules/reddit/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/reddit/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/reddit/pages.py b/modules/reddit/pages.py
index ae11da59527f90ce66fdfa83e7bbbd7e2d818a87..49092d049e8d7935dc73cfc4ab1aad0d7ef192ba 100644
--- a/modules/reddit/pages.py
+++ b/modules/reddit/pages.py
@@ -22,7 +22,7 @@
from collections import OrderedDict
from weboob.browser.elements import method, ListElement, ItemElement, SkipItem
-from weboob.browser.filters.standard import CleanText, Regexp, Field, DateTime
+from .compat.weboob_browser_filters_standard import CleanText, Regexp, Field, DateTime
from weboob.browser.filters.html import AbsoluteLink, Link, Attr, CleanHTML
from weboob.browser.pages import HTMLPage, RawPage, pagination
from weboob.capabilities.image import BaseImage, Thumbnail
diff --git a/modules/redmine/pages/compat/__init__.py b/modules/redmine/pages/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/redmine/pages/compat/weboob_browser_filters_standard.py b/modules/redmine/pages/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/redmine/pages/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/redmine/pages/issues.py b/modules/redmine/pages/issues.py
index b9394d2ee0a161711d93d20c323d27a6c1d1df55..f1dd222a9a3e85c63c48b92dff505d6c653ae821 100644
--- a/modules/redmine/pages/issues.py
+++ b/modules/redmine/pages/issues.py
@@ -25,7 +25,7 @@
from weboob.tools.date import parse_french_date
from weboob.tools.json import json
from weboob.tools.misc import to_unicode
-from weboob.browser.filters.standard import CleanText
+from .compat.weboob_browser_filters_standard import CleanText
from .index import BaseHTMLPage
diff --git a/modules/regionsjob/compat/__init__.py b/modules/regionsjob/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/regionsjob/compat/weboob_browser_filters_standard.py b/modules/regionsjob/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/regionsjob/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/regionsjob/pages.py b/modules/regionsjob/pages.py
index cc39e133707fa8061901986cf2f8715e87568e4d..ca20f176f5703ec5b37261dc6929ced9664c0236 100644
--- a/modules/regionsjob/pages.py
+++ b/modules/regionsjob/pages.py
@@ -19,7 +19,7 @@
from weboob.browser.pages import HTMLPage, pagination, JsonPage
from weboob.browser.elements import ItemElement, ListElement, method
-from weboob.browser.filters.standard import CleanText, Regexp, Env, Date, BrowserURL, Join
+from .compat.weboob_browser_filters_standard import CleanText, Regexp, Env, Date, BrowserURL, Join
from weboob.browser.filters.html import CleanHTML, Link
from weboob.browser.filters.json import Dict
from weboob.capabilities.job import BaseJobAdvert
diff --git a/modules/residentadvisor/compat/__init__.py b/modules/residentadvisor/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/residentadvisor/compat/weboob_browser_filters_standard.py b/modules/residentadvisor/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/residentadvisor/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/residentadvisor/pages.py b/modules/residentadvisor/pages.py
index 5f957707ffd6c14626f1089278467a40d6f6c856..09f4aa885f888a9ce551d7dd7942ecd50351cb50 100644
--- a/modules/residentadvisor/pages.py
+++ b/modules/residentadvisor/pages.py
@@ -21,7 +21,7 @@
from weboob.capabilities.calendar import CATEGORIES, STATUS, TICKET
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.browser.filters.html import Attr, CleanHTML, Link
-from weboob.browser.filters.standard import CleanDecimal, CleanText, Date, CombineDate, DateTime, Regexp, Time, Type
+from .compat.weboob_browser_filters_standard import CleanDecimal, CleanText, Date, CombineDate, DateTime, Regexp, Time, Type
from weboob.browser.pages import HTMLPage
from weboob.capabilities.calendar import BaseCalendarEvent
diff --git a/modules/rmll/compat/__init__.py b/modules/rmll/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/rmll/compat/weboob_browser_filters_standard.py b/modules/rmll/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/rmll/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/rmll/pages.py b/modules/rmll/pages.py
index 3719df03d415c418a69e333f74c1116770501c7b..c47a7b8bdb93fe30d5c747fb799fda0ff04bbe41 100644
--- a/modules/rmll/pages.py
+++ b/modules/rmll/pages.py
@@ -23,7 +23,7 @@
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.browser.filters.html import CleanHTML, Link, XPath
from weboob.browser.filters.json import Dict
-from weboob.browser.filters.standard import CleanText, DateTime, Duration, Filter, Format, Regexp
+from .compat.weboob_browser_filters_standard import CleanText, DateTime, Duration, Filter, Format, Regexp
from weboob.browser.pages import HTMLPage, JsonPage
from weboob.capabilities import NotLoaded
from weboob.capabilities.collection import Collection
diff --git a/modules/s2e/compat/weboob_browser_filters_standard.py b/modules/s2e/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/s2e/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/s2e/pages.py b/modules/s2e/pages.py
index 50d71f45545bcd99d31bad1bad9155d8c1c3d9b1..5825debd7a1d8eb82d02a411825334163403e352 100644
--- a/modules/s2e/pages.py
+++ b/modules/s2e/pages.py
@@ -26,7 +26,7 @@
from weboob.browser.pages import HTMLPage, XMLPage, RawPage, LoggedPage, pagination, FormNotFound, PartialHTMLPage
from weboob.browser.elements import ItemElement, TableElement, SkipItem, method
-from weboob.browser.filters.standard import CleanText, Date, Regexp, Eval, CleanDecimal, Env, Field
+from .compat.weboob_browser_filters_standard import CleanText, Date, Regexp, Eval, CleanDecimal, Env, Field
from weboob.browser.filters.html import Attr, TableCell
from weboob.capabilities.bank import Account, Investment, Pocket, Transaction
from weboob.capabilities.base import NotAvailable
diff --git a/modules/sachsen/compat/__init__.py b/modules/sachsen/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/sachsen/compat/weboob_browser_filters_standard.py b/modules/sachsen/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/sachsen/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/sachsen/pages.py b/modules/sachsen/pages.py
index 50c96013bb7ee4c5ce7c4ba077f70df4f4fbba73..d0fe998fe06eb86eda40b1c40f95c62459f53f6b 100644
--- a/modules/sachsen/pages.py
+++ b/modules/sachsen/pages.py
@@ -20,7 +20,7 @@
from weboob.browser.pages import HTMLPage
from weboob.browser.elements import ListElement, ItemElement, method
-from weboob.browser.filters.standard import Env, CleanText, Regexp, Field, DateTime, Map
+from .compat.weboob_browser_filters_standard import Env, CleanText, Regexp, Field, DateTime, Map
from weboob.browser.filters.html import Attr
from weboob.capabilities.gauge import Gauge, GaugeMeasure, GaugeSensor
from weboob.capabilities.base import NotAvailable, NotLoaded
diff --git a/modules/seloger/compat/__init__.py b/modules/seloger/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/seloger/compat/weboob_browser_filters_standard.py b/modules/seloger/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/seloger/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/seloger/pages.py b/modules/seloger/pages.py
index 0941f87f67e81063e458a2522392655e2d9c420c..4069cdc3e470c20ce5be80470c6832034571fde7 100644
--- a/modules/seloger/pages.py
+++ b/modules/seloger/pages.py
@@ -22,7 +22,7 @@
from weboob.browser.elements import ItemElement, ListElement, DictElement, method
from weboob.browser.filters.json import Dict
from weboob.browser.filters.html import XPath
-from weboob.browser.filters.standard import (CleanText, CleanDecimal, Currency,
+from .compat.weboob_browser_filters_standard import (CleanText, CleanDecimal, Currency,
DateTime, Env, Format, Regexp)
from weboob.capabilities.base import NotAvailable, NotLoaded
from weboob.capabilities.housing import (Housing, HousingPhoto, City,
diff --git a/modules/senscritique/compat/__init__.py b/modules/senscritique/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/senscritique/compat/weboob_browser_filters_standard.py b/modules/senscritique/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/senscritique/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/senscritique/pages.py b/modules/senscritique/pages.py
index c729cbba71f8adce060bb37135ff4eb2c048241d..914d3b856982fc5728d61a2518c83e3b0ca2f5fc 100644
--- a/modules/senscritique/pages.py
+++ b/modules/senscritique/pages.py
@@ -24,7 +24,7 @@
from weboob.capabilities.base import empty
from weboob.browser.pages import HTMLPage, JsonPage
from weboob.browser.elements import ItemElement, ListElement, method
-from weboob.browser.filters.standard import Filter, CleanText, Regexp, Join, Format, BrowserURL, Env
+from .compat.weboob_browser_filters_standard import Filter, CleanText, Regexp, Join, Format, BrowserURL, Env
from weboob.browser.filters.html import Link
diff --git a/modules/societegenerale/browser.py b/modules/societegenerale/browser.py
index 67ffaf2afb4b4dc3f495d0f7c78a169661fe9ad1..e7bf32a0da9906bd189524dbf4d4124df8c6cd61 100644
--- a/modules/societegenerale/browser.py
+++ b/modules/societegenerale/browser.py
@@ -25,7 +25,7 @@
from weboob.browser import LoginBrowser, URL, need_login, StatesMixin
from weboob.exceptions import BrowserIncorrectPassword, ActionNeeded, BrowserUnavailable
-from weboob.capabilities.bank import Account, TransferBankError, AddRecipientStep
+from weboob.capabilities.bank import Account, TransferBankError, AddRecipientStep, TransactionType
from weboob.capabilities.base import find_object, NotAvailable
from weboob.browser.exceptions import BrowserHTTPNotFound, ClientError
from weboob.capabilities.profile import ProfileMissing
@@ -108,7 +108,9 @@ class SocieteGenerale(LoginBrowser, StatesMixin):
r'/com/icd-web/forms/kyc-index.html',
ActionNeededPage)
unavailable_service_page = URL(r'/com/service-indisponible.html',
- r'.*/Technical-pages/503-error-page/unavailable.html', UnavailableServicePage)
+ r'.*/Technical-pages/503-error-page/unavailable.html'
+ r'.*/Technical-pages/service-indisponible/service-indisponible.html',
+ UnavailableServicePage)
error = URL(r'https://static.societegenerale.fr/pri/erreur.html', ErrorPage)
login = URL(r'/sec/vk', LoginPage)
main_page = URL(r'https://particuliers.societegenerale.fr', MainPage)
@@ -251,6 +253,9 @@ def iter_history(self, account):
for card_tr in summary_card_tr._card_transactions:
card_tr.date = summary_card_tr.date
+ # We use the Raw pattern to set the rdate automatically, but that make
+ # the transaction type to "CARD", so we have to correct it in the browser.
+ card_tr.type = TransactionType.DEFERRED_CARD
yield card_tr
return
@@ -284,6 +289,9 @@ def iter_coming(self, account):
if transaction._card_coming:
for card_coming in transaction._card_coming:
card_coming.date = transaction.date
+ # We use the Raw pattern to set the rdate automatically, but that make
+ # the transaction type to "CARD", so we have to correct it in the browser.
+ card_coming.type = TransactionType.DEFERRED_CARD
yield card_coming
return
diff --git a/modules/societegenerale/pages/accounts_list.py b/modules/societegenerale/pages/accounts_list.py
index 0028a6fd5b1d6eaa025659bb588a1d6414cd1cfb..fa351a6d9be8a0c01cef7766bfb7a475e6f6f5cb 100644
--- a/modules/societegenerale/pages/accounts_list.py
+++ b/modules/societegenerale/pages/accounts_list.py
@@ -31,7 +31,7 @@
from weboob.tools.capabilities.bank.investments import is_isin_valid, create_french_liquidity
from weboob.browser.elements import DictElement, ItemElement, TableElement, method, ListElement
from weboob.browser.filters.json import Dict
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
CleanText, CleanDecimal, Regexp, Currency, Eval, Field, Format, Date, Env,
)
from weboob.browser.filters.html import Link, TableCell
@@ -149,9 +149,11 @@ def condition(self):
'PEA_PME_ESPECES': Account.TYPE_PEA,
'COMPTE_TITRE_PEA': Account.TYPE_PEA,
'COMPTE_TITRE_PEA_PME': Account.TYPE_PEA,
+ 'VIE_LMP': Account.TYPE_LIFE_INSURANCE,
'PROJECTIS': Account.TYPE_LIFE_INSURANCE,
'VIE_FEDER': Account.TYPE_LIFE_INSURANCE,
'PALISSANDRE': Account.TYPE_LIFE_INSURANCE,
+ 'PROJECTIS_PROFESS': Account.TYPE_LIFE_INSURANCE,
'SOGECAPI_PATRIMOINE': Account.TYPE_LIFE_INSURANCE,
'EBENE_CAPITALISATION': Account.TYPE_LIFE_INSURANCE,
'ASSURANCE_VIE_GENERALE': Account.TYPE_LIFE_INSURANCE,
@@ -428,8 +430,8 @@ class tr_item(TransactionItemElement):
def condition(self):
return Dict('statutOperation')(self) == 'COMPTABILISE'
- obj_raw = Dict('libOpe')
- obj_type = Transaction.TYPE_DEFERRED_CARD
+ obj_raw = Transaction.Raw(Dict('libOpe'))
+ obj_bdate = Eval(lambda t: datetime.date.fromtimestamp(int(t) / 1000), Dict('dateOpe'))
@pagination
@method
@@ -472,7 +474,7 @@ class tr_item(ItemElement):
klass = Transaction
obj_amount = CleanDecimal(Dict('montant/value'))
- obj_date = obj_vdate = Date(Dict('dateEcheance'))
+ obj_date = obj_vdate = obj_bdate = Date(Dict('dateEcheance'))
obj_raw = Transaction.Raw(Dict('libelleOrigine'))
@@ -544,15 +546,28 @@ def get_history_url(self):
if history_link:
return history_link.group(1)
- def iter_history(self):
- is_no_transaction_msg = any((
- self.doc.xpath(u'//div[contains(text(), "Aucune opération trouvée sur la période de restitution possible")]'),
- self.doc.xpath(u'//div[contains(text(), "Aucune opération n\'a été réalisée depuis le dernier relevé")]'),
- ))
- assert is_no_transaction_msg, 'There are transactions, retrieve them !'
+ @method
+ class iter_history(TableElement):
+ head_xpath = '//table[not(@id)]//td/div[contains(@class, "tableauHead")]'
+ item_xpath = '//table[@id]//tr'
+
+ def condition(self):
+ no_transaction_msg = any((
+ self.xpath('//div[contains(text(), "Aucune opération trouvée sur la période de restitution possible")]'),
+ self.xpath('//div[contains(text(), "Aucune opération n\'a été réalisée depuis le dernier relevé")]'),
+ ))
+ return not no_transaction_msg
+
+ col_label = 'Libellé'
+ col_amount = 'Montant'
+ col_date = 'Date'
+
+ class item(ItemElement):
+ klass = Transaction
- # waiting for account with history
- return []
+ obj_label = CleanText(TableCell('label'))
+ obj_amount = CleanDecimal(TableCell('amount'))
+ obj_date = Date(CleanText(TableCell('date')), dayfirst=True)
class LifeInsurance(LoggedPage, HTMLPage):
diff --git a/modules/societegenerale/pages/base.py b/modules/societegenerale/pages/base.py
index 2fcaa3aef13420a3728aaed17ea6b8978dfc86c7..14f422cc325b25a11fff29dcf1d61e631701324c 100644
--- a/modules/societegenerale/pages/base.py
+++ b/modules/societegenerale/pages/base.py
@@ -23,7 +23,7 @@
from weboob.capabilities.base import NotAvailable
from weboob.browser.pages import HTMLPage
from weboob.tools.capabilities.bank.transactions import FrenchTransaction
-from weboob.browser.filters.standard import CleanText
+from .compat.weboob_browser_filters_standard import CleanText
class BasePage(HTMLPage):
diff --git a/modules/societegenerale/pages/compat/__init__.py b/modules/societegenerale/pages/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/societegenerale/pages/compat/weboob_browser_filters_standard.py b/modules/societegenerale/pages/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/societegenerale/pages/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/societegenerale/pages/login.py b/modules/societegenerale/pages/login.py
index b137d295a5f34c389d6b220c03c49ea65d211f6b..526cd3a1c6bc8ee77a05e30e3b2b519ce3b493da 100644
--- a/modules/societegenerale/pages/login.py
+++ b/modules/societegenerale/pages/login.py
@@ -26,7 +26,7 @@
from weboob.exceptions import BrowserUnavailable, BrowserPasswordExpired, ActionNeeded
from weboob.browser.pages import HTMLPage, JsonPage
-from weboob.browser.filters.standard import CleanText
+from .compat.weboob_browser_filters_standard import CleanText
from weboob.browser.filters.json import Dict
from .base import BasePage
diff --git a/modules/societegenerale/pages/subscription.py b/modules/societegenerale/pages/subscription.py
index c8844dd3f76d453b937fc3d4706a0057609350f1..87d299e503d748546573f0f1e5080fac0e8bd335 100644
--- a/modules/societegenerale/pages/subscription.py
+++ b/modules/societegenerale/pages/subscription.py
@@ -24,7 +24,7 @@
from weboob.capabilities.bill import Document, Subscription
from weboob.browser.elements import TableElement, ItemElement, method
-from weboob.browser.filters.standard import CleanText, Regexp, Env, Date, Format, Field
+from .compat.weboob_browser_filters_standard import CleanText, Regexp, Env, Date, Format, Field
from weboob.browser.filters.html import Link, TableCell, Attr
from weboob.browser.pages import LoggedPage
diff --git a/modules/societegenerale/pages/transfer.py b/modules/societegenerale/pages/transfer.py
index c724c5a3993ec7dec7645b6aa541a2f1addc11a0..98fd59b745c94343040737254917485ce20ab139 100644
--- a/modules/societegenerale/pages/transfer.py
+++ b/modules/societegenerale/pages/transfer.py
@@ -27,7 +27,7 @@
)
from weboob.tools.capabilities.bank.iban import is_iban_valid
from weboob.capabilities.base import NotAvailable
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
CleanText, CleanDecimal, Env, Date, Field, Format,
)
from weboob.browser.filters.html import Link
diff --git a/modules/societegenerale/sgpe/compat/__init__.py b/modules/societegenerale/sgpe/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/societegenerale/sgpe/compat/weboob_browser_filters_standard.py b/modules/societegenerale/sgpe/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/societegenerale/sgpe/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/societegenerale/sgpe/json_pages.py b/modules/societegenerale/sgpe/json_pages.py
index ce9d67f7dfefe14fe653d1d7299b3d59c59721c2..0f273d6157c8db93ef4f8e4e5b6645d0ede9137a 100644
--- a/modules/societegenerale/sgpe/json_pages.py
+++ b/modules/societegenerale/sgpe/json_pages.py
@@ -22,7 +22,7 @@
from weboob.browser.pages import LoggedPage, JsonPage, pagination
from weboob.browser.elements import ItemElement, method, DictElement
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
CleanDecimal, CleanText, Date, Format, BrowserURL, Env,
Field,
)
diff --git a/modules/societegenerale/sgpe/pages.py b/modules/societegenerale/sgpe/pages.py
index df869fbc00be17fde1994f735ca9510060f4fc5e..86ef8d841dedc83669335fd4c3d178e3119536b1 100644
--- a/modules/societegenerale/sgpe/pages.py
+++ b/modules/societegenerale/sgpe/pages.py
@@ -25,7 +25,7 @@
from weboob.browser.pages import HTMLPage, LoggedPage
from weboob.browser.elements import ListElement, ItemElement, method
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
CleanText, CleanDecimal, Date,
Env, Regexp, Field, Format,
)
diff --git a/modules/societegenerale/sgpe/transfer_pages.py b/modules/societegenerale/sgpe/transfer_pages.py
index ac4052a2c110e41116c5167446bb856bc6b7d11b..321edfed6855255fea87e69533f268d122991c14 100644
--- a/modules/societegenerale/sgpe/transfer_pages.py
+++ b/modules/societegenerale/sgpe/transfer_pages.py
@@ -25,10 +25,10 @@
from weboob.browser.pages import LoggedPage, HTMLPage, JsonPage
from weboob.browser.elements import method, DictElement, ItemElement
-from weboob.browser.filters.standard import CleanText, CleanDecimal
+from .compat.weboob_browser_filters_standard import CleanText, CleanDecimal
from weboob.browser.filters.html import Attr
from weboob.browser.filters.json import Dict
-from weboob.browser.filters.standard import Date, Eval
+from .compat.weboob_browser_filters_standard import Date, Eval
from weboob.capabilities.bank import Recipient, Transfer
from .pages import LoginPage
diff --git a/modules/sogecartenet/compat/__init__.py b/modules/sogecartenet/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/sogecartenet/compat/weboob_browser_filters_standard.py b/modules/sogecartenet/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/sogecartenet/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/sogecartenet/pages.py b/modules/sogecartenet/pages.py
index 04f1bcd6dbb6ce47bf5e00d7839b3e4a70cfe61a..ec07000444a5b331e858b7b5102ae20efdb841dd 100644
--- a/modules/sogecartenet/pages.py
+++ b/modules/sogecartenet/pages.py
@@ -22,7 +22,7 @@
from weboob.browser.pages import HTMLPage, CsvPage, pagination
from weboob.exceptions import BrowserIncorrectPassword, BrowserPasswordExpired, NoAccountsException
from weboob.browser.elements import DictElement, ItemElement, method, TableElement
-from weboob.browser.filters.standard import CleanText, CleanDecimal, Date, Env
+from .compat.weboob_browser_filters_standard import CleanText, CleanDecimal, Date, Env
from weboob.browser.filters.html import TableCell
from weboob.browser.filters.json import Dict
from weboob.capabilities.bank import Account
diff --git a/modules/spirica/browser.py b/modules/spirica/browser.py
index 9df2fbee7ad1f22bf3694209708ce4bc0c9b928c..0fd87443c33516fdb197d7416c2c5e7931603c1d 100644
--- a/modules/spirica/browser.py
+++ b/modules/spirica/browser.py
@@ -21,12 +21,13 @@
from weboob.browser import LoginBrowser, URL, need_login
from weboob.exceptions import BrowserIncorrectPassword
+from weboob.browser.exceptions import ClientError
from .pages import LoginPage, AccountsPage, DetailsPage, MaintenancePage
class SpiricaBrowser(LoginBrowser):
- TIMEOUT = 60
+ TIMEOUT = 180
login = URL('/securite/login.xhtml', LoginPage)
accounts = URL('/sylvea/client/synthese.xhtml', AccountsPage)
@@ -38,6 +39,7 @@ def __init__(self, website, *args, **kwargs):
self.BASEURL = website
self.cache = {}
self.cache['invs'] = {}
+ self.transaction_page = None
def do_login(self):
self.login.go().login(self.username, self.password)
@@ -65,25 +67,72 @@ def iter_investment(self, account):
self.cache['invs'][account.id] = invs
return self.cache['invs'][account.id]
+ def check_if_logged_in(self, url):
+ if self.login.is_here():
+ self.logger.warning('We were logged out during iter_history, proceed to re-login.')
+ self.do_login()
+ self.location(url)
+ self.page.go_historytab()
+ # Store new transaction_page after login:
+ self.transaction_page = self.page
+
+ @need_login
+ def get_transactions_with_investments(self, max_count, url):
+ transactions = []
+ for index, transaction in enumerate(self.page.iter_history()):
+ self.check_if_logged_in(url)
+ if index < max_count:
+ try:
+ self.transaction_page.go_investments_form(transaction._index)
+ except ClientError as e:
+ self.logger.warning(e)
+ # Check if we are logged out
+ if self.login.is_here():
+ self.check_if_logged_in(url)
+ if self.details.is_here():
+ transaction.investments = []
+ for inv in self.page.iter_transactions_investments():
+ # Only keep investments that have at least a label and a valuation:
+ if inv.label and inv.valuation:
+ transaction.investments.append(inv)
+ transactions.append(transaction)
+ return transactions
+
@need_login
def iter_history(self, account):
self.location(account.url)
self.page.go_historytab()
- transaction_page = self.page
+ self.transaction_page = self.page
# Determining the number of transaction pages:
total_pages = int(self.page.count_transactions()) // 100
- # Scraping transactions for each page:
- for page_number in range(total_pages + 1):
- self.page.go_historyall(page_number)
+ # Scraping transactions with their investments for the 20 first transactions.
+ # Sometimes go_historyall fails so we go back to the accounts page and retry.
+ if self.transaction_page.go_historyall(page_number=0):
+ for tr in self.get_transactions_with_investments(20, account.url):
+ yield tr
+ else:
+ self.logger.warning('The first go_historyall() failed, go back to account details and retry.')
+ self.location(account.url)
+ self.page.go_historytab()
+ self.transaction_page = self.page
+ if self.transaction_page.go_historyall(page_number=0):
+ for tr in self.get_transactions_with_investments(20, account.url):
+ yield tr
+
+ # Scraping other transaction pages without their investments:
+ for page_number in range(1, total_pages + 1):
+ self.check_if_logged_in(account.url)
+ if not self.transaction_page.go_historyall(page_number):
+ self.logger.warning('The first go_historyall() failed, go back to account details and retry.')
+ self.location(account.url)
+ self.page.go_historytab()
+ self.transaction_page = self.page
+ if not self.transaction_page.go_historyall(page_number):
+ self.logger.warning('The go_historyall() failed twice, these transactions will be skipped.')
+ continue
for transaction in self.page.iter_history():
- transaction_page.go_investments_form(transaction._index)
- transaction.investments = []
- for inv in self.page.iter_transactions_investments():
- # Only keep investments that have at least a label and a valuation:
- if inv.label and inv.valuation:
- transaction.investments.append(inv)
yield transaction
def fill_from_list(self, invs, objects_list):
diff --git a/modules/spirica/compat/__init__.py b/modules/spirica/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/spirica/compat/weboob_browser_filters_standard.py b/modules/spirica/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/spirica/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/spirica/pages.py b/modules/spirica/pages.py
index 016665b88ebbba03cd1682431e06150924c51e2f..9f24afa36d3141ab32fbe8f3bfe1c74f8de63d56 100644
--- a/modules/spirica/pages.py
+++ b/modules/spirica/pages.py
@@ -23,7 +23,7 @@
from weboob.browser.pages import HTMLPage, LoggedPage
from weboob.browser.elements import ItemElement, ListElement, TableElement, method
-from weboob.browser.filters.standard import CleanText, Date, Regexp, CleanDecimal, \
+from .compat.weboob_browser_filters_standard import CleanText, Date, Regexp, CleanDecimal, \
Field, Async, AsyncLoad, Eval, Currency
from weboob.browser.filters.html import Attr, Link, TableCell
from weboob.capabilities.bank import Account, Investment, Transaction
@@ -227,8 +227,11 @@ def go_historytab(self):
def go_historyall(self, page_number):
form = self.get_form(xpath='//form[contains(@id, "ongletHistoOperations:ongletHistoriqueOperations")]')
- # The form value varies (for example j_idt913 or j_idt62081) so we need to scrape it dynamically:
- form_value = Attr('//div[@id="ongletHistoOperations:ongletHistoriqueOperations:newoperations"]/div[1]', 'id')(self.doc)
+ # The form value varies (for example j_idt913 or j_idt62081) so we need to scrape it dynamically.
+ # However, sometimes the form does not contain the 'id' attribute, in which case we must reload the page.
+ form_value = Attr('//div[@id="ongletHistoOperations:ongletHistoriqueOperations:newoperations"]/div[1]', 'id', default=None)(self.doc)
+ if not form_value:
+ return False
form['javax.faces.partial.ajax'] = 'true'
form['javax.faces.partial.execute'] = form_value
form['javax.faces.partial.render'] = form_value
@@ -239,6 +242,7 @@ def go_historyall(self, page_number):
form[form_value + '_rows'] = '100'
form[form_value + '_first'] = page_number * 100
form.submit()
+ return True
def go_investments_form(self, index):
form = self.get_form(xpath='//form[contains(@id, "ongletHistoOperations:ongletHistoriqueOperations")]')
diff --git a/modules/sprunge/browser.py b/modules/sprunge/browser.py
index 35a56697d9e6b861b37935d8d0b1a112543e2b09..3761648fe005e68763087d9635928ede0d5780cb 100644
--- a/modules/sprunge/browser.py
+++ b/modules/sprunge/browser.py
@@ -19,7 +19,7 @@
from weboob.browser.browsers import PagesBrowser
from weboob.browser.elements import ItemElement, method
-from weboob.browser.filters.standard import BrowserURL, Env, Field
+from .compat.weboob_browser_filters_standard import BrowserURL, Env, Field
from weboob.browser.pages import HTMLPage
from weboob.browser.url import URL
from weboob.capabilities.base import NotAvailable
diff --git a/modules/sprunge/compat/__init__.py b/modules/sprunge/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/sprunge/compat/weboob_browser_filters_standard.py b/modules/sprunge/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/sprunge/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/sueurdemetal/compat/__init__.py b/modules/sueurdemetal/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/sueurdemetal/compat/weboob_browser_filters_standard.py b/modules/sueurdemetal/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/sueurdemetal/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/sueurdemetal/pages.py b/modules/sueurdemetal/pages.py
index 2bc892ac10b6f4ea25f711bc161f4f923bb8cb0c..93550b9928edd88f7192578be09cf6c59df0979c 100644
--- a/modules/sueurdemetal/pages.py
+++ b/modules/sueurdemetal/pages.py
@@ -25,7 +25,7 @@
from weboob.browser.pages import JsonPage
from weboob.browser.elements import DictElement, ItemElement, method
from weboob.browser.filters.json import Dict
-from weboob.browser.filters.standard import Field
+from .compat.weboob_browser_filters_standard import Field
from weboob.capabilities.base import NotAvailable
from weboob.capabilities.calendar import BaseCalendarEvent, CATEGORIES, STATUS, TRANSP
diff --git a/modules/supertoinette/compat/__init__.py b/modules/supertoinette/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/supertoinette/compat/weboob_browser_filters_standard.py b/modules/supertoinette/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/supertoinette/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/supertoinette/pages.py b/modules/supertoinette/pages.py
index ad47fe9fb2084202718d9b70ddd02b1a4b311998..8ede6b3e952ee28c8815ecb88306d5057c10730f 100644
--- a/modules/supertoinette/pages.py
+++ b/modules/supertoinette/pages.py
@@ -22,7 +22,7 @@
from weboob.capabilities.image import BaseImage, Thumbnail
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.browser.pages import HTMLPage
-from weboob.browser.filters.standard import (
+from .compat.weboob_browser_filters_standard import (
CleanText, Env, Regexp, Type, Join, Eval,
)
from weboob.browser.filters.html import XPath
diff --git a/modules/suravenir/compat/__init__.py b/modules/suravenir/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/suravenir/compat/weboob_browser_filters_standard.py b/modules/suravenir/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/suravenir/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/suravenir/pages.py b/modules/suravenir/pages.py
index 4a993b0811e1ba364fa033a83c0ca7eb12a6159a..51477d5799e46ad4e4a85fb785e14cc09f535ce2 100644
--- a/modules/suravenir/pages.py
+++ b/modules/suravenir/pages.py
@@ -21,7 +21,7 @@
from weboob.browser.elements import ListElement, TableElement, ItemElement, method
from weboob.browser.filters.html import AbsoluteLink, TableCell, Link
-from weboob.browser.filters.standard import CleanText, CleanDecimal, Date
+from .compat.weboob_browser_filters_standard import CleanText, CleanDecimal, Date
from weboob.capabilities import NotAvailable
from weboob.capabilities.bank import Account, Investment, Transaction
from weboob.browser.pages import HTMLPage, LoggedPage, pagination
diff --git a/modules/t411/pages/compat/__init__.py b/modules/t411/pages/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/t411/pages/compat/weboob_browser_filters_standard.py b/modules/t411/pages/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/t411/pages/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/t411/pages/torrents.py b/modules/t411/pages/torrents.py
index cdd56b58475976a5f5dd13a2c2858766dcf2c12c..2ef4225c3fcc63931021b558610d11980762c286 100644
--- a/modules/t411/pages/torrents.py
+++ b/modules/t411/pages/torrents.py
@@ -23,7 +23,7 @@
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.browser.pages import HTMLPage, LoggedPage, RawPage
-from weboob.browser.filters.standard import Regexp, CleanText, Type, Format
+from .compat.weboob_browser_filters_standard import Regexp, CleanText, Type, Format
from weboob.browser.filters.html import CleanHTML
diff --git a/modules/themisbanque/compat/__init__.py b/modules/themisbanque/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/themisbanque/compat/weboob_browser_filters_standard.py b/modules/themisbanque/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/themisbanque/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/themisbanque/pages.py b/modules/themisbanque/pages.py
index 43d99acedcbb9639c79d675059a6cbf14441721c..0603ebd75049001359c92589cf9c1acb7225ceb0 100644
--- a/modules/themisbanque/pages.py
+++ b/modules/themisbanque/pages.py
@@ -27,7 +27,7 @@
from weboob.capabilities.bank import Account
from weboob.capabilities.base import NotAvailable
from weboob.capabilities.profile import Profile
-from weboob.browser.filters.standard import CleanText, CleanDecimal, Async, Regexp, Join, Field
+from .compat.weboob_browser_filters_standard import CleanText, CleanDecimal, Async, Regexp, Join, Field
from weboob.browser.filters.html import Link, TableCell, ColumnNotFound
from weboob.tools.capabilities.bank.transactions import FrenchTransaction
from weboob.tools.capabilities.bank.iban import is_iban_valid
diff --git a/modules/ticketscesu/compat/__init__.py b/modules/ticketscesu/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/ticketscesu/compat/weboob_browser_filters_standard.py b/modules/ticketscesu/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/ticketscesu/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/ticketscesu/pages.py b/modules/ticketscesu/pages.py
index 8c99899b8a9da2b14a1590c5de22e374b285eb2c..be0728fca351633e3eb2872b19d0d448bbcd8f67 100644
--- a/modules/ticketscesu/pages.py
+++ b/modules/ticketscesu/pages.py
@@ -21,7 +21,7 @@
from weboob.browser.elements import method, ItemElement, ListElement, SkipItem
-from weboob.browser.filters.standard import CleanDecimal, CleanText, Field, Format, Date
+from .compat.weboob_browser_filters_standard import CleanDecimal, CleanText, Field, Format, Date
from weboob.browser.filters.html import Attr
from weboob.browser.pages import HTMLPage, LoggedPage
from weboob.capabilities.bank import Account, Transaction
diff --git a/modules/tinder/browser.py b/modules/tinder/browser.py
index 960e1e03ab1efc4cc13e22a9b89d651b2efb02f1..1d0378840e9c59d197497bb70125804c873140dd 100644
--- a/modules/tinder/browser.py
+++ b/modules/tinder/browser.py
@@ -21,7 +21,7 @@
import re
from weboob.browser.browsers import DomainBrowser, APIBrowser
-from weboob.browser.filters.standard import CleanText
+from .compat.weboob_browser_filters_standard import CleanText
from weboob.browser.pages import HTMLPage
from weboob.browser.profiles import IPhone, Android
from weboob.exceptions import BrowserIncorrectPassword, ParseError
diff --git a/modules/tinder/compat/__init__.py b/modules/tinder/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/tinder/compat/weboob_browser_filters_standard.py b/modules/tinder/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/tinder/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/torrentz/pages/compat/__init__.py b/modules/torrentz/pages/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/torrentz/pages/compat/weboob_browser_filters_standard.py b/modules/torrentz/pages/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/torrentz/pages/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/torrentz/pages/torrents.py b/modules/torrentz/pages/torrents.py
index 53f380e09d99308446c7909c9763e98444dd2d92..a124a59987ae0df3f18ebe7f749be9a84f8af4af 100644
--- a/modules/torrentz/pages/torrents.py
+++ b/modules/torrentz/pages/torrents.py
@@ -7,7 +7,7 @@
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.capabilities.base import NotAvailable
from weboob.capabilities.torrent import Torrent, MagnetOnly
-from weboob.browser.filters.standard import CleanText, Regexp, Date, Type
+from .compat.weboob_browser_filters_standard import CleanText, Regexp, Date, Type
from weboob.tools.compat import quote_plus
diff --git a/modules/trainline/browser.py b/modules/trainline/browser.py
index 09a2a8cb0697e39fa49f96e9df1e94195157fd3e..0abdc8c679f5a08783636f6fe0e7d1b59b71f754 100644
--- a/modules/trainline/browser.py
+++ b/modules/trainline/browser.py
@@ -23,7 +23,7 @@
from weboob.browser.browsers import APIBrowser
from weboob.exceptions import BrowserIncorrectPassword
-from weboob.browser.filters.standard import CleanDecimal, Date
+from .compat.weboob_browser_filters_standard import CleanDecimal, Date
from weboob.browser.exceptions import ClientError
from weboob.capabilities.bill import DocumentTypes, Bill, Subscription
diff --git a/modules/trainline/compat/__init__.py b/modules/trainline/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/trainline/compat/weboob_browser_filters_standard.py b/modules/trainline/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/trainline/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/transilien/compat/__init__.py b/modules/transilien/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/transilien/compat/weboob_browser_filters_standard.py b/modules/transilien/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/transilien/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/transilien/pages.py b/modules/transilien/pages.py
index 2ded719b854167277719d7fa80126dc8e93f74ac..9ae8d9fc3f398adcc6749e3077f9b4afebe70b4a 100644
--- a/modules/transilien/pages.py
+++ b/modules/transilien/pages.py
@@ -24,7 +24,7 @@
from weboob.browser.elements import TableElement, ItemElement, DictElement, method
from weboob.capabilities.travel import Station, Departure, RoadStep
from weboob.capabilities import NotAvailable
-from weboob.browser.filters.standard import CleanText, Filter, Time, Env, Regexp, Duration,\
+from .compat.weboob_browser_filters_standard import CleanText, Filter, Time, Env, Regexp, Duration,\
Format, Join, DateTime
from weboob.browser.filters.json import Dict
from weboob.browser.filters.html import Link, TableCell
diff --git a/modules/tumblr/browser.py b/modules/tumblr/browser.py
index 3e04cd030115f4b8f4b25270cb180f37b96d677e..fffc693797e7281079e8d2b8a7fcbe35151561a6 100644
--- a/modules/tumblr/browser.py
+++ b/modules/tumblr/browser.py
@@ -24,7 +24,7 @@
from weboob.tools.json import json
from weboob.browser.browsers import APIBrowser
-from weboob.browser.filters.standard import CleanText
+from .compat.weboob_browser_filters_standard import CleanText
from weboob.capabilities.gallery import BaseImage
from weboob.capabilities.image import Thumbnail
diff --git a/modules/tumblr/compat/__init__.py b/modules/tumblr/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/tumblr/compat/weboob_browser_filters_standard.py b/modules/tumblr/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/tumblr/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/twitter/compat/__init__.py b/modules/twitter/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/twitter/compat/weboob_browser_filters_standard.py b/modules/twitter/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/twitter/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/twitter/pages.py b/modules/twitter/pages.py
index a27b07a0bd4bf03a0124333a8fd91108ce1bf3ca..fe5b190c205fddce163cb0493b8a7b1e81602e56 100644
--- a/modules/twitter/pages.py
+++ b/modules/twitter/pages.py
@@ -25,7 +25,7 @@
from weboob.tools.json import json
from weboob.browser.pages import HTMLPage, JsonPage, FormNotFound, pagination, LoggedPage
from weboob.browser.elements import ListElement, ItemElement, method
-from weboob.browser.filters.standard import CleanText, Format, Regexp, Env, DateTime, Filter
+from .compat.weboob_browser_filters_standard import CleanText, Format, Regexp, Env, DateTime, Filter
from weboob.browser.filters.html import Link, Attr
from weboob.capabilities.messages import Thread, Message
from weboob.capabilities.base import BaseObject
diff --git a/modules/vimeo/compat/__init__.py b/modules/vimeo/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/vimeo/compat/weboob_browser_filters_standard.py b/modules/vimeo/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/vimeo/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/vimeo/pages.py b/modules/vimeo/pages.py
index e1e395ac20c57d3d733e4fb3a441de5abc154de4..77fde4c4a7336d333973b43b0a12e3e04870177a 100644
--- a/modules/vimeo/pages.py
+++ b/modules/vimeo/pages.py
@@ -25,7 +25,7 @@
from weboob.exceptions import ParseError
from weboob.browser.elements import ItemElement, ListElement, method, DictElement
from weboob.browser.pages import HTMLPage, pagination, JsonPage, XMLPage
-from weboob.browser.filters.standard import Regexp, Env, CleanText, DateTime, Duration, Field, BrowserURL
+from .compat.weboob_browser_filters_standard import Regexp, Env, CleanText, DateTime, Duration, Field, BrowserURL
from weboob.browser.filters.html import Attr, Link
from weboob.browser.filters.json import Dict
diff --git a/modules/vine/compat/__init__.py b/modules/vine/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/vine/compat/weboob_browser_filters_standard.py b/modules/vine/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/vine/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/vine/pages.py b/modules/vine/pages.py
index 0196e0cfc87649c38e5714cc7feb10a1e917a22f..581c3d3cebb037c9558940e64f7ca0b89e522a77 100644
--- a/modules/vine/pages.py
+++ b/modules/vine/pages.py
@@ -21,7 +21,7 @@
from weboob.browser.elements import ItemElement, DictElement, method
from weboob.browser.pages import JsonPage
-from weboob.browser.filters.standard import Regexp
+from .compat.weboob_browser_filters_standard import Regexp
from weboob.browser.filters.json import Dict
diff --git a/modules/vlille/compat/__init__.py b/modules/vlille/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/vlille/compat/weboob_browser_filters_standard.py b/modules/vlille/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/vlille/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/vlille/pages.py b/modules/vlille/pages.py
index 35626659dad8f3e8eca5cc7e0558930fc97e2c6d..c575f697ac04ad22fd091c0ed7194b3aa14354a4 100644
--- a/modules/vlille/pages.py
+++ b/modules/vlille/pages.py
@@ -21,7 +21,7 @@
from weboob.browser.pages import HTMLPage
from weboob.browser.elements import ItemElement, TableElement, method
-from weboob.browser.filters.standard import CleanText, TableCell, DateTime, Field
+from .compat.weboob_browser_filters_standard import CleanText, TableCell, DateTime, Field
from weboob.capabilities.gauge import Gauge, GaugeMeasure, GaugeSensor
from weboob.capabilities.base import NotLoaded
diff --git a/modules/weather/compat/__init__.py b/modules/weather/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/weather/compat/weboob_browser_filters_standard.py b/modules/weather/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/weather/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/weather/pages.py b/modules/weather/pages.py
index e75db93e4c6ab8b3097a2661c412874b72662d9b..375a285dc5cc6bb012daa312cde84a6565575939 100644
--- a/modules/weather/pages.py
+++ b/modules/weather/pages.py
@@ -21,7 +21,7 @@
from weboob.browser.elements import ItemElement, method, DictElement
from weboob.browser.pages import JsonPage
-from weboob.browser.filters.standard import Format, DateTime, Env
+from .compat.weboob_browser_filters_standard import Format, DateTime, Env
from weboob.browser.filters.json import Dict
from weboob.capabilities.weather import Forecast, Current, City, Temperature
diff --git a/modules/wordreference/compat/__init__.py b/modules/wordreference/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/wordreference/compat/weboob_browser_filters_standard.py b/modules/wordreference/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/wordreference/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/wordreference/pages.py b/modules/wordreference/pages.py
index c32df5a6e147f71704f289aa63727521d4c15e52..b669d3417ccb884087ccafa7831e762ad0e53778 100644
--- a/modules/wordreference/pages.py
+++ b/modules/wordreference/pages.py
@@ -20,7 +20,7 @@
from weboob.browser.pages import HTMLPage
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.capabilities.translate import Translation
-from weboob.browser.filters.standard import CleanText, Regexp, Env
+from .compat.weboob_browser_filters_standard import CleanText, Regexp, Env
class TranslatePage(HTMLPage):
diff --git a/modules/xhamster/compat/__init__.py b/modules/xhamster/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/xhamster/compat/weboob_browser_filters_standard.py b/modules/xhamster/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/xhamster/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/xhamster/pages.py b/modules/xhamster/pages.py
index 11aefc19e0d7a67fec06b181ddf3f60d44a2a38c..fc9d07dd037151ec8d9b4b5e75dcaa666e8e5c73 100644
--- a/modules/xhamster/pages.py
+++ b/modules/xhamster/pages.py
@@ -20,7 +20,7 @@
from __future__ import unicode_literals
from weboob.browser.elements import ItemElement, ListElement, method
-from weboob.browser.filters.standard import CleanText, Duration, Regexp, Env, Field, RawText, Eval, Base
+from .compat.weboob_browser_filters_standard import CleanText, Duration, Regexp, Env, Field, RawText, Eval, Base
from weboob.browser.filters.html import AbsoluteLink, Attr
from weboob.browser.filters.json import Dict
from weboob.browser.pages import HTMLPage, pagination
diff --git a/modules/yahoo/compat/__init__.py b/modules/yahoo/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/yahoo/compat/weboob_browser_filters_standard.py b/modules/yahoo/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/yahoo/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/yahoo/pages.py b/modules/yahoo/pages.py
index 45b3a0e4d22d03dcbef2ea023bc68dd3e15f51b5..3189d3c9f6d5e05a45166353e03e96e3f436a4dd 100644
--- a/modules/yahoo/pages.py
+++ b/modules/yahoo/pages.py
@@ -22,7 +22,7 @@
from weboob.browser.elements import ItemElement, DictElement, method
from weboob.capabilities.weather import Forecast, Current, City, Temperature
from weboob.browser.filters.json import Dict
-from weboob.browser.filters.standard import CleanText, CleanDecimal, Format, Date, Env
+from .compat.weboob_browser_filters_standard import CleanText, CleanDecimal, Format, Date, Env
class YahooPage(JsonPage):
diff --git a/modules/yggtorrent/pages/compat/__init__.py b/modules/yggtorrent/pages/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/yggtorrent/pages/compat/weboob_browser_filters_standard.py b/modules/yggtorrent/pages/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/yggtorrent/pages/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/yggtorrent/pages/torrents.py b/modules/yggtorrent/pages/torrents.py
index a60e0bbdc488d511bc1667feb31be153f87b895b..84df0e7cb17f79d6c7ab9c647bebfda724f0bdca 100644
--- a/modules/yggtorrent/pages/torrents.py
+++ b/modules/yggtorrent/pages/torrents.py
@@ -24,7 +24,7 @@
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.browser.pages import HTMLPage, LoggedPage, RawPage, pagination
-from weboob.browser.filters.standard import Regexp, CleanText, CleanDecimal, Format
+from .compat.weboob_browser_filters_standard import Regexp, CleanText, CleanDecimal, Format
from weboob.browser.filters.html import CleanHTML, AbsoluteLink
diff --git a/modules/yomoni/browser.py b/modules/yomoni/browser.py
index 4ce98051191c2a5614487e691240d0450136fba0..41243e4a88c6ddea7ef233463a4db77974eff75b 100644
--- a/modules/yomoni/browser.py
+++ b/modules/yomoni/browser.py
@@ -28,7 +28,7 @@
from weboob.browser.browsers import APIBrowser
from weboob.browser.exceptions import ClientError
-from weboob.browser.filters.standard import CleanDecimal, Date
+from .compat.weboob_browser_filters_standard import CleanDecimal, Date
from weboob.exceptions import BrowserIncorrectPassword, ActionNeeded
from weboob.capabilities.bank import Account, Investment, Transaction
from weboob.capabilities.base import NotAvailable
diff --git a/modules/yomoni/compat/__init__.py b/modules/yomoni/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/yomoni/compat/weboob_browser_filters_standard.py b/modules/yomoni/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/yomoni/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/youjizz/pages/compat/__init__.py b/modules/youjizz/pages/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/youjizz/pages/compat/weboob_browser_filters_standard.py b/modules/youjizz/pages/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/youjizz/pages/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/youjizz/pages/index.py b/modules/youjizz/pages/index.py
index 0a38977aec9abdf5ffb20076ad2a53b9fde7bc71..169e0f481058bd490697b3108d6a00999007538c 100644
--- a/modules/youjizz/pages/index.py
+++ b/modules/youjizz/pages/index.py
@@ -20,7 +20,7 @@
from weboob.browser.pages import HTMLPage, pagination
from weboob.browser.elements import ListElement, ItemElement, method
-from weboob.browser.filters.standard import CleanText, Duration, Regexp
+from .compat.weboob_browser_filters_standard import CleanText, Duration, Regexp
from weboob.browser.filters.html import Link, CSS
from weboob.capabilities.base import NotAvailable
from weboob.capabilities.image import Thumbnail
diff --git a/modules/youjizz/pages/video.py b/modules/youjizz/pages/video.py
index 3555a6df62e9f49a977379277d18272d02b02cc4..d432d6b46fe58da4e1d40c9fb72c5506331d99f1 100644
--- a/modules/youjizz/pages/video.py
+++ b/modules/youjizz/pages/video.py
@@ -22,7 +22,7 @@
from weboob.browser.pages import HTMLPage
from weboob.browser.elements import ItemElement, method
-from weboob.browser.filters.standard import CleanText, Env
+from .compat.weboob_browser_filters_standard import CleanText, Env
from weboob.capabilities.video import BaseVideo
from weboob.tools.misc import to_unicode
diff --git a/modules/youporn/pages/compat/__init__.py b/modules/youporn/pages/compat/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/modules/youporn/pages/compat/weboob_browser_filters_standard.py b/modules/youporn/pages/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/youporn/pages/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/youporn/pages/index.py b/modules/youporn/pages/index.py
index 1672ccd5d9993983475b8afd30a308b190278433..a7eb5f7614ef589a6bb38954a14c87ea3db0334c 100644
--- a/modules/youporn/pages/index.py
+++ b/modules/youporn/pages/index.py
@@ -22,7 +22,7 @@
from weboob.browser.pages import HTMLPage
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.browser.filters.html import Attr
-from weboob.browser.filters.standard import CleanText, Duration, Regexp, Type
+from .compat.weboob_browser_filters_standard import CleanText, Duration, Regexp, Type
from weboob.capabilities.base import NotAvailable
from weboob.capabilities.image import Thumbnail
diff --git a/modules/youporn/pages/video.py b/modules/youporn/pages/video.py
index 9654e42ceff38e233bd2265751b0192b9a89474a..42502218626404846c73dc421e91c92081fff9a8 100644
--- a/modules/youporn/pages/video.py
+++ b/modules/youporn/pages/video.py
@@ -22,7 +22,7 @@
from weboob.browser.pages import HTMLPage
from weboob.browser.elements import ItemElement, method
-from weboob.browser.filters.standard import CleanText, Env, Regexp, Type
+from .compat.weboob_browser_filters_standard import CleanText, Env, Regexp, Type
from weboob.capabilities.base import NotAvailable
from ..video import YoupornVideo
diff --git a/modules/zerobin/compat/weboob_browser_filters_standard.py b/modules/zerobin/compat/weboob_browser_filters_standard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f382d162f07989986480f1ac6e229c930e1b4879
--- /dev/null
+++ b/modules/zerobin/compat/weboob_browser_filters_standard.py
@@ -0,0 +1,49 @@
+
+import weboob.browser.filters.standard as OLD
+
+# can't import *, __all__ is incomplete...
+for attr in dir(OLD):
+ globals()[attr] = getattr(OLD, attr)
+
+
+try:
+ __all__ = OLD.__all__
+except AttributeError:
+ pass
+
+
+class Coalesce(MultiFilter):
+ """
+ Returns the first value that is not falsy,
+ or default if all values are falsy.
+ """
+ @debug()
+ def filter(self, values):
+ for value in values:
+ if value:
+ return value
+ return self.default_or_raise(FilterError('All falsy and no default.'))
+
+
+class MapIn(Filter):
+ """
+ Map the pattern of a selected value to another value using a dict.
+ """
+
+ def __init__(self, selector, map_dict, default=_NO_DEFAULT):
+ """
+ :param selector: key from `map_dict` to use
+ """
+ super(MapIn, self).__init__(selector, default=default)
+ self.map_dict = map_dict
+
+ @debug()
+ def filter(self, txt):
+ """
+ :raises: :class:`ItemNotFound` if key pattern does not exist in dict
+ """
+ for key in self.map_dict:
+ if key in txt:
+ return self.map_dict[key]
+
+ return self.default_or_raise(ItemNotFound('Unable to handle %r on %r' % (txt, self.map_dict)))
diff --git a/modules/zerobin/crypto.py b/modules/zerobin/crypto.py
index 9292af46b210882323e7e058b05b7c823086dec9..5cb45b4306e8feeb4025f8795fc1f01b47bc2bc2 100644
--- a/modules/zerobin/crypto.py
+++ b/modules/zerobin/crypto.py
@@ -22,10 +22,16 @@
import math
from os import urandom
-from Cryptodome.Cipher import AES
-from Cryptodome.Protocol.KDF import PBKDF2
-from Cryptodome.Hash import SHA256
-from Cryptodome.Hash import HMAC
+try:
+ from Cryptodome.Cipher import AES
+ from Cryptodome.Protocol.KDF import PBKDF2
+ from Cryptodome.Hash import SHA256
+ from Cryptodome.Hash import HMAC
+except ImportError:
+ from Crypto.Cipher import AES
+ from Crypto.Protocol.KDF import PBKDF2
+ from Crypto.Hash import SHA256
+ from Crypto.Hash import HMAC
def log2(n):
diff --git a/modules/zerobin/pages.py b/modules/zerobin/pages.py
index b6b53116be58cb9382309abb33e54b808646cfdf..6bb6ca3ef501246778425bda15a5948163c54b2e 100644
--- a/modules/zerobin/pages.py
+++ b/modules/zerobin/pages.py
@@ -22,7 +22,7 @@
from zlib import decompress, MAX_WBITS, compressobj, DEFLATED
from weboob.browser.pages import HTMLPage
-from weboob.browser.filters.standard import CleanText
+from .compat.weboob_browser_filters_standard import CleanText
from weboob.tools.json import json
from weboob.tools.compat import urljoin
|