From 5d9f3d528e8cd3cd30471906783fae6d969c9d0f Mon Sep 17 00:00:00 2001 From: Étienne Loks Date: Sat, 14 Feb 2015 13:47:10 +0100 Subject: Refactoring XSLT imports - fix tests --- chimere/tests.py | 18 +++++-- chimere/utils.py | 155 +++++++++++++++++++++++++++++-------------------------- 2 files changed, 98 insertions(+), 75 deletions(-) diff --git a/chimere/tests.py b/chimere/tests.py index ef54d0b..3a3144e 100644 --- a/chimere/tests.py +++ b/chimere/tests.py @@ -137,8 +137,9 @@ class ImporterTest: nb, nb_updated, res = importer.manager.get() if awaited_nb == None: continue - self.assertEqual(nb, awaited_nb, msg=u"%s: get test failed" % - unicode(self.__class__)) + self.assertEqual(nb, awaited_nb, + msg=u"%s: get test failed - got %d when %d was awaited" % + (unicode(self.__class__), nb, awaited_nb)) self.assertEqual(nb_updated, 0) for cat in importer.categories.all(): if cat not in nb_by_cat: @@ -311,6 +312,17 @@ class HtmlXsltImporterTest(TestCase, ImporterTest): importer1.categories.add(subcategories[0]) self.marker_importers = [(importer1, 7),] +class XmlXsltImporterTest(TestCase, ImporterTest): + def setUp(self): + subcategories = subcategory_setup() + xslt1 = File(open(test_dir_path + 'tests/magny-xml.xslt')) + importer1 = Importer.objects.create(importer_type='XXLT', + source='http://www.chymeres.net/test/magny.xml', + source_file=xslt1, + default_localisation='SRID=4326;POINT(-4.5 48.4)',) + importer1.categories.add(subcategories[0]) + self.marker_importers = [(importer1, 10),] + class FeedsTest(TestCase): def setUp(self): self.areas = areas_setup() @@ -442,7 +454,7 @@ class DynamicCategoryTest(TestCase): response = self.client.get(url) self.assertEqual(200, response.status_code) cats = json.loads(response.content)['categories'] - self.assertEqual(len(cats), 2) + self.assertEqual(len(cats), 5) class NewsTest(TestCase): def setUp(self): diff --git a/chimere/utils.py b/chimere/utils.py index 73e38ba..ba5e558 100644 --- a/chimere/utils.py +++ b/chimere/utils.py @@ -870,17 +870,17 @@ except UnicodeEncodeError: for locale in MONTH_NAMES} DATE_PARSINGS = {'fr_FR':[ - re.compile(r'(?P\d{1,2}) '\ - r'(?P'+ '|'.join(UNI_MONTH_NAMES['fr_FR']) +') '\ - r'(?P\d{4})?[^\d]*'\ - r'(?P\d{1,2}) '\ - r'(?P'+ '|'.join(UNI_MONTH_NAMES['fr_FR']) +') *'\ - r'(?P\d{4})?.*'), - re.compile(r'(?P\d{1,2}) '\ - r'(?P'+ '|'.join(UNI_MONTH_NAMES['fr_FR']) +') *'\ - r'(?P\d{4})?') - ] - } + re.compile(r'(?P\d{1,2}) '\ + r'(?P'+ '|'.join(UNI_MONTH_NAMES['fr_FR']) +') '\ + r'(?P\d{4})?[^\d]*'\ + r'(?P\d{1,2}) '\ + r'(?P'+ '|'.join(UNI_MONTH_NAMES['fr_FR']) +') *'\ + r'(?P\d{4})?.*'), + re.compile(r'(?P\d{1,2}) '\ + r'(?P'+ '|'.join(UNI_MONTH_NAMES['fr_FR']) +') *'\ + r'(?P\d{4})?') + ] + } def clean_field(value): return value.strip() @@ -897,6 +897,7 @@ class HtmlXsltManager(ImportManager): - error detail on error. """ from models import Marker + self.marker_cls = Marker try: main_page = urllib2.urlopen(self.importer_instance.source) assert main_page.getcode() == 200 @@ -966,71 +967,81 @@ class HtmlXsltManager(ImportManager): for r, replaced in RE_CLEANS: val = re.sub(r, replaced % {'base_url':base_url}, val) item[k] = html_unescape(val) - updated_item, new_item = 0, 0 - key_categories = self.importer_instance.get_key_category_dict() - missing_cats = set() + self.key_categories = self.importer_instance.get_key_category_dict() + self.missing_cats = set() + self.updated_item, self.new_item = 0, 0 for item in items: - if not self.importer_instance.default_localisation and \ - not "point" in item and not ("lat" in item and item['lat']): - continue - cls = None - dct = {'origin':"%s" % (item['link'], - self.importer_instance.origin), - 'license':self.importer_instance.license, - 'name':item['name']} - category = None - if 'category' in item and item['category']: - if item['category'] in key_categories: - category = key_categories[item['category']] - else: - missing_cats.add(item['category']) - cls = Marker - if 'point' in item: - x, y = item['point'].split(",") - dct['point'] = 'SRID=4326;POINT(%s %s)' % (x, y) - elif 'lat' in item and item['lat']: - dct['point'] = 'SRID=4326;POINT(%s %s)' % (item['lon'], - item['lat']) - else: - dct['point'] = self.importer_instance.default_localisation - dct['description'] = item['description'] - if 'date' in item: - has_dates = False - for locale in DATE_PARSINGS: - if has_dates: - break - for r in DATE_PARSINGS[locale]: - m = r.search(item['date']) - if not m: - continue - has_dates = True - values = m.groupdict() - year1 = datetime.date.today().year if 'year1' not in values \ - else int(values['year1']) - dct['start_date'] = datetime.date(year1, - MONTH_NAMES[locale].index(values['month1'].encode('utf-8')) + 1, - int(values['day1'])) - if 'day2' not in values: - break - year2 = datetime.date.today().year if 'year2' not in values \ - else int(values['year2']) - dct['end_date'] = datetime.date(year2, - MONTH_NAMES[locale].index(values['month2'].encode('utf-8')) + 1, - int(values['day2'])) - break - key = item['key'] - it, updated, created = self.create_or_update_item(cls, dct, key, - category=category) - if updated: - updated_item += 1 - if created: - new_item += 1 + self.add_dct_item(item) msg = '' - if missing_cats: + if self.missing_cats: msg = _(u"Names \"%s\" doesn't match existing categories. " u"Modify the import to match theses names with categories.") % ( - u'", "'.join(missing_cats)) - return (new_item, updated_item, msg) + u'", "'.join(self.missing_cats)) + return (self.new_item, self.updated_item, msg) + + def parse_date(self, date): + dct = {} + has_dates = False + for locale in DATE_PARSINGS: + if has_dates: + break + for r in DATE_PARSINGS[locale]: + m = r.search(date) + if not m: + continue + has_dates = True + values = m.groupdict() + year1 = datetime.date.today().year if 'year1' not in values \ + else int(values['year1']) + dct['start_date'] = datetime.date(year1, + MONTH_NAMES[locale].index(values['month1'].encode('utf-8') + ) + 1, + int(values['day1'])) + if 'day2' not in values: + break + year2 = datetime.date.today().year if 'year2' not in values \ + else int(values['year2']) + dct['end_date'] = datetime.date(year2, + MONTH_NAMES[locale].index(values['month2'].encode('utf-8') + ) + 1, + int(values['day2'])) + break + return dct + + def add_dct_item(self, item): + if not self.importer_instance.default_localisation and \ + not "point" in item and not ("lat" in item and item['lat']): + return + cls = None + dct = {'origin':"%s" % (item['link'], + self.importer_instance.origin), + 'license':self.importer_instance.license, + 'name':item['name']} + category = None + if 'category' in item and item['category']: + if item['category'] in self.key_categories: + category = self.key_categories[item['category']] + else: + self.missing_cats.add(item['category']) + cls = self.marker_cls + if 'point' in item: + x, y = item['point'].split(",") + dct['point'] = 'SRID=4326;POINT(%s %s)' % (x, y) + elif 'lat' in item and item['lat']: + dct['point'] = 'SRID=4326;POINT(%s %s)' % (item['lon'], + item['lat']) + else: + dct['point'] = self.importer_instance.default_localisation + dct['description'] = item['description'] + if 'date' in item: + dct.update(self.parse_date(item['date'])) + key = item['key'] + it, updated, created = self.create_or_update_item(cls, dct, key, + category=category) + if updated: + self.updated_item += 1 + if created: + self.new_item += 1 class XMLXsltManager(HtmlXsltManager): PARSER = 'XMLParser' -- cgit v1.2.3 From 0a995754f9b62bc6ce74e6a09f5820f7067f1926 Mon Sep 17 00:00:00 2001 From: Étienne Loks Date: Sat, 14 Feb 2015 13:53:25 +0100 Subject: Add missing files for tests --- chimere/tests/magny-xml.xslt | 21 ++++++++ chimere/tests/magny.xml | 123 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 chimere/tests/magny-xml.xslt create mode 100644 chimere/tests/magny.xml diff --git a/chimere/tests/magny-xml.xslt b/chimere/tests/magny-xml.xslt new file mode 100644 index 0000000..1da9212 --- /dev/null +++ b/chimere/tests/magny-xml.xslt @@ -0,0 +1,21 @@ + + + + + + + + + Magny-les-hameaux : + + + + magny-les-hameaux- + + + + + + + + diff --git a/chimere/tests/magny.xml b/chimere/tests/magny.xml new file mode 100644 index 0000000..47304f9 --- /dev/null +++ b/chimere/tests/magny.xml @@ -0,0 +1,123 @@ + + + + Cirque - Mime + Le cirque Plume pour les seniors + 2015-02-01T15:00:00 + + Le service seniors organise une sortie pour découvrir ou re-découvrir le cirque Plume, au Théâtre de St-Quentin-en-Yvelines. Il souffle, cette année, ses 30 bougies. Trente ans d’envolées oniriques, acrobatiques et musicales. Trente ans de triomphes. Un réjouissant spectacle de grâce, poésie et magie. + http://www.magny-les-hameaux.fr/node/3187 + + + + + Environnement + Journée de chasse + 2015-02-03T08:00:00 + + L’ONF nous informe que des journées de chasse sont organisées de novembre à février dans les Forêts domaniales de Port-Royal/Trappes et Port-Royal/Mérantais.<br />La chasse est pratiquée chaque année en forêt domaniale. Elle permet de réguler les populations de sangliers et de chevreuils et contribue ainsi à la conservation des écosystèmes forestiers.<br /> + http://www.magny-les-hameaux.fr/node/3038 + + + + + Exposition + Exposition « Agir pour l’Avenir » + 2015-02-04T09:00:00 » 2015-02-28T17:00:00 + + Souvenez-vous en classe, derrière vous… il y avait sûrement des planches pédagogiques de la maison Deyrolle… + + Depuis 2007, la Maison Deyrolle relance l’édition de nouvelles planches pédagogiques sur le développement durable, sous le nom de « Agir pour l’Avenir », qui abordent les enjeux environnementaux et sociétaux contemporains. + http://www.magny-les-hameaux.fr/node/3240 + + + + + Jeune public + Les après-midis « contes » à la médiathèque Jacques Brel + 2015-02-04T14:30:00 + + Le centre social Albert Schweitzer vous invite à venir participer à des après-midis au cours desquels papa ou maman pourra passer un agréable moment avec son enfant à la Médiathèque Jacques Brel. + + Mercredis 7 janvier, 4 et 18 février, 11 et 25 mars 2015 + + Rendez-vous à l’accueil du Centre Social + http://www.magny-les-hameaux.fr/node/3168 + + + + + Événement + Café du jeudi 2015 + 2015-02-05T08:00:00 + + Les Cafés du Jeudi vous accueillent à Magny les Hameaux, deux fois par mois, le jeudi matin de 9 heures à 11h30, au pôle associatif Blaise Pascal, salle Coluche. + + Il s’agit d’un moment échanges autour des passions et centres d'intérêt des participants : collections, histoire de Magny, lecture, cuisine, jardin, … mais aussi de vos préoccupations du moment. + http://www.magny-les-hameaux.fr/node/3139 + + + + + Atelier + Atelier informatique : coup de pouce pour les demandeurs d’emploi + 2015-02-05T08:30:00 + + Vous êtes à la recherche d’un emploi, d’un stage ou d’une formation et vous ne maîtrisez pas les outils informatiques ? Sachez que le service Emploi de la Ville et le CIDFF (Centre d’information du droit des femmes) organisent, tous les jeudis, des ateliers d’initiation pour vous apprendre le B.A.BA de l’informatique : WORD, EXCEL, la navigation Internet, l’envoi de mails… + + http://www.magny-les-hameaux.fr/node/3179 + + + + + Atelier + SOS informatique : Internet ! C’est facile ! + 2015-02-05T15:00:00 + + Les médiathèques étendent leurs propositions d’accompagnement dans les domaines du numérique pour vous aider dans votre pratique quotidienne, l’emploi, l’aide aux devoirs et les réseaux sociaux. + + http://www.magny-les-hameaux.fr/node/3175 + 48.722817 + 2.094394 + + + Conférence + Semaine de l'emploi + 2015-02-06T09:00:00 » 2015-02-14T16:00:00 + + La Communauté d’agglomération de Saint-Quentin-en-Yvelines et ses partenaires se mobilisent et organisent du 6 au 14 février la 19èmeSemaine de l’emploi. + + Objectif : créer localement des lieux de rencontre entre les entreprises et un public en découverte d’un métier ou en recherche d’emploi. + + Vous êtes à la recherche d’un emploi ?<br /> + Vous aimeriez être accompagné dans votre parcours professionnel ?<br /> + Vous souhaitez découvrir les métiers de demain ?<br /> + De nombreux événements sont organisés pour vous : découvrez le programme, munissez-vous de vos CV et rendez-vous sur l’une des manifestations organisées pour vous ! + + http://www.magny-les-hameaux.fr/node/3258 + + + + + Événement + Collecte de denrées alimentaires + 2015-02-07T08:00:00 + + Le secours populaire organise une collecte alimentaire dans la galerie marchande de votre Intermarché, les samedis suivants :  + + http://www.magny-les-hameaux.fr/node/3241 + + + + + Événement + Commerce équitable + 2015-02-07T09:00:00 » 2015-02-07T11:30:00 + + L'association Les Amis de l'Estaminet et de la Culture vous propose de venir acheter des produits d'artisans du monde (bijoux, alimentation, produits de beauté, vêtements...), une fois par mois. Cette action est liée à une action humanitaire. + + http://www.magny-les-hameaux.fr/node/3004 + + + + -- cgit v1.2.3 From afbcd9cf0578f70ac25afac0199446a43d317b52 Mon Sep 17 00:00:00 2001 From: Étienne Loks Date: Sat, 14 Feb 2015 14:32:44 +0100 Subject: XSLT imports: better date management - refactoring - manage date ISO format --- chimere/utils.py | 80 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 15 deletions(-) diff --git a/chimere/utils.py b/chimere/utils.py index ba5e558..55fc45c 100644 --- a/chimere/utils.py +++ b/chimere/utils.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Copyright (C) 2012-2013 Étienne Loks +# Copyright (C) 2012-2015 Étienne Loks # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as @@ -879,7 +879,35 @@ DATE_PARSINGS = {'fr_FR':[ re.compile(r'(?P\d{1,2}) '\ r'(?P'+ '|'.join(UNI_MONTH_NAMES['fr_FR']) +') *'\ r'(?P\d{4})?') - ] + ], + 'en':[ + re.compile(r'(?P\d{4})-'\ + r'(?P\d{2})-'\ + r'(?P\d{2})'\ + r'(?:T'\ + r'(?P\d{2})?:'\ + r'(?P\d{2})?:'\ + r'(?P\d{2})'\ + r')?.*'\ + r'(?P\d{4})-'\ + r'(?P\d{2})-'\ + r'(?P\d{2})'\ + r'(?:T'\ + r'(?P\d{2})?:'\ + r'(?P\d{2})?:'\ + r'(?P\d{2})'\ + r')?.*' + ), + re.compile(r'(?P\d{4})-'\ + r'(?P\d{2})-'\ + r'(?P\d{2})'\ + r'(?:T'\ + r'(?P\d{2})?:'\ + r'(?P\d{2})?:'\ + r'(?P\d{2})'\ + r')?' + ) + ], } def clean_field(value): @@ -979,6 +1007,29 @@ class HtmlXsltManager(ImportManager): u'", "'.join(self.missing_cats)) return (self.new_item, self.updated_item, msg) + @classmethod + def _internal_parse_date(cls, locale, year, month, day): + try: + year = datetime.date.today().year if not year else int(year) + except ValueError: + return + month = month.encode('utf-8') + if locale in MONTH_NAMES and month in MONTH_NAMES[locale]: + month = MONTH_NAMES[locale].index(month) + 1 + else: + try: + month = int(month) + except ValueError: + return + try: + day = int(day) + except ValueError: + return + try: + return datetime.date(year, month, day) + except ValueError: + return + def parse_date(self, date): dct = {} has_dates = False @@ -989,22 +1040,21 @@ class HtmlXsltManager(ImportManager): m = r.search(date) if not m: continue - has_dates = True values = m.groupdict() - year1 = datetime.date.today().year if 'year1' not in values \ - else int(values['year1']) - dct['start_date'] = datetime.date(year1, - MONTH_NAMES[locale].index(values['month1'].encode('utf-8') - ) + 1, - int(values['day1'])) + date = self._internal_parse_date(locale, + 'year1' in values and values['year1'], + values['month1'], values['day1']) + if not date: + continue + dct['start_date'] = date + has_dates = True if 'day2' not in values: break - year2 = datetime.date.today().year if 'year2' not in values \ - else int(values['year2']) - dct['end_date'] = datetime.date(year2, - MONTH_NAMES[locale].index(values['month2'].encode('utf-8') - ) + 1, - int(values['day2'])) + date = self._internal_parse_date(locale, + 'year2' in values and values['year2'], + values['month2'], values['day2']) + if date: + dct['end_date'] = date break return dct -- cgit v1.2.3