From c5d409e7c38cd5dd5686ce2311928587796349f9 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Tue, 12 Sep 2017 21:32:35 +0200 Subject: Lecture du contenu de la réponse avec r.content et non r.text pour limiter les problèmes --- management/commands/_private.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'management/commands/_private.py') diff --git a/management/commands/_private.py b/management/commands/_private.py index 17896c4..2b57599 100644 --- a/management/commands/_private.py +++ b/management/commands/_private.py @@ -159,5 +159,5 @@ def get_xml(url): r = requests.get(url) r.encoding = "utf8" - soup = BeautifulSoup(r.text, "html.parser") + soup = BeautifulSoup(r.content, "html.parser") return soup -- cgit v1.2.1 From 32bd236f2c53bc8dfd515018a7ae0ec06f65c115 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sun, 10 Sep 2017 11:54:38 +0200 Subject: La consolidation a lieu pour le parent d’un groupe mais aussi ses enfants --- management/commands/_private.py | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) (limited to 'management/commands/_private.py') diff --git a/management/commands/_private.py b/management/commands/_private.py index 2b57599..c140f51 100644 --- a/management/commands/_private.py +++ b/management/commands/_private.py @@ -45,19 +45,34 @@ def add_time(date, time): def consolidate_group(group): group_content_key = ("mention", "subgroup", "td", "tp") group_content_list = group.group_info[1:] - group_content = dict(zip(group_content_key, group_content_list)) - for i in range(len(group_content_list))[::-1]: - del group_content[group_content_key[i]] - group_content[group_content_key[i] + "__isnull"] = True + if group.subgroup is not None: + group_content = dict(zip(group_content_key, group_content_list)) - if group_content_list[i] is not None: - break + for i in range(len(group_content_list))[::-1]: + del group_content[group_content_key[i]] + group_content[group_content_key[i] + "__isnull"] = True - if "subgroup" in group_content: - group.parent = Group.objects.filter(**group_content).first() + if group_content_list[i] is not None: + break + + group.parent = Group.objects.filter(timetable=group.timetable, + **group_content).first() group.save() + if group.tp is None: + group_content = dict(zip(group_content_key, group_content_list)) + last_is_none = False + + for i, key in enumerate(group_content_key): + if group_content_list[i] is None or last_is_none: + del group_content[key] + group_content[key + "__isnull"] = last_is_none + last_is_none = True + + Group.objects.filter(timetable=group.timetable, parent__isnull=True, + **group_content).update(parent=group) + def consolidate_groups(groups): for group in groups: if group.parent == None: -- cgit v1.2.1 From aa7ccf13a8735f162e2ea859ad1d8ebe9f34f657 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Mon, 25 Sep 2017 16:08:01 +0200 Subject: Utilisation de pylint pour améliorer la qualité du code --- management/commands/_private.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'management/commands/_private.py') diff --git a/management/commands/_private.py b/management/commands/_private.py index c140f51..2d01e67 100644 --- a/management/commands/_private.py +++ b/management/commands/_private.py @@ -13,15 +13,15 @@ # You should have received a copy of the GNU Affero General Public License # along with celcatsanitizer. If not, see . +import datetime +import re + from bs4 import BeautifulSoup from django.utils import timezone from edt.models import Group, Room, Course from edt.utils import get_week -import datetime -import re - import requests @@ -31,8 +31,8 @@ class Week: self.start = timezone.make_aware( datetime.datetime.strptime(start, "%d/%m/%Y")) - def get_day(self, id): - return self.start + datetime.timedelta(id) + def get_day(self, day_id): + return self.start + datetime.timedelta(day_id) @property def year(self): @@ -75,7 +75,7 @@ def consolidate_group(group): def consolidate_groups(groups): for group in groups: - if group.parent == None: + if group.parent is None: consolidate_group(group) def delete_courses_in_week(timetable, year, week): @@ -153,7 +153,7 @@ def get_update_date(soup): # (\d+) au moins un nombre # : un deux-points # (\d+) au moins un nombre - datetime_regex = re.compile("(\d+)/(\d+)/(\d+)\s+(\d+):(\d+):(\d+)") + datetime_regex = re.compile(r"(\d+)/(\d+)/(\d+)\s+(\d+):(\d+):(\d+)") search = datetime_regex.search(soup.footer.text) if search is None: return None @@ -171,8 +171,8 @@ def get_weeks(soup): return weeks def get_xml(url): - r = requests.get(url) - r.encoding = "utf8" + req = requests.get(url) + req.encoding = "utf8" - soup = BeautifulSoup(r.content, "html.parser") + soup = BeautifulSoup(req.content, "html.parser") return soup -- cgit v1.2.1 From a8d35aee63f073674993b8afde78a8d5c1517e05 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Fri, 29 Sep 2017 21:19:01 +0200 Subject: get_events() renvoie des objets Course au lieu d’un tuple de données. Ajout de commentaires dans la fonction get_events() Les paramètres year et week des fonctions get_events(), process_timetable_week() et process_timetable() sont maintenant optionnels. --- management/commands/_private.py | 59 ++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 21 deletions(-) (limited to 'management/commands/_private.py') diff --git a/management/commands/_private.py b/management/commands/_private.py index 2d01e67..e018e3a 100644 --- a/management/commands/_private.py +++ b/management/commands/_private.py @@ -93,50 +93,67 @@ def get_from_db_or_create(cls, **kwargs): return obj -def get_events(timetable, year, week, soup, weeks_in_soup): +def get_events(timetable, soup, weeks_in_soup, year=None, week=None): + """Récupère tous les cours disponibles dans l’emploi du temps Celcat. + Le traîtement se limitera à la semaine indiquée si il y en a une.""" for event in soup.find_all("event"): - title = None - type_ = None - groups = None - rooms = None - notes = None - - if weeks_in_soup[event.rawweeks.text].number == week and \ - weeks_in_soup[event.rawweeks.text].year == year and \ + event_week = weeks_in_soup[event.rawweeks.text] + + # On passe le traitement si la semaine de l’événement ne correspond pas + # à la semaine passée, ou qu’il ne contient pas de groupe ou n’a pas de + # date de début ou de fin. + if (event_week.number == week and event_week.year == year or \ + year is None or week is None) and \ event.resources.group is not None and \ event.starttime is not None and event.endtime is not None: - date = weeks_in_soup[event.rawweeks.text].get_day(int( - event.day.text)) - + # On récupère la date de l’évènement à partir de la semaine + # et de la semaine référencée, puis la date de début et de fin + date = event_week.get_day(int(event.day.text)) begin = add_time(date, datetime.datetime.strptime( event.starttime.text, "%H:%M")) end = add_time(date, datetime.datetime.strptime( event.endtime.text, "%H:%M")) + # Création de l’objet cours + course = Course.objects.create(timetable=timetable, begin=begin, + end=end) + + # On récupère les groupes concernés par les cours, on les + # « consolide », puis on les insère dans l’objet cours. groups = [get_from_db_or_create(Group, timetable=timetable, celcat_name=item.text) for item in event.resources.group.find_all("item")] consolidate_groups(groups) + course.groups.add(*groups) + # On récupère le champ « remarque » if event.notes is not None: - notes = event.notes.text + course.notes = event.notes.text + # On récupère le nom du cours if event.resources.module is not None: - title = event.resources.module.item.text - elif notes is not None: - title = notes - notes = None + course.name = event.resources.module.item.text else: - title = "Aucune information" - + # Il est possible qu’un cours n’ait pas de nom. Oui oui. + # Qui sont les concepteurs de ce système ? Quels sont leurs + # réseaux ? + # Bref, dans ce cas, on déplace le champ « remarque » de + # l’objet dans le champ « nom ». + course.name, course.notes = course.notes, None + + # Récupération du type de cours if event.category is not None: - type_ = event.category.text + course.type = event.category.text + # Si un cours a une salle attribuée (oui, il est possible qu’il n’y + # en ait pas… qui sont ils, leurs réseaux, tout ça…), on les insère + # dans la base de données, et on les ajoute dans l’objet cours if event.resources.room is not None: rooms = [get_from_db_or_create(Room, name=item.text) for item in event.resources.room.find_all("item")] + course.rooms.add(*rooms) - yield title, type_, groups, rooms, notes, begin, end + yield course def get_update_date(soup): # Explication de la regex -- cgit v1.2.1 From bc2c2cae1fd6a52fb17771b4b537e07bca103987 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Fri, 29 Sep 2017 22:09:51 +0200 Subject: Suppression de la classe Week \o/ --- management/commands/_private.py | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) (limited to 'management/commands/_private.py') diff --git a/management/commands/_private.py b/management/commands/_private.py index e018e3a..0b26b4e 100644 --- a/management/commands/_private.py +++ b/management/commands/_private.py @@ -24,22 +24,9 @@ from edt.utils import get_week import requests - -class Week: - def __init__(self, number, start): - self.number = number - self.start = timezone.make_aware( - datetime.datetime.strptime(start, "%d/%m/%Y")) - - def get_day(self, day_id): - return self.start + datetime.timedelta(day_id) - - @property - def year(self): - return self.start.year - def add_time(date, time): - delta = datetime.timedelta(hours=time.hour, minutes=time.minute) + ptime = datetime.datetime.strptime(time, "%H:%M") + delta = datetime.timedelta(hours=ptime.hour, minutes=ptime.minute) return date + delta def consolidate_group(group): @@ -98,21 +85,20 @@ def get_events(timetable, soup, weeks_in_soup, year=None, week=None): Le traîtement se limitera à la semaine indiquée si il y en a une.""" for event in soup.find_all("event"): event_week = weeks_in_soup[event.rawweeks.text] + event_week_num = event_week.isocalendar()[1] # Numéro de semaine # On passe le traitement si la semaine de l’événement ne correspond pas # à la semaine passée, ou qu’il ne contient pas de groupe ou n’a pas de # date de début ou de fin. - if (event_week.number == week and event_week.year == year or \ + if (event_week_num == week and event_week.year == year or \ year is None or week is None) and \ event.resources.group is not None and \ event.starttime is not None and event.endtime is not None: # On récupère la date de l’évènement à partir de la semaine - # et de la semaine référencée, puis la date de début et de fin - date = event_week.get_day(int(event.day.text)) - begin = add_time(date, datetime.datetime.strptime( - event.starttime.text, "%H:%M")) - end = add_time(date, datetime.datetime.strptime( - event.endtime.text, "%H:%M")) + # et de la semaine référencée, puis l’heure de début et de fin + date = event_week + datetime.timedelta(int(event.day.text)) + begin = add_time(date, event.starttime.text) + end = add_time(date, event.endtime.text) # Création de l’objet cours course = Course.objects.create(timetable=timetable, begin=begin, @@ -182,8 +168,8 @@ def get_update_date(soup): def get_weeks(soup): weeks = {} for span in soup.find_all("span"): - weeks[span.alleventweeks.text] = Week(int(span.title.text), - span["date"]) + weeks[span.alleventweeks.text] = timezone.make_aware( + datetime.datetime.strptime(span["date"], "%d/%m/%Y")) return weeks -- cgit v1.2.1 From a796926c1d1e4ea19d1de205678be638fbfe8c06 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sat, 30 Sep 2017 11:51:54 +0200 Subject: Déplacement de la logique de création de l’objet Course dans sa propre fonction --- management/commands/_private.py | 95 +++++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 46 deletions(-) (limited to 'management/commands/_private.py') diff --git a/management/commands/_private.py b/management/commands/_private.py index 0b26b4e..23083e1 100644 --- a/management/commands/_private.py +++ b/management/commands/_private.py @@ -80,6 +80,54 @@ def get_from_db_or_create(cls, **kwargs): return obj +def get_event(timetable, event, event_week): + """Renvoie une classe Course à partir d’un événement récupéré par BS4""" + # On récupère la date de l’évènement à partir de la semaine + # et de la semaine référencée, puis l’heure de début et de fin + date = event_week + datetime.timedelta(int(event.day.text)) + begin = add_time(date, event.starttime.text) + end = add_time(date, event.endtime.text) + + # Création de l’objet cours + course = Course.objects.create(timetable=timetable, begin=begin, end=end) + + # On récupère les groupes concernés par les cours, on les + # « consolide », puis on les insère dans l’objet cours. + groups = [get_from_db_or_create(Group, timetable=timetable, + celcat_name=item.text) + for item in event.resources.group.find_all("item")] + consolidate_groups(groups) + course.groups.add(*groups) + + # On récupère le champ « remarque » + if event.notes is not None: + course.notes = event.notes.text + + # On récupère le nom du cours + if event.resources.module is not None: + course.name = event.resources.module.item.text + else: + # Il est possible qu’un cours n’ait pas de nom. Oui oui. + # Qui sont les concepteurs de ce système ? Quels sont leurs + # réseaux ? + # Bref, dans ce cas, on déplace le champ « remarque » de + # l’objet dans le champ « nom ». + course.name, course.notes = course.notes, None + + # Récupération du type de cours + if event.category is not None: + course.type = event.category.text + + # Si un cours a une salle attribuée (oui, il est possible qu’il n’y + # en ait pas… qui sont ils, leurs réseaux, tout ça…), on les insère + # dans la base de données, et on les ajoute dans l’objet cours + if event.resources.room is not None: + rooms = [get_from_db_or_create(Room, name=item.text) + for item in event.resources.room.find_all("item")] + course.rooms.add(*rooms) + + return course + def get_events(timetable, soup, weeks_in_soup, year=None, week=None): """Récupère tous les cours disponibles dans l’emploi du temps Celcat. Le traîtement se limitera à la semaine indiquée si il y en a une.""" @@ -94,52 +142,7 @@ def get_events(timetable, soup, weeks_in_soup, year=None, week=None): year is None or week is None) and \ event.resources.group is not None and \ event.starttime is not None and event.endtime is not None: - # On récupère la date de l’évènement à partir de la semaine - # et de la semaine référencée, puis l’heure de début et de fin - date = event_week + datetime.timedelta(int(event.day.text)) - begin = add_time(date, event.starttime.text) - end = add_time(date, event.endtime.text) - - # Création de l’objet cours - course = Course.objects.create(timetable=timetable, begin=begin, - end=end) - - # On récupère les groupes concernés par les cours, on les - # « consolide », puis on les insère dans l’objet cours. - groups = [get_from_db_or_create(Group, timetable=timetable, - celcat_name=item.text) - for item in event.resources.group.find_all("item")] - consolidate_groups(groups) - course.groups.add(*groups) - - # On récupère le champ « remarque » - if event.notes is not None: - course.notes = event.notes.text - - # On récupère le nom du cours - if event.resources.module is not None: - course.name = event.resources.module.item.text - else: - # Il est possible qu’un cours n’ait pas de nom. Oui oui. - # Qui sont les concepteurs de ce système ? Quels sont leurs - # réseaux ? - # Bref, dans ce cas, on déplace le champ « remarque » de - # l’objet dans le champ « nom ». - course.name, course.notes = course.notes, None - - # Récupération du type de cours - if event.category is not None: - course.type = event.category.text - - # Si un cours a une salle attribuée (oui, il est possible qu’il n’y - # en ait pas… qui sont ils, leurs réseaux, tout ça…), on les insère - # dans la base de données, et on les ajoute dans l’objet cours - if event.resources.room is not None: - rooms = [get_from_db_or_create(Room, name=item.text) - for item in event.resources.room.find_all("item")] - course.rooms.add(*rooms) - - yield course + yield get_event(timetable, event, event_week) def get_update_date(soup): # Explication de la regex -- cgit v1.2.1 From 45402cbdab2dfdbd9e2f72c70d27f966f932789b Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sat, 30 Sep 2017 12:20:48 +0200 Subject: Ajout de commentaires à la fonction get_weeks() --- management/commands/_private.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'management/commands/_private.py') diff --git a/management/commands/_private.py b/management/commands/_private.py index 23083e1..8f195a1 100644 --- a/management/commands/_private.py +++ b/management/commands/_private.py @@ -169,8 +169,18 @@ def get_update_date(soup): return timezone.make_aware(date) def get_weeks(soup): + # Les semaines sont référencées de manière assez… exotique + # En gros, il y a une liste d’éléments span qui contiennent une sorte d’ID + # de la semaine, formaté de la manière suivante : + # NNNNNNNNNNNNNNNNNNNYNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN + # Tous sont de la même longueur, contiennent 51 N et un seul Y. + # Allez savoir pourquoi. Il se trouve dans la balise « alleventweeks ». + # Un paramètre du span (« date ») représente la date de début. + # Un cours contient donc un ID de semaine, puis le nombre de jours après le + # début de cette semaine. weeks = {} - for span in soup.find_all("span"): + for span in soup.find_all("span"): # Liste de toutes les semaines définies + # On parse la date et on la fait correspondre à l’ID weeks[span.alleventweeks.text] = timezone.make_aware( datetime.datetime.strptime(span["date"], "%d/%m/%Y")) -- cgit v1.2.1