def on_loaded(self): self.accounts = OrderedDict() self.parse_table('comptes', Account.TYPE_CHECKING) self.parse_table('comptesEpargne', Account.TYPE_SAVINGS) self.parse_table('comptesTitres', Account.TYPE_MARKET) self.parse_table('comptesVie', Account.TYPE_DEPOSIT) self.parse_table('comptesRetraireEuros')
def get_loan_list(self): accounts = OrderedDict() # New website for table in self.document.xpath('//div[@class="panel"]'): title = table.getprevious() if title is None: continue account_type = self.ACCOUNT_TYPES.get(self.parser.tocleanstring(title), Account.TYPE_UNKNOWN) for tr in table.xpath('./table/tbody/tr[contains(@id,"MM_SYNTHESE_CREDITS") and contains(@id,"IdTrGlobal")]'): tds = tr.findall('td') if len(tds) == 0 : continue for i in tds[0].xpath('.//a/strong'): label = i.text.strip() break balance = Decimal(FrenchTransaction.clean_amount(self.parser.tocleanstring(tds[-1]))) account = Account() account.id = label.split(' ')[-1] account.label = unicode(label) account.type = account_type account.balance = -abs(balance) account.currency = account.get_currency(self.parser.tocleanstring(tds[-1])) account._card_links = [] accounts[account.id] = account return accounts.itervalues()
def format(self, obj, selected_fields=None): """ Format an object to be human-readable. An object has fields which can be selected. If the object provides an iter_fields() method, the formatter will call it. It can be used to specify the fields order. @param obj [object] object to format @param selected_fields [tuple] fields to display. If None, all fields are selected @return a string of the formatted object """ assert isinstance(obj, (dict, CapBaseObject, tuple)) if isinstance(obj, dict): item = obj elif isinstance(obj, tuple): item = OrderedDict([(k, v) for k, v in obj]) else: item = self.to_dict(obj, selected_fields) if item is None: return None if self.MANDATORY_FIELDS: missing_fields = set(self.MANDATORY_FIELDS) - set(item.keys()) if missing_fields: raise MandatoryFieldsNotFound(missing_fields) formatted = self.format_dict(item=item) if formatted: self.after_format(formatted) return formatted
def on_loaded(self): self.accounts = OrderedDict() self.parse_table('comptes') self.parse_table('comptesEpargne') self.parse_table('comptesTitres') self.parse_table('comptesVie') self.parse_table('comptesRetraireEuros')
def get_loan_list(self): accounts = OrderedDict() # New website for table in self.document.xpath('//div[@class="panel"]'): title = table.getprevious() if title is None: continue account_type = self.ACCOUNT_TYPES.get( self.parser.tocleanstring(title), Account.TYPE_UNKNOWN) for tr in table.xpath( './table/tbody/tr[contains(@id,"MM_SYNTHESE_CREDITS") and contains(@id,"IdTrGlobal")]' ): tds = tr.findall('td') if len(tds) == 0: continue for i in tds[0].xpath('.//a/strong'): label = i.text.strip() break balance = Decimal( FrenchTransaction.clean_amount( self.parser.tocleanstring(tds[-1]))) account = Account() account.id = label.split(' ')[-1] account.label = unicode(label) account.type = account_type account.balance = -abs(balance) account.currency = account.get_currency( self.parser.tocleanstring(tds[-1])) account._card_links = [] accounts[account.id] = account return accounts.itervalues()
def get_list(self): accounts = OrderedDict() for tr in self.document.getiterator('tr'): first_td = tr.getchildren()[0] if (first_td.attrib.get('class', '') == 'i g' or first_td.attrib.get('class', '') == 'p g') \ and first_td.find('a') is not None: a = first_td.find('a') link = a.get('href', '') if link.startswith('POR_SyntheseLst'): continue url = urlparse(link) p = parse_qs(url.query) if not 'rib' in p: continue for i in (2,1): balance = FrenchTransaction.clean_amount(tr.getchildren()[i].text) currency = Account.get_currency(tr.getchildren()[i].text) if len(balance) > 0: break balance = Decimal(balance) id = p['rib'][0] if id in accounts: account = accounts[id] if not account.coming: account.coming = Decimal('0.0') account.coming += balance account._card_links.append(link) continue account = Account() account.id = id account.label = unicode(a.text).strip().lstrip(' 0123456789').title() account._link_id = link account._card_links = [] # Find accounting amount page = self.browser.get_document(self.browser.openurl(link)) coming = self.find_amount(page, u"Opérations à venir") accounting = self.find_amount(page, u"Solde comptable") if accounting is not None and accounting + (coming or Decimal('0')) != balance: self.logger.warning('%s + %s != %s' % (accounting, coming, balance)) if accounting is not None: balance = accounting if coming is not None: account.coming = coming account.balance = balance account.currency = currency accounts[account.id] = account return accounts.itervalues()
def on_loaded(self): if self.document.xpath(u'//h2[text()="%s"]' % u'ERREUR'): raise BrowserUnavailable() self.accounts = OrderedDict() self.parse_table('comptes', Account.TYPE_CHECKING) self.parse_table('comptesEpargne', Account.TYPE_SAVINGS) self.parse_table('comptesTitres', Account.TYPE_MARKET) self.parse_table('comptesVie', Account.TYPE_DEPOSIT) self.parse_table('comptesRetraireEuros')
def get_list(self): accounts = OrderedDict() # Old website for table in self.document.xpath('//table[@cellpadding="1"]'): account_type = Account.TYPE_UNKNOWN for tr in table.xpath('./tr'): tds = tr.findall('td') if tr.attrib.get('class', '') == 'DataGridHeader': account_type = self.ACCOUNT_TYPES.get(tds[1].text.strip()) or\ self.ACCOUNT_TYPES.get(self.parser.tocleanstring(tds[2])) or\ self.ACCOUNT_TYPES.get(self.parser.tocleanstring(tds[3]), Account.TYPE_UNKNOWN) else: # On the same row, there are many accounts (for example a # check accound and a card one). if len(tds) > 4: for i, a in enumerate(tds[2].xpath('./a')): label = self.parser.tocleanstring(a) balance = self.parser.tocleanstring( tds[-2].xpath('./a')[i]) self._add_account(accounts, a, label, account_type, balance) # Only 4 tds on banque de la reunion website. elif len(tds) == 4: for i, a in enumerate(tds[1].xpath('./a')): label = self.parser.tocleanstring(a) balance = self.parser.tocleanstring( tds[-1].xpath('./a')[i]) self._add_account(accounts, a, label, account_type, balance) if len(accounts) == 0: # New website for table in self.document.xpath('//div[@class="panel"]'): title = table.getprevious() if title is None: continue account_type = self.ACCOUNT_TYPES.get( self.parser.tocleanstring(title), Account.TYPE_UNKNOWN) for tr in table.xpath('.//tr'): tds = tr.findall('td') for i in xrange(len(tds)): a = tds[i].find('a') if a is not None: break if a is None: continue label = self.parser.tocleanstring(tds[0]) balance = self.parser.tocleanstring(tds[-1]) self._add_account(accounts, a, label, account_type, balance) return accounts.itervalues()
def get_list(self): accounts = OrderedDict() # Old website for table in self.document.xpath('//table[@cellpadding="1"]'): account_type = Account.TYPE_UNKNOWN for tr in table.xpath('./tr'): tds = tr.findall('td') if tr.attrib.get('class', '') == 'DataGridHeader': account_type = self.ACCOUNT_TYPES.get(tds[1].text.strip(), Account.TYPE_UNKNOWN) else: label = '' i = 1 a = None while label == '' and i < len(tds): a = tds[i].find('a') if a is None: continue label = self.parser.tocleanstring(a) i += 1 balance = '' i = -1 while balance == '' and i > -len(tds): try: balance = self.parser.tocleanstring(tds[i].xpath('./a')[0]) except KeyError: balance = u''.join([txt.strip() for txt in tds[i].itertext()]) i -= 1 self._add_account(accounts, a, label, account_type, balance) if len(accounts) == 0: # New website for table in self.document.xpath('//div[@class="panel"]'): title = table.getprevious() if title is None: continue account_type = self.ACCOUNT_TYPES.get(self.parser.tocleanstring(title), Account.TYPE_UNKNOWN) for tr in table.xpath('.//tr'): tds = tr.findall('td') for i in xrange(len(tds)): a = tds[i].find('a') if a is not None: break if a is None: continue label = self.parser.tocleanstring(tds[0]) balance = self.parser.tocleanstring(tds[-1]) self._add_account(accounts, a, label, account_type, balance) return accounts.itervalues()
def __init__(self, name, backend): self.my_id = backend.browser.get_userid() self.name = 'wiki/weboob/%s' % name self.description = None self.date = None self.begin = None self.end = None self.location = None self.winner = None self.backend = backend self.members = OrderedDict() self.load()
def on_loaded(self): for script in self.document.xpath('//script'): text = script.text if text is None: continue m = re.search("window.location.replace\('([^']+)'\);", text) if m: self.browser.location(m.group(1)) try: self.browser.select_form(name='banque') except FormNotFoundError: pass else: self.browser.set_all_readonly(False) accounts = OrderedDict() for tr in self.document.getroot().cssselect( 'table.compteTable > tbody > tr'): if len(tr.findall('td')) == 0: continue attr = tr.xpath('.//a')[0].attrib.get('onclick', '') m = re.search( "value = '(\w+)';(checkAndSubmit\('\w+','(\w+)','(\w+)'\))?", attr) if m: typeCompte = m.group(1) tagName = m.group(3) if tagName is not None: value = self.document.xpath( '//input[@name="%s"]' % m.group(3))[int( m.group(4))].attrib['value'] else: value = typeCompte accounts[value] = (typeCompte, tagName) try: typeCompte, tagName = accounts[self.browser.accnum] value = self.browser.accnum except KeyError: accnums = ', '.join(accounts.keys()) if self.browser.accnum != '00000000000': self.logger.warning( u'Unable to find account "%s". Available ones: %s' % (self.browser.accnum, accnums)) elif len(accounts) > 1: self.logger.warning( 'There are several accounts, please use "accnum" backend parameter to force the one to use (%s)' % accnums) value, (typeCompte, tagName) = accounts.popitem(last=False) self.browser['typeCompte'] = typeCompte if tagName is not None: self.browser[tagName] = [value] self.browser.submit()
def get_profile(self): title = self.parser.select(self.document.getroot(), 'title', 1) if title.text == 'OkCupid: Account Not Found': return None profile = {} profile['id'] = unicode(title.text[len('OkCupid: '):]) profile['data'] = OrderedDict() profile_p = self.parser.select(self.document.getroot(), "//div[@id='page_content']//p", method='xpath') profile['data']['infos'] = ProfileNode('infos', u'Informations', OrderedDict(), flags=ProfileNode.SECTION) info = { 'age' : unicode(profile_p[1].text.split(' / ')[0]), 'sex' : unicode(profile_p[1].text.split(' / ')[1]), 'orientation' : unicode(profile_p[1].text.split(' / ')[2]), 'relationship' : unicode(profile_p[1].text.split(' / ')[3]), } for key, val in info.iteritems(): profile['data']['infos'].value[key] = ProfileNode(key, key.capitalize(), val) div_essays = self.parser.select(self.document.getroot(), "//div[@class='essay']", method='xpath') h3_essays = self.parser.select(self.document.getroot(), "//div[@id='page_content']//h3", method='xpath') essays = OrderedDict(zip(h3_essays, div_essays)) profile['data']['look_for'] = ProfileNode('look_for', u'Look for', OrderedDict(), flags=ProfileNode.SECTION) profile['data']['details'] = ProfileNode('details', u'Details', OrderedDict(), flags=ProfileNode.SECTION) profile['data']['essays'] = ProfileNode('essays', u'Essays', OrderedDict(), flags=ProfileNode.SECTION) for label, val in essays.iteritems(): label = unicode(label.text).strip() txt = self.parser.tocleanstring(val) if 'looking for' in label: for i, li in enumerate(val.xpath('.//li')): profile['data']['look_for'].value['look_for_%s' % i] = ProfileNode('look_for_%s' % i, '', li.text.strip()) elif 'summary' in label and 'summary' not in profile: profile['summary'] = txt else: key = label.replace(' ', '_') profile['data']['essays'].value[key] = ProfileNode(key, label, txt) details_div = self.parser.select(self.document.getroot(), "//div[@id='details']//li", method='xpath') for elem in details_div: label = unicode(elem.getchildren()[0].text.strip()) val = unicode(elem.getchildren()[1].text.strip()) key = label.lower().replace(' ', '_') profile['data']['details'].value[key] = ProfileNode(key, label, val) return profile
def parse_profile(self, profile, consts): if profile['online']: self.status = Contact.STATUS_ONLINE self.status_msg = u'online' self.status_msg = u'since %s' % profile['last_cnx'] else: self.status = Contact.STATUS_OFFLINE self.status_msg = u'last connection %s' % profile['last_cnx'] self.summary = unicode(unescape(profile.get('announce', '').strip())) if len(profile.get('shopping_list', '')) > 0: self.summary += u'\n\nLooking for:\n%s' % unescape( profile['shopping_list'].strip()) for photo in profile['pics']: self.set_photo(photo.split('/')[-1], url=photo + '/full', thumbnail_url=photo + '/small', hidden=False) self.profile = OrderedDict() if 'sex' in profile: for section, d in self.TABLE.iteritems(): flags = ProfileNode.SECTION if section.startswith('_'): flags |= ProfileNode.HEAD if (section.startswith('+') and int(profile['sex']) != 1) or \ (section.startswith('-') and int(profile['sex']) != 0): continue section = section.lstrip('_+-') s = ProfileNode(section, section.capitalize(), OrderedDict(), flags=flags) for key, builder in d.iteritems(): try: value = builder.get_value(profile, consts[int(profile['sex'])]) except KeyError: pass else: s.value[key] = ProfileNode( key, key.capitalize().replace('_', ' '), value) self.profile[section] = s self._aum_profile = profile
def get_list(self): accounts = OrderedDict() # Old website for table in self.document.xpath('//table[@cellpadding="1"]'): account_type = Account.TYPE_UNKNOWN for tr in table.xpath('./tr'): tds = tr.findall('td') if tr.attrib.get('class', '') == 'DataGridHeader': account_type = self.ACCOUNT_TYPES.get(tds[1].text.strip()) or\ self.ACCOUNT_TYPES.get(self.parser.tocleanstring(tds[2])) or\ self.ACCOUNT_TYPES.get(self.parser.tocleanstring(tds[3]), Account.TYPE_UNKNOWN) else: # On the same row, there are many accounts (for example a # check accound and a card one). if len(tds) > 4: for i, a in enumerate(tds[2].xpath('./a')): label = self.parser.tocleanstring(a) balance = self.parser.tocleanstring(tds[-2].xpath('./a')[i]) self._add_account(accounts, a, label, account_type, balance) # Only 4 tds on banque de la reunion website. elif len(tds) == 4: for i, a in enumerate(tds[1].xpath('./a')): label = self.parser.tocleanstring(a) balance = self.parser.tocleanstring(tds[-1].xpath('./a')[i]) self._add_account(accounts, a, label, account_type, balance) if len(accounts) == 0: # New website for table in self.document.xpath('//div[@class="panel"]'): title = table.getprevious() if title is None: continue account_type = self.ACCOUNT_TYPES.get(self.parser.tocleanstring(title), Account.TYPE_UNKNOWN) for tr in table.xpath('.//tr'): tds = tr.findall('td') for i in xrange(len(tds)): a = tds[i].find('a') if a is not None: break if a is None: continue label = self.parser.tocleanstring(tds[0]) balance = self.parser.tocleanstring(tds[-1]) self._add_account(accounts, a, label, account_type, balance) return accounts.itervalues()
def to_dict(self, obj): if not isinstance(obj, CapBaseObject): try: return OrderedDict(obj) except ValueError: raise TypeError('Please give a CapBaseObject or a dict') def iter_decorate(d): for key, value in d: if key == 'id' and obj.backend is not None: value = obj.fullid yield key, value fields_iterator = obj.iter_fields() return OrderedDict(iter_decorate(fields_iterator))
def load(self, default={}): self.values = OrderedDict(default) if os.path.exists(self.path): logging.debug(u'Loading application configuration file: %s.' % self.path) self.config.read(self.path) for section in self.config.sections(): args = section.split(':') if args[0] == self.ROOTSECT: args.pop(0) for key, value in self.config.items(section): self.set(*(args + [key, value])) # retro compatibility if len(self.config.sections()) == 0: first = True for key, value in self.config.items(DEFAULTSECT): if first: logging.warning( 'The configuration file "%s" uses an old-style' % self.path) logging.warning('Please rename the %s section to %s' % (DEFAULTSECT, self.ROOTSECT)) first = False self.set(key, value) logging.debug(u'Application configuration file loaded: %s.' % self.path) else: self.save() logging.debug( u'Application configuration file created with default values: %s. ' 'Please customize it.' % self.path) return self.values
class NewspaperPresseuropBrowser(BaseBrowser): "NewspaperPresseuropBrowser class" PAGES = OrderedDict(( ("http://www.presseurop.eu/.*/news-brief/.*", DailySinglePage), ("http://www.presseurop.eu/.*/today/.*", DailyTitlesPage), ("http://www.presseurop.eu/.*/cartoon/.*", CartoonPage), ("http://www.presseurop.eu/.*", PresseuropPage), )) def is_logged(self): return False def login(self): pass def fillobj(self, obj, fields): pass def get_content(self, _id): "return page article content" self.location(_id) return self.page.get_article(_id) def get_daily_date(self, _id): self.location(_id) return self.page.get_daily_date() def get_daily_infos(self, _id): url = "http://www.presseurop.eu/fr/today/" + _id self.location(url) title = self.page.get_title() article_date = date(*[int(x) for x in _id.split('-')]) article_time = time(0, 0, 0) article_datetime = datetime.combine(article_date, article_time) return url, title, article_datetime
class YahooModule(Module, CapWeather): NAME = 'yahoo' MAINTAINER = u'Romain Bignon' EMAIL = '*****@*****.**' VERSION = '1.2' DESCRIPTION = 'Yahoo! Weather.' LICENSE = 'AGPLv3+' BROWSER = YahooBrowser units_choice = OrderedDict([('c', 'International System of Units'), ('f', 'U.S. System of Units')]) CONFIG = BackendConfig(Value('units', label=u'System of Units', choices=units_choice)) def create_default_browser(self): return self.create_browser(unit=self.config['units'].get()) def iter_city_search(self, pattern): return self.browser.iter_city_search(pattern) def get_current(self, city_id): return self.browser.get_current(city_id) def iter_forecast(self, city_id): return self.browser.iter_forecast(city_id)
def on_loaded(self): self.accounts = OrderedDict() self.parse_table("comptes") self.parse_table("comptesEpargne") self.parse_table("comptesTitres") self.parse_table("comptesVie") self.parse_table("comptesRetraireEuros")
class RazibusModule(Module, CapCalendarEvent): NAME = 'razibus' DESCRIPTION = u'site annonçant les évènements attendus par les punks a chiens' MAINTAINER = u'Bezleputh' EMAIL = '*****@*****.**' LICENSE = 'AGPLv3+' VERSION = '1.1' ASSOCIATED_CATEGORIES = [CATEGORIES.CONCERT] BROWSER = RazibusBrowser region_choices = OrderedDict([ (k, u'%s' % (v)) for k, v in sorted({ '': u'-- Indifférent --', 'Alsace': u'Alsace', 'Aquitaine': u'Aquitaine', 'Auvergne': u'Auvergne', 'Basse-Normandie': u'Basse-Normandie', 'Bourgogne': u'Bourgogne', 'Bretagne': u'Bretagne', 'Centre': u'Centre', 'Champagne-Ardenne': u'Champagne-Ardenne', 'Franche-Comte': u'Franche-Comté', 'Haute-Normandie': u'Haute-Normandie', 'Ile-de-France': u'Île-de-France', 'Languedoc-Roussillon': u'Languedoc-Roussillon', 'Limousin': u'Limousin', 'Lorraine': u'Lorraine', 'Midi-Pyrenees': u'Midi-Pyrénées', 'Nord-Pas-de-Calais': u'Nord-Pas-de-Calais', 'Pays-de-la-Loire': u'Pays de la Loire', 'Picardie': u'Picardie', 'Poitou-Charentes': u'Poitou-Charentes', 'PACA': u'PACA', 'Rhone-Alpes': u'Rhône-Alpes', 'Belgique': u'Belgique', 'Suisse': u'Suisse', }.iteritems()) ]) CONFIG = BackendConfig( Value('region', label=u'Region', choices=region_choices, default='')) def create_default_browser(self): region = self.config['region'].get() return self.create_browser(region) def search_events(self, query): return self.browser.list_events(query.start_date, query.end_date, query.city, query.categories) def get_event(self, _id): return self.browser.get_event(_id) def list_events(self, date_from, date_to=None): return self.browser.list_events(date_from, date_to) def fill_obj(self, event, fields): return self.browser.get_event(event.id, event) OBJECTS = {RazibusCalendarEvent: fill_obj}
class GanAssurancesModule(Module, CapBank): NAME = 'ganassurances' MAINTAINER = u'Romain Bignon' EMAIL = '*****@*****.**' VERSION = '1.1' DESCRIPTION = u'Groupama' LICENSE = 'AGPLv3+' website_choices = OrderedDict([(k, u'%s (%s)' % (v, k)) for k, v in sorted({ 'espaceclient.groupama.fr': u'Groupama Banque', 'espaceclient.ganassurances.fr': u'Gan Assurances', }.iteritems(), key=lambda k_v: (k_v[1], k_v[0]))]) CONFIG = BackendConfig(Value('website', label='Banque', choices=website_choices, default='espaceclient.ganassurances.fr'), ValueBackendPassword('login', label=u'Numéro client', masked=False), ValueBackendPassword('password', label=u"Code d'accès")) BROWSER = GanAssurances def create_default_browser(self): return self.create_browser(self.config['website'].get(), self.config['login'].get(), self.config['password'].get()) def iter_accounts(self): return self.browser.get_accounts_list() def get_account(self, _id): return find_object(self.browser.get_accounts_list(), id=_id, error=AccountNotFound) def iter_history(self, account): return self.browser.get_history(account) def iter_coming(self, account): return self.browser.get_coming(account)
class CappedBrowser(Browser): DOMAIN = 'capped.tv' PROTOCOL = 'http' ENCODING = None PAGES = OrderedDict(( (r'http://capped\.tv/?', IndexPage), (r'http://capped\.tv/newest', IndexPage), (r'http://capped\.tv/mostviews', IndexPage), (r'http://capped\.tv/leastviews', IndexPage), (r'http://capped\.tv/monthtop', IndexPage), (r'http://capped\.tv/monthbottom', IndexPage), (r'http://capped\.tv/alpha', IndexPage), (r'http://capped\.tv/ahpla', IndexPage), (r'http://capped\.tv/search\?s\=(?P<pattern>.+)', IndexPage), (r'http://capped\.tv/(?P<id>.+)', VideoPage), )) @id2url(CappedVideo.id2url) def get_video(self, url, video=None): self.location(url) assert self.is_on_page(VideoPage), 'Should be on video page.' return self.page.get_video(video) def search_videos(self, pattern): self.location('/search?s=%s' % (urllib.quote_plus(pattern.encode('utf-8')))) assert self.is_on_page(IndexPage) return self.page.iter_videos() def latest_videos(self): self.home() assert self.is_on_page(IndexPage) return self.page.iter_videos()
def set(self, *args): v = self.values for k in args[:-2]: if k not in v: v[k] = OrderedDict() v = v[k] v[args[-2]] = args[-1]
def build_request(self, url, referrer=None, data_encoding=None, **kwargs): """ Does the same job as open(), but returns a Request without submitting it. This allows further customization to the Request. """ if isinstance(url, requests.Request): req = url url = req.url else: req = requests.Request(url=url, **kwargs) # guess method if req.method is None: if req.data: req.method = 'POST' else: req.method = 'GET' # convert unicode strings to proper encoding if isinstance(req.data, unicode) and data_encoding: req.data = req.data.encode(data_encoding) if isinstance(req.data, dict) and data_encoding: req.data = OrderedDict([ (k, v.encode(data_encoding) if isinstance(v, unicode) else v) for k, v in req.data.iteritems() ]) if referrer is None: referrer = self.get_referrer(self.url, url) if referrer: # Yes, it is a misspelling. req.headers.setdefault('Referer', referrer) return req
def __new__(cls, name, bases, attrs): fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)] fields.sort(key=lambda x: x[1]._creation_counter) new_class = super(_BaseObjectMeta, cls).__new__(cls, name, bases, attrs) if new_class._fields is None: new_class._fields = OrderedDict() else: new_class._fields = deepcopy(new_class._fields) new_class._fields.update(fields) if new_class.__doc__ is None: new_class.__doc__ = '' for name, field in fields: doc = '(%s) %s' % (', '.join([ ':class:`%s`' % v.__name__ if isinstance(v, type) else v for v in field.types ]), field.doc) if field.value is not NotLoaded: doc += ' (default: %s)' % field.value new_class.__doc__ += '\n:var %s: %s' % (name, doc) return new_class
def do_list(self, line): """ list [CAPS ..] Show backends. """ caps = line.split() for instance_name, name, params in sorted( self.weboob.backends_config.iter_backends()): try: module = self.weboob.modules_loader.get_or_load_module(name) except ModuleLoadError as e: self.logger.warning('Unable to load module %r: %s' % (name, e)) continue if caps and not module.has_caps(*caps): continue row = OrderedDict([ ('Name', instance_name), ('Module', name), ('Configuration', ', '.join( '%s=%s' % (key, ('*****' if key in module.config and module.config[key].masked else value)) for key, value in params.iteritems())), ]) self.format(row)
class CreditDuNordModule(Module, CapBank): NAME = 'creditdunord' MAINTAINER = u'Romain Bignon' EMAIL = '*****@*****.**' VERSION = '1.1' DESCRIPTION = u'Crédit du Nord, Banque Courtois, Kolb, Tarneaud' LICENSE = 'AGPLv3+' website_choices = OrderedDict([ (k, u'%s (%s)' % (v, k)) for k, v in sorted({ 'www.credit-du-nord.fr': u'Crédit du Nord', 'www.banque-courtois.fr': u'Banque Courtois', 'www.banque-kolb.fr': u'Banque Kolb', 'www.banque-rhone-alpes.fr': u'Banque Rhône-Alpes', 'www.tarneaud.fr': u'Tarneaud', }.iteritems(), key=lambda k_v: (k_v[1], k_v[0])) ]) CONFIG = BackendConfig( Value('website', label='Banque', choices=website_choices, default='www.credit-du-nord.fr'), ValueBackendPassword('login', label='Identifiant', masked=False), ValueBackendPassword('password', label='Code confidentiel')) BROWSER = CreditDuNordBrowser def create_default_browser(self): return self.create_browser(self.config['website'].get(), self.config['login'].get(), self.config['password'].get()) def iter_accounts(self): with self.browser: for account in self.browser.get_accounts_list(): yield account def get_account(self, _id): with self.browser: account = self.browser.get_account(_id) if account: return account else: raise AccountNotFound() def iter_history(self, account): with self.browser: account = self.browser.get_account(account.id) transactions = list(self.browser.get_history(account)) transactions.sort(key=lambda tr: tr.rdate, reverse=True) return [tr for tr in transactions if not tr._is_coming] def iter_coming(self, account): with self.browser: account = self.browser.get_account(account.id) transactions = list(self.browser.get_card_operations(account)) transactions.sort(key=lambda tr: tr.rdate, reverse=True) return [tr for tr in transactions if tr._is_coming]
class AccountList(Page): def on_loaded(self): if self.document.xpath(u'//h2[text()="%s"]' % u'ERREUR'): raise BrowserUnavailable() self.accounts = OrderedDict() self.parse_table('comptes', Account.TYPE_CHECKING) self.parse_table('comptesEpargne', Account.TYPE_SAVINGS) self.parse_table('comptesTitres', Account.TYPE_MARKET) self.parse_table('comptesVie', Account.TYPE_DEPOSIT) self.parse_table('comptesRetraireEuros') def get_accounts_list(self): return self.accounts.itervalues() def parse_table(self, what, actype=Account.TYPE_UNKNOWN): tables = self.document.xpath("//table[@id='%s']" % what, smart_strings=False) if len(tables) < 1: return lines = tables[0].xpath(".//tbody/tr") for line in lines: account = Account() tmp = line.xpath("./td//a")[0] account.label = to_unicode(tmp.text) account.type = actype account._link_id = tmp.get("href") if 'BourseEnLigne' in account._link_id: account.type = Account.TYPE_MARKET tmp = line.xpath("./td/span/strong") if len(tmp) >= 2: tmp_id = tmp[0].text tmp_balance = tmp[1].text else: tmp_id = line.xpath("./td//span")[1].text tmp_balance = tmp[0].text account.id = tmp_id account.currency = account.get_currency(tmp_balance) account.balance = Decimal(FrenchTransaction.clean_amount(tmp_balance)) if account.id in self.accounts: a = self.accounts[account.id] a._card_links.append(account._link_id) if not a.coming: a.coming = Decimal('0.0') a.coming += account.balance else: account._card_links = [] self.accounts[account.id] = account page = self.browser.get_page(self.browser.openurl(self.browser.buildurl('/voscomptes/canalXHTML/comptesCommun/imprimerRIB/init-imprimer_rib.ea', ('compte.numero', account.id)))) account.iban = page.get_iban() def get_account(self, id): try: return self.accounts[id] except KeyError: raise AccountNotFound('Unable to find account: %s' % id)
class BanquePopulaireModule(Module, CapBank): NAME = 'banquepopulaire' MAINTAINER = u'Romain Bignon' EMAIL = '*****@*****.**' VERSION = '1.1' DESCRIPTION = u'Banque Populaire' LICENSE = 'AGPLv3+' website_choices = OrderedDict([(k, u'%s (%s)' % (v, k)) for k, v in sorted({ 'www.ibps.alpes.banquepopulaire.fr': u'Alpes', 'www.ibps.alsace.banquepopulaire.fr': u'Alsace', 'www.ibps.bpaca.banquepopulaire.fr': u'Aquitaine Centre atlantique', 'www.ibps.atlantique.banquepopulaire.fr': u'Atlantique', 'www.ibps.bpbfc.banquepopulaire.fr': u'Bourgogne-Franche Comté', 'www.ibps.bretagnenormandie.cmm.groupe.banquepopulaire.fr': u'Crédit Maritime Bretagne Normandie', 'www.ibps.atlantique.creditmaritime.groupe.banquepopulaire.fr': u'Crédit Maritime Atlantique', 'www.ibps.sudouest.creditmaritime.groupe.banquepopulaire.fr': u'Crédit Maritime du Littoral du Sud-Ouest', 'www.ibps.cotedazur.banquepopulaire.fr': u'Côte d\'azur', 'www.ibps.loirelyonnais.banquepopulaire.fr': u'Loire et Lyonnais', 'www.ibps.lorrainechampagne.banquepopulaire.fr': u'Lorraine Champagne', 'www.ibps.massifcentral.banquepopulaire.fr': u'Massif central', 'www.ibps.nord.banquepopulaire.fr': u'Nord', 'www.ibps.occitane.banquepopulaire.fr': u'Occitane', 'www.ibps.ouest.banquepopulaire.fr': u'Ouest', 'www.ibps.provencecorse.banquepopulaire.fr': u'Provence et Corse', 'www.ibps.rivesparis.banquepopulaire.fr': u'Rives de Paris', 'www.ibps.sud.banquepopulaire.fr': u'Sud', 'www.ibps.valdefrance.banquepopulaire.fr': u'Val de France', }.iteritems(), key=lambda k_v: (k_v[1], k_v[0]))]) CONFIG = BackendConfig(Value('website', label=u'Région', choices=website_choices), ValueBackendPassword('login', label='Identifiant', masked=False), ValueBackendPassword('password', label='Mot de passee')) BROWSER = BanquePopulaire def create_default_browser(self): return self.create_browser(self.config['website'].get(), self.config['login'].get(), self.config['password'].get()) def iter_accounts(self): with self.browser: return self.browser.get_accounts_list() def get_account(self, _id): with self.browser: account = self.browser.get_account(_id) if account: return account else: raise AccountNotFound() def iter_history(self, account): with self.browser: return self.browser.get_history(account) def iter_coming(self, account): with self.browser: return self.browser.get_history(account, coming=True)
class AccountList(Page): def on_loaded(self): if self.document.xpath(u'//h2[text()="%s"]' % u'ERREUR'): raise BrowserUnavailable() self.accounts = OrderedDict() self.parse_table('comptes', Account.TYPE_CHECKING) self.parse_table('comptesEpargne', Account.TYPE_SAVINGS) self.parse_table('comptesTitres', Account.TYPE_MARKET) self.parse_table('comptesVie', Account.TYPE_DEPOSIT) self.parse_table('comptesRetraireEuros') def get_accounts_list(self): return self.accounts.itervalues() def parse_table(self, what, actype=Account.TYPE_UNKNOWN): tables = self.document.xpath("//table[@id='%s']" % what, smart_strings=False) if len(tables) < 1: return lines = tables[0].xpath(".//tbody/tr") for line in lines: account = Account() tmp = line.xpath("./td//a")[0] account.label = to_unicode(tmp.text) account.type = actype account._link_id = tmp.get("href") if 'BourseEnLigne' in account._link_id: account.type = Account.TYPE_MARKET tmp = line.xpath("./td/span/strong") if len(tmp) >= 2: tmp_id = tmp[0].text tmp_balance = tmp[1].text else: tmp_id = line.xpath("./td//span")[1].text tmp_balance = tmp[0].text account.id = tmp_id account.currency = account.get_currency(tmp_balance) account.balance = Decimal( FrenchTransaction.clean_amount(tmp_balance)) if account.id in self.accounts: a = self.accounts[account.id] a._card_links.append(account._link_id) if not a.coming: a.coming = Decimal('0.0') a.coming += account.balance else: account._card_links = [] self.accounts[account.id] = account def get_account(self, id): try: return self.accounts[id] except KeyError: raise AccountNotFound('Unable to find account: %s' % id)
class CaisseEpargneModule(Module, CapBank): NAME = 'caissedepargne' MAINTAINER = u'Romain Bignon' EMAIL = '*****@*****.**' VERSION = '1.2' DESCRIPTION = u'Caisse d\'Épargne' LICENSE = 'AGPLv3+' website_choices = OrderedDict([ (k, u'%s (%s)' % (v, k)) for k, v in sorted({ 'www.caisse-epargne.fr': u'Caisse d\'Épargne', 'www.banquebcp.fr': u'Banque BCP', }.iteritems(), key=lambda k_v: (k_v[1], k_v[0])) ]) CONFIG = BackendConfig( Value('website', label='Banque', choices=website_choices, default='www.caisse-epargne.fr'), ValueBackendPassword('login', label='Identifiant client', masked=False), ValueBackendPassword('password', label='Code personnel', regexp='\d+'), Value('nuser', label='User ID (optional)', default='')) BROWSER = CaisseEpargne def create_default_browser(self): return self.create_browser(nuser=self.config['nuser'].get(), username=self.config['login'].get(), password=self.config['password'].get(), domain=self.config['website'].get()) def iter_accounts(self): with self.browser: for account in self.browser.get_accounts_list(): yield account for account in self.browser.get_loans_list(): yield account def get_account(self, _id): with self.browser: account = self.browser.get_account(_id) if account: return account else: raise AccountNotFound() def iter_history(self, account): with self.browser: return self.browser.get_history(account) def iter_coming(self, account): with self.browser: return self.browser.get_coming(account) def iter_investment(self, account): return self.browser.get_investment(account)
class S2eModule(Module, CapBank): NAME = 's2e' MAINTAINER = u'Christophe Lampin' EMAIL = '*****@*****.**' VERSION = '1.2' LICENSE = 'AGPLv3+' DESCRIPTION = u'Esalia, Capeasi, BNP PERE, HSBC ERE' website_choices = OrderedDict([ (k, u'%s (%s)' % (v, k)) for k, v in sorted( { 'm.esalia.com': u'Esalia', # Good Url. Tested 'mobile.capeasi.com': u'Capeasi', # Good Url. Not fully tested 'mobi.ere.hsbc.fr': u'ERE HSBC', # Good Url. Tested 'smartphone.s2e-net.com': u'BNPP ERE', # Good Url. Tested # 'smartphone.s2e-net.com': u'Groupe Crédit du Nord', # Mobile version not available yet. }.iteritems(), key=lambda k_v: (k_v[1], k_v[0])) ]) BROWSERS = { 'm.esalia.com': Esalia, 'mobile.capeasi.com': Capeasi, 'mobi.ere.hsbc.fr': EREHSBC, 'smartphone.s2e-net.com': BNPPERE, # 'smartphone.s2e-net.com': CreditNord, # Mobile version not available yet. } CONFIG = BackendConfig( Value('website', label='Banque', choices=website_choices, default='smartphone.s2e-net.com'), ValueBackendPassword('login', label='Identifiant', masked=False), ValueBackendPassword('password', label='Code secret', regexp='^(\d{6}|)$')) def create_default_browser(self): self.BROWSER = self.BROWSERS[self.config['website'].get()] return self.create_browser(self.config['website'].get(), self.config['login'].get(), self.config['password'].get()) def iter_accounts(self): return self.browser.get_accounts_list() def get_account(self, _id): return find_object(self.browser.get_accounts_list(), id=_id, error=AccountNotFound) def iter_investment(self, account): return account._investments def iter_history(self, account): return self.browser.iter_history(account)
def to_dict(self): def iter_decorate(d): for key, value in d: if key == 'id' and self.backend is not None: value = self.fullid yield key, value fields_iterator = self.iter_fields() return OrderedDict(iter_decorate(fields_iterator))
def get_list(self): accounts = OrderedDict() for tr in self.document.getiterator('tr'): first_td = tr.getchildren()[0] if (first_td.attrib.get('class', '') == 'i g' or first_td.attrib.get('class', '') == 'p g') \ and first_td.find('a') is not None: a = first_td.find('a') link = a.get('href', '') if link.startswith('POR_SyntheseLst'): continue url = urlparse(link) p = parse_qs(url.query) if not 'rib' in p: continue for i in (2,1): balance = FrenchTransaction.clean_amount(tr.getchildren()[i].text.strip(' EUR')) if len(balance) > 0: break balance = Decimal(balance) id = p['rib'][0] if id in accounts: account = accounts[id] if not account.coming: account.coming = Decimal('0.0') account.coming += balance account._card_links.append(link) continue account = Account() account.id = id account.label = unicode(a.text).strip().lstrip(' 0123456789').title() account._link_id = link account._card_links = [] account.balance = balance accounts[account.id] = account return accounts.itervalues()
def on_loaded(self): for script in self.document.xpath('//script'): text = script.text if text is None: continue m = re.search("window.location.replace\('([^']+)'\);", text) if m: self.browser.location(m.group(1)) try: self.browser.select_form(name='banque') except FormNotFoundError: pass else: self.browser.set_all_readonly(False) accounts = OrderedDict() for tr in self.document.getroot().cssselect('table.compteTable > tbody > tr'): if len(tr.findall('td')) == 0: continue attr = tr.xpath('.//a')[0].attrib.get('onclick', '') m = re.search("value = '(\w+)';(checkAndSubmit\('\w+','(\w+)','(\w+)'\))?", attr) if m: typeCompte = m.group(1) tagName = m.group(3) if tagName is not None: value = self.document.xpath('//input[@name="%s"]' % m.group(3))[int(m.group(4))].attrib['value'] else: value = typeCompte accounts[value] = (typeCompte, tagName) try: typeCompte, tagName = accounts[self.browser.accnum] value = self.browser.accnum except KeyError: accnums = ', '.join(accounts.keys()) if self.browser.accnum != '00000000000': self.logger.warning(u'Unable to find account "%s". Available ones: %s' % (self.browser.accnum, accnums)) elif len(accounts) > 1: self.logger.warning('There are several accounts, please use "accnum" backend parameter to force the one to use (%s)' % accnums) value, (typeCompte, tagName) = accounts.popitem(last=False) self.browser['typeCompte'] = typeCompte if tagName is not None: self.browser[tagName] = [value] self.browser.submit()
class BanquePopulaireBackend(BaseBackend, ICapBank): NAME = 'banquepopulaire' MAINTAINER = u'Romain Bignon' EMAIL = '*****@*****.**' VERSION = '0.e' DESCRIPTION = u'Banque Populaire French bank website' LICENSE = 'AGPLv3+' website_choices = OrderedDict([(k, u'%s (%s)' % (v, k)) for k, v in sorted( { 'www.ibps.alpes.banquepopulaire.fr': u'Alpes', 'www.ibps.alsace.banquepopulaire.fr': u'Alsace', 'www.ibps.bpaca.banquepopulaire.fr': u'Aquitaine Centre atlantique', 'www.ibps.atlantique.banquepopulaire.fr': u'Atlantique', 'www.ibps.bpbfc.banquepopulaire.fr': u'Bourgogne-Franche Comté', 'www.ibps.cotedazur.banquepopulaire.fr': u'Côte d\'azur', 'www.ibps.loirelyonnais.banquepopulaire.fr': u'Loire et Lyonnais', 'www.ibps.lorrainechampagne.banquepopulaire.fr': u'Lorraine Champagne', 'www.ibps.massifcentral.banquepopulaire.fr': u'Massif central', 'www.ibps.nord.banquepopulaire.fr': u'Nord', 'www.ibps.occitane.banquepopulaire.fr': u'Occitane', 'www.ibps.ouest.banquepopulaire.fr': u'Ouest', 'www.ibps.provencecorse.banquepopulaire.fr': u'Provence et Corse', 'www.ibps.rivesparis.banquepopulaire.fr': u'Rives de Paris', 'www.ibps.sud.banquepopulaire.fr': u'Sud', 'www.ibps.valdefrance.banquepopulaire.fr': u'Val de France', }.iteritems())]) CONFIG = BackendConfig( Value('website', label='Website to use', choices=website_choices), ValueBackendPassword('login', label='Account ID', masked=False), ValueBackendPassword('password', label='Password')) BROWSER = BanquePopulaire def create_default_browser(self): return self.create_browser(self.config['website'].get(), self.config['login'].get(), self.config['password'].get()) def iter_accounts(self): with self.browser: return self.browser.get_accounts_list() def get_account(self, _id): with self.browser: account = self.browser.get_account(_id) if account: return account else: raise AccountNotFound() def iter_history(self, account): with self.browser: return self.browser.get_history(account)
def __new__(mcs, name, bases, attrs): urls = [(url_name, attrs.pop(url_name)) for url_name, obj in attrs.items() if isinstance(obj, URL)] urls.sort(key=lambda x: x[1]._creation_counter) new_class = super(_PagesBrowserMeta, mcs).__new__(mcs, name, bases, attrs) if new_class._urls is None: new_class._urls = OrderedDict() else: new_class._urls = deepcopy(new_class._urls) new_class._urls.update(urls) return new_class
class AccountList(BasePage): def on_loaded(self): self.accounts = OrderedDict() self.parse_table('comptes', Account.TYPE_CHECKING) self.parse_table('comptesEpargne', Account.TYPE_SAVINGS) self.parse_table('comptesTitres', Account.TYPE_MARKET) self.parse_table('comptesVie', Account.TYPE_DEPOSIT) self.parse_table('comptesRetraireEuros') def get_accounts_list(self): return self.accounts.itervalues() def parse_table(self, what, actype=Account.TYPE_UNKNOWN): tables = self.document.xpath("//table[@id='%s']" % what, smart_strings=False) if len(tables) < 1: return lines = tables[0].xpath(".//tbody/tr") for line in lines: account = Account() tmp = line.xpath("./td//a")[0] account.label = to_unicode(tmp.text) account.type = actype account._link_id = tmp.get("href") if 'BourseEnLigne' in account._link_id: account.type = Account.TYPE_MARKET tmp = line.xpath("./td/span/strong") if len(tmp) >= 2: tmp_id = tmp[0].text tmp_balance = tmp[1].text else: tmp_id = line.xpath("./td//span")[1].text tmp_balance = tmp[0].text account.id = tmp_id account.currency = account.get_currency(tmp_balance) account.balance = Decimal(FrenchTransaction.clean_amount(tmp_balance)) if account.id in self.accounts: a = self.accounts[account.id] a._card_links.append(account._link_id) if not a.coming: a.coming = Decimal('0.0') a.coming += account.balance else: account._card_links = [] self.accounts[account.id] = account def get_account(self, id): try: return self.accounts[id] except KeyError: raise AccountNotFound('Unable to find account: %s' % id)
def __init__(self, *args, **kwargs): self.PAGES = OrderedDict(( ('%s://%s/Pgn/.+PageID=SoldeV3&.+' % (self.PROTOCOL, self.DOMAIN), AccountsPage), ('%s://%s/Pgn/.+PageID=Cartes&.+' % (self.PROTOCOL, self.DOMAIN), CardsPage), ('%s://%s/Pgn/.+PageID=ReleveCompteV3&.+' % (self.PROTOCOL, self.DOMAIN), HistoryPage), ('%s://%s/Pgn/.+PageID=ReleveCarte&.+' % (self.PROTOCOL, self.DOMAIN), CardHistoryPage), ('%s://%s/ord-web/ord//ord-liste-compte-emetteur.json' % (self.PROTOCOL, self.DOMAIN), (OrderPage, JsonParser())), ('%s://%s/authent\.html' % (self.PROTOCOL, self.DOMAIN), ErrorPage), ('%s://%s/' % (self.PROTOCOL, self.DOMAIN), LoginPage), )) Browser.__init__(self, *args, **kwargs)
def to_dict(self): def iter_decorate(d): for key, value in d: if key == 'id' and self.backend is not None: value = u'%s@%s' % (self.basename, self.backend) yield key, value if key == 'split_path': yield key, '/'.join(value) fields_iterator = self.iter_fields() return OrderedDict(iter_decorate(fields_iterator))
def parse_profile(self, profile, consts): if profile['online']: self.status = Contact.STATUS_ONLINE self.status_msg = u'online' self.status_msg = u'since %s' % profile['last_cnx'] else: self.status = Contact.STATUS_OFFLINE self.status_msg = u'last connection %s' % profile['last_cnx'] self.summary = html2text(profile.get('announce', '')).strip().replace('\n\n', '\n') if len(profile.get('shopping_list', '')) > 0: self.summary += u'\n\nLooking for:\n%s' % html2text(profile['shopping_list']).strip().replace('\n\n', '\n') for photo in profile['pics']: self.set_photo(photo.split('/')[-1], url=photo + '/full', thumbnail_url=photo + '/small', hidden=False) self.profile = OrderedDict() if 'sex' in profile: for section, d in self.TABLE.iteritems(): flags = ProfileNode.SECTION if section.startswith('_'): flags |= ProfileNode.HEAD if (section.startswith('+') and int(profile['sex']) != 1) or \ (section.startswith('-') and int(profile['sex']) != 0): continue section = section.lstrip('_+-') s = ProfileNode(section, section.capitalize(), OrderedDict(), flags=flags) for key, builder in d.iteritems(): try: value = builder.get_value(profile, consts[int(profile['sex'])]) except KeyError: pass else: s.value[key] = ProfileNode(key, key.capitalize().replace('_', ' '), value) self.profile[section] = s self._aum_profile = profile
def format(self, obj, selected_fields=None, alias=None): """ Format an object to be human-readable. An object has fields which can be selected. :param obj: object to format :type obj: BaseObject or dict :param selected_fields: fields to display. If None, all fields are selected :type selected_fields: tuple :param alias: an alias to use instead of the object's ID :type alias: unicode """ if isinstance(obj, BaseObject): if selected_fields: # can be an empty list (nothing to do), or None (return all fields) obj = obj.copy() for name, value in obj.iter_fields(): if name not in selected_fields: delattr(obj, name) if self.MANDATORY_FIELDS: missing_fields = set(self.MANDATORY_FIELDS) - set([name for name, value in obj.iter_fields()]) if missing_fields: raise MandatoryFieldsNotFound(missing_fields) formatted = self.format_obj(obj, alias) else: try: obj = OrderedDict(obj) except ValueError: raise TypeError('Please give a BaseObject or a dict') if selected_fields: obj = obj.copy() for name, value in obj.iteritems(): if name not in selected_fields: obj.pop(name) if self.MANDATORY_FIELDS: missing_fields = set(self.MANDATORY_FIELDS) - set(obj.iterkeys()) if missing_fields: raise MandatoryFieldsNotFound(missing_fields) formatted = self.format_dict(obj) if formatted: self.output(formatted) return formatted
def registerEvent(self): selection = self.ui.modulesList.selectedItems() if not selection: return try: module = self.weboob.modules_loader.get_or_load_module(unicode(selection[0].text()).lower()) except ModuleLoadError: module = None if not module: return dialog = QDialog(self) vbox = QVBoxLayout(dialog) if module.website: website = 'on the website <b>%s</b>' % module.website else: website = 'with the module <b>%s</b>' % module.name vbox.addWidget(QLabel('To create an account %s, please provide this information:' % website)) formlayout = QFormLayout() props_widgets = OrderedDict() for key, prop in module.klass.ACCOUNT_REGISTER_PROPERTIES.iteritems(): widget = QtValue(prop) formlayout.addRow(QLabel(u'%s:' % prop.label), widget) props_widgets[prop.id] = widget vbox.addLayout(formlayout) buttonBox = QDialogButtonBox(dialog) buttonBox.setStandardButtons(QDialogButtonBox.Ok|QDialogButtonBox.Cancel) self.connect(buttonBox, SIGNAL("accepted()"), dialog.accept) self.connect(buttonBox, SIGNAL("rejected()"), dialog.reject) vbox.addWidget(buttonBox) end = False while not end: end = True if dialog.exec_(): account = Account() account.properties = {} for key, widget in props_widgets.iteritems(): try: v = widget.get_value() except ValueError as e: QMessageBox.critical(self, self.tr('Invalid value'), unicode(self.tr('Invalid value for field "%s":<br /><br />%s')) % (key, e)) end = False break else: account.properties[key] = v if end: try: module.klass.register_account(account) except AccountRegisterError as e: QMessageBox.critical(self, self.tr('Error during register'), unicode(self.tr('Unable to register account %s:<br /><br />%s')) % (website, e)) end = False else: for key, value in account.properties.iteritems(): if key in self.config_widgets: self.config_widgets[key][1].set_value(value)
class Contact(_Contact): TABLE = OrderedDict(( ('_info', OrderedDict(( ('title', FieldStr('title')), # ipaddr is not available anymore. #('IPaddr', FieldIP('last_ip', 'first_ip')), ('admin', FieldBool('admin')), ('ban', FieldBool('isBan')), ('first', FieldStr('first_cnx')), ('godfather', FieldProfileURL('godfather')), ))), ('_stats', OrderedDict(( ('mails', FieldPopu('mails')), ('baskets', FieldPopu('contacts')), ('charms', FieldPopu('flashs')), ('visites', FieldPopu('visites')), ('invits', FieldPopu('invits')), ('bonus', FieldPopu('bonus')), ('score', FieldStr('points')), ('ratio', FieldPopuRatio('mails', 'flashs')), ('mailable', FieldBool('can_mail')), ))), ('details', OrderedDict(( ('old', FieldStr('age')), #('old', FieldOld('birthday')), ('birthday', FieldStr('birthday')), ('zipcode', FieldStr('zip')), ('location', FieldStr('city')), ('distance', FieldDist('dist')), ('country', FieldStr('country')), ('phone', FieldStr('phone')), ('eyes', FieldConst('eyes_color')), ('hair_color', FieldConst('hair_color')), ('hair_size', FieldConst('hair_size')), ('height', FieldConst('size')), ('weight', FieldConst('weight')), ('BMI', FieldBMI('size', 'weight')), ('fat', FieldBMI('size', 'weight', fat=True)), ('shape', FieldConst('shape')), ('origins', FieldConst('origins')), ('signs', FieldConst('features')), ('job', FieldStr('job')), ('style', FieldConst('style')), ('food', FieldConst('diet')), ('drink', FieldConst('alcohol')), ('smoke', FieldConst('tobacco')), ))), ('tastes', OrderedDict(( ('hobbies', FieldStr('hobbies')), ('music', FieldList('music')), ('cinema', FieldList('cinema')), ('books', FieldList('books')), ('tv', FieldList('tvs')), ))), ('+sex', OrderedDict(( ('underwear', FieldConst('underwear')), ('practices', FieldConst('sexgames')), ('favorite', FieldConst('arousing')), ('toys', FieldConst('sextoys')), ))), ('+personality', OrderedDict(( ('snap', FieldStr('fall_for')), ('exciting', FieldStr('turned_on_by')), ('hate', FieldStr('cant_stand')), ('vices', FieldStr('vices')), ('assets', FieldStr('assets')), ('fantasies', FieldStr('fantasies')), ('is', FieldConst('character')), ))) )) def parse_profile(self, profile, consts): if profile['online']: self.status = Contact.STATUS_ONLINE self.status_msg = u'online' self.status_msg = u'since %s' % profile['last_cnx'] else: self.status = Contact.STATUS_OFFLINE self.status_msg = u'last connection %s' % profile['last_cnx'] self.summary = html2text(profile.get('announce', '')).strip().replace('\n\n', '\n') if len(profile.get('shopping_list', '')) > 0: self.summary += u'\n\nLooking for:\n%s' % html2text(profile['shopping_list']).strip().replace('\n\n', '\n') for photo in profile['pics']: self.set_photo(photo.split('/')[-1], url=photo + '/full', thumbnail_url=photo + '/small', hidden=False) self.profile = OrderedDict() if 'sex' in profile: for section, d in self.TABLE.iteritems(): flags = ProfileNode.SECTION if section.startswith('_'): flags |= ProfileNode.HEAD if (section.startswith('+') and int(profile['sex']) != 1) or \ (section.startswith('-') and int(profile['sex']) != 0): continue section = section.lstrip('_+-') s = ProfileNode(section, section.capitalize(), OrderedDict(), flags=flags) for key, builder in d.iteritems(): try: value = builder.get_value(profile, consts[int(profile['sex'])]) except KeyError: pass else: s.value[key] = ProfileNode(key, key.capitalize().replace('_', ' '), value) self.profile[section] = s self._aum_profile = profile def get_text(self): def print_node(node, level=1): result = u'' if node.flags & node.SECTION: result += u'\t' * level + node.label + '\n' for sub in node.value.itervalues(): result += print_node(sub, level + 1) else: if isinstance(node.value, (tuple, list)): value = ', '.join(unicode(v) for v in node.value) elif isinstance(node.value, float): value = '%.2f' % node.value else: value = node.value result += u'\t' * level + u'%-20s %s\n' % (node.label + ':', value) return result result = u'Nickname: %s\n' % self.name if self.status & Contact.STATUS_ONLINE: s = 'online' elif self.status & Contact.STATUS_OFFLINE: s = 'offline' elif self.status & Contact.STATUS_AWAY: s = 'away' else: s = 'unknown' result += u'Status: %s (%s)\n' % (s, self.status_msg) result += u'URL: %s\n' % self.url result += u'Photos:\n' for name, photo in self.photos.iteritems(): result += u'\t%s%s\n' % (photo, ' (hidden)' if photo.hidden else '') result += u'\nProfile:\n' for head in self.profile.itervalues(): result += print_node(head) result += u'Description:\n' for s in self.summary.split('\n'): result += u'\t%s\n' % s return result
class Event(object): def __init__(self, name, backend): self.my_id = backend.browser.get_userid() self.name = 'wiki/weboob/%s' % name self.description = None self.date = None self.begin = None self.end = None self.location = None self.winner = None self.backend = backend self.members = OrderedDict() self.load() def get_me(self): return self.members.get(self.backend.browser.get_userid(), None) def currently_in_event(self): if not self.date or not self.begin or not self.end: return False return self.begin < datetime.now() < self.end def is_closed(self): return self.end < datetime.now() def format_duration(self): if not self.begin or not self.end: return None delta = self.end - self.begin return '%02d:%02d' % (delta.seconds/3600, delta.seconds%3600) def check_time_coherence(self): """ Check if the end's day is before the begin's one, in case it stops at the next day (eg. 15h->1h). If it occures, add a day. """ if self.begin > self.end: self.end = self.end + timedelta(1) def load(self): self.content = self.backend.get_content(self.name) self.members.clear() member = None for line in self.content.content.split('\n'): line = line.strip() if line.startswith('h1. '): self.title = line[4:] elif line.startswith('h3=. '): m = re.match('h3=. Event finished. Winner is "(.*)":/users/(\d+)\!', line) if not m: print >>self.stderr, 'Unable to parse h3=: %s' % line continue self.winner = Member(int(m.group(2)), m.group(1)) elif line.startswith('h2. '): continue elif line.startswith('h3. '): m = re.match('h3. "(.*)":/users/(\d+)', line) if not m: print >>self.stderr, 'Unable to parse user "%s"' % line continue member = Member(int(m.group(2)), m.group(1)) if member.id == self.my_id: member.is_me = True if self.winner is not None and member.id == self.winner.id: self.winner = member self.members[member.id] = member elif self.description is None and len(line) > 0 and line != '{{TOC}}': self.description = line elif line.startswith('* '): m = re.match('\* \*(\w+)\*: (.*)', line) if not m: continue key, value = m.group(1), m.group(2) if member is None: if key == 'Date': self.date = self.parse_date(value) elif key == 'Start' or key == 'Begin': self.begin = self.parse_time(value) elif key == 'End': self.end = self.parse_time(value) self.check_time_coherence() elif key == 'Location': self.location = value else: if key == 'Repository': m = re.match('"(.*.git)":.*', value) if m: member.repository = m.group(1) else: member.repository = value elif key == 'Hardware': member.hardware = value elif key == 'Availabilities': member.availabilities = value elif line.startswith('[['): m = re.match('\[\[(\w+)\]\]\|\[\[(\w+)\]\]\|(.*)\|', line) if not m: print >>self.stderr, 'Unable to parse task: "%s"' % line continue task = Task(m.group(1), m.group(2)) member.tasks.append(task) if m.group(3) == '!/img/weboob/_progress.png!': task.status = task.STATUS_PROGRESS continue mm = re.match('!/img/weboob/_done.png! (\d+):(\d+) (\w+)', m.group(3)) if mm and self.date: task.status = task.STATUS_DONE task.date = datetime(self.date.year, self.date.month, self.date.day, int(mm.group(1)), int(mm.group(2))) task.branch = mm.group(3) def parse_date(self, value): try: return datetime.strptime(value, '%Y-%m-%d') except ValueError: return None def parse_time(self, value): m = re.match('(\d+):(\d+)', value) if not m: return try: return self.date.replace(hour=int(m.group(1)), minute=int(m.group(2))) except ValueError: return None def save(self, message): if self.winner: finished = u'\nh3=. Event finished. Winner is "%s":/users/%d!\n' % (self.winner.name, self.winner.id) else: finished = u'' s = u"""h1. %s {{TOC}} %s h2. Event %s * *Date*: %s * *Begin*: %s * *End*: %s * *Duration*: %s * *Location*: %s h2. Attendees """ % (self.title, finished, self.description, self.date.strftime('%Y-%m-%d') if self.date else '_Unknown_', self.begin.strftime('%H:%M') if self.begin else '_Unknown_', self.end.strftime('%H:%M') if self.end else '_Unknown_', self.format_duration() or '_Unknown_', self.location or '_Unknown_') for member in self.members.itervalues(): if self.date: availabilities = '' else: availabilities = '* *Availabilities*: %s' % member.availabilities if member.repository is None: repository = '_Unknown_' elif member.repository.endswith('.git'): repository = '"%s":git://git.symlink.me/pub/%s ("http":http://git.symlink.me/?p=%s;a=summary)' repository = repository.replace('%s', member.repository) else: repository = member.repository s += u"""h3. "%s":/users/%d * *Repository*: %s * *Hardware*: %s %s |_.Backend|_.Capabilities|_.Status|""" % (member.name, member.id, repository, member.hardware, availabilities) for task in member.tasks: if task.status == task.STATUS_DONE: status = '!/img/weboob/_done.png! %02d:%02d %s' % (task.date.hour, task.date.minute, task.branch) elif task.status == task.STATUS_PROGRESS: status = '!/img/weboob/_progress.png!' else: status = ' ' s += u""" |=.!/img/weboob/%s.png!:/projects/weboob/wiki/%s [[%s]]|[[%s]]|%s|""" % (task.backend.lower(), task.backend, task.backend, task.capability, status) s += '\n\n' self.content.content = s self.backend.push_content(self.content, message)
def __init__(self, *args, **kwargs): super(ListElement, self).__init__(*args, **kwargs) self.logger = getLogger(self.__class__.__name__.lower()) self.objects = OrderedDict()
class ListElement(AbstractElement): item_xpath = None flush_at_end = False ignore_duplicate = False def __init__(self, *args, **kwargs): super(ListElement, self).__init__(*args, **kwargs) self.logger = getLogger(self.__class__.__name__.lower()) self.objects = OrderedDict() def __call__(self, *args, **kwargs): for key, value in kwargs.iteritems(): self.env[key] = value return self.__iter__() def find_elements(self): """ Get the nodes that will have to be processed. This method can be overridden if xpath filters are not sufficient. """ if self.item_xpath is not None: for el in self.el.xpath(self.item_xpath): yield el else: yield self.el def __iter__(self): self.parse(self.el) items = [] for el in self.find_elements(): for attrname in dir(self): attr = getattr(self, attrname) if isinstance(attr, type) and issubclass(attr, AbstractElement) and attr != type(self): item = attr(self.page, self, el) item.handle_loaders() items.append(item) for item in items: for obj in item: obj = self.store(obj) if obj and not self.flush_at_end: yield obj if self.flush_at_end: for obj in self.flush(): yield obj self.check_next_page() def flush(self): for obj in self.objects.itervalues(): yield obj def check_next_page(self): if not hasattr(self, 'next_page'): return next_page = getattr(self, 'next_page') try: value = self.use_selector(next_page) except (AttributeNotFound, XPathNotFound): return if value is None: return raise NextPage(value) def store(self, obj): if obj.id: if obj.id in self.objects: if self.ignore_duplicate: self.logger.warning('There are two objects with the same ID! %s' % obj.id) return else: raise DataError('There are two objects with the same ID! %s' % obj.id) self.objects[obj.id] = obj return obj