aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--admin.py5
-rw-r--r--forms.py9
-rw-r--r--management/commands/_private.py14
-rw-r--r--management/commands/cleancourses.py3
-rw-r--r--management/commands/listtimetables.py5
-rw-r--r--management/commands/timetables.py65
-rw-r--r--models.py37
-rw-r--r--templatetags/dt_week.py2
-rw-r--r--templatetags/rooms.py4
-rw-r--r--tests.py99
-rw-r--r--utils.py9
11 files changed, 164 insertions, 88 deletions
diff --git a/admin.py b/admin.py
index 5af6cb1..dcac794 100644
--- a/admin.py
+++ b/admin.py
@@ -16,10 +16,12 @@
from django.contrib import admin
from .models import Course, Group, Room, Source, Timetable, Year
+
def make_hidden(modeladmin, request, queryset):
queryset.update(hidden=True)
make_hidden.short_description = "Cacher les groupes sélectionnés"
+
def make_visible(modeladmin, request, queryset):
queryset.update(hidden=False)
make_visible.short_description = "Afficher les groupes sélectionnés"
@@ -66,7 +68,8 @@ class RoomAdmin(admin.ModelAdmin):
@admin.register(Course)
class CourseAdmin(admin.ModelAdmin):
fieldsets = (
- (None, {"fields": ("name", "type", "source", "groups", "rooms", "last_update",)}),
+ (None, {"fields": ("name", "type", "source", "groups", "rooms",
+ "last_update",)}),
("Horaires", {"fields": ("begin", "end",)}),
("Remarques", {"fields": ("notes",)}),)
list_display = ("name", "type", "source", "begin", "end",)
diff --git a/forms.py b/forms.py
index 5e76bc1..00dbf9e 100644
--- a/forms.py
+++ b/forms.py
@@ -22,7 +22,8 @@ from .utils import tz_now
class QSJPSForm(forms.Form):
- day = forms.DateField(label="Jour", widget=DateInput(attrs={"type": "date"}))
+ day = forms.DateField(label="Jour",
+ widget=DateInput(attrs={"type": "date"}))
# Ces champs n’acceptent pas les secondes
begin = forms.TimeField(label="Heure de début", input_formats=("%H:%M",),
@@ -38,7 +39,8 @@ class QSJPSForm(forms.Form):
# heures de début et de fin.
self.fields["day"].initial = tz_now().strftime("%Y-%m-%d")
self.fields["begin"].initial = tz_now().strftime("%H:%M")
- self.fields["end"].initial = (tz_now() + timedelta(hours=1)).strftime("%H:%M")
+ self.fields["end"].initial = (tz_now() + timedelta(hours=1)) \
+ .strftime("%H:%M")
def clean(self):
form_data = self.cleaned_data
@@ -51,5 +53,6 @@ class QSJPSForm(forms.Form):
form_data["begin"] >= form_data["end"]:
# Si l’heure de fin est plus petite ou égale, on affiche
# une erreur.
- self._errors["end"].append("L’heure de début doit être supérieure à celle de fin.")
+ self._errors["end"].append("L’heure de début doit être supérieure "
+ "à celle de fin.")
return form_data
diff --git a/management/commands/_private.py b/management/commands/_private.py
index e78c3c2..bac749b 100644
--- a/management/commands/_private.py
+++ b/management/commands/_private.py
@@ -25,16 +25,19 @@ from edt.utils import get_week
import requests
import edt
+
def add_time(date, time):
ptime = datetime.datetime.strptime(time, "%H:%M")
delta = datetime.timedelta(hours=ptime.hour, minutes=ptime.minute)
return date + delta
+
def delete_courses_in_week(source, year, week, today):
start, end = get_week(year, week)
Course.objects.filter(begin__gte=max(start, today), begin__lt=end,
source=source).delete()
+
def get_from_db_or_create(cls, **kwargs):
obj = cls.objects.all().filter(**kwargs)
@@ -45,6 +48,7 @@ def get_from_db_or_create(cls, **kwargs):
return obj
+
def get_event(source, event, event_week, today):
"""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
@@ -96,17 +100,18 @@ def get_event(source, event, event_week, today):
return course
+
def get_events(source, soup, weeks_in_soup, today, 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"):
event_week = weeks_in_soup[event.rawweeks.text]
- event_week_num = event_week.isocalendar()[1] # Numéro de semaine
+ 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_num == 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:
@@ -116,6 +121,7 @@ def get_events(source, soup, weeks_in_soup, today, year=None, week=None):
if course is not None:
yield course
+
def get_update_date(soup):
# Explication de la regex
#
@@ -140,6 +146,7 @@ def get_update_date(soup):
date = datetime.datetime(year, month, day, hour, minute, second)
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
@@ -151,13 +158,14 @@ def get_weeks(soup):
# 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"): # Liste de toutes les semaines définies
+ 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"))
return weeks
+
def get_xml(url):
user_agent = "celcatsanitizer/" + edt.VERSION
req = requests.get(url, headers={"User-Agent": user_agent})
diff --git a/management/commands/cleancourses.py b/management/commands/cleancourses.py
index 310c843..88eec64 100644
--- a/management/commands/cleancourses.py
+++ b/management/commands/cleancourses.py
@@ -30,7 +30,8 @@ class Command(BaseCommand):
Course.objects.all().delete()
Group.objects.all().delete()
else:
- Course.objects.filter(source__id__in=options["source"]).delete()
+ Course.objects.filter(source__id__in=options["source"]) \
+ .delete()
Group.objects.filter(source__id__in=options["source"]).delete()
self.stdout.write(self.style.SUCCESS("Done."))
diff --git a/management/commands/listtimetables.py b/management/commands/listtimetables.py
index 25f641b..7892855 100644
--- a/management/commands/listtimetables.py
+++ b/management/commands/listtimetables.py
@@ -29,8 +29,9 @@ class Command(BaseCommand):
sources = sources.order_by("id")
for source in sources:
- self.stdout.write("{0}\t: {1} (id: {2})".format(source.formatted_timetables,
- source, source.id))
+ self.stdout.write("{0}\t: {1} (id: {2})"
+ .format(source.formatted_timetables,
+ source, source.id))
self.stdout.write("")
self.stdout.write(self.style.SUCCESS("Done."))
diff --git a/management/commands/timetables.py b/management/commands/timetables.py
index 86f389e..cf48af6 100644
--- a/management/commands/timetables.py
+++ b/management/commands/timetables.py
@@ -22,10 +22,13 @@ from django.db.models import Min
from edt.models import Course, Source
from edt.utils import get_week, tz_now
-from ._private import delete_courses_in_week, get_events, get_update_date, get_weeks, get_xml
+from ._private import delete_courses_in_week, get_events, get_update_date, \
+ get_weeks, get_xml
+
@transaction.atomic
-def process_timetable_week(source, soup, weeks_in_soup, force, year=None, week=None):
+def process_timetable_week(source, soup, weeks_in_soup, force,
+ year=None, week=None):
if year is not None and week is not None:
begin, end = get_week(year, week)
@@ -40,32 +43,34 @@ def process_timetable_week(source, soup, weeks_in_soup, force, year=None, week=N
else:
today = tz_now()
- # On récupère la mise à jour la plus ancienne dans les cours de l’emploi du temps
+ # On récupère la mise à jour la plus ancienne dans les cours de
+ # l’emploi du temps
last_update_date = Course.objects.filter(source=source)
if today is not None:
- # Cette date concerne les éléments commençant à partir d’aujourd’hui si la valeur
- # n’est pas nulle.
+ # Cette date concerne les éléments commençant à partir
+ # d’aujourd’hui si la valeur n’est pas nulle.
last_update_date = last_update_date.filter(begin__gte=today)
if year is not None and week is not None:
- # Si jamais on traite une semaine spécifique, on limite les cours sélectionnés
- # à ceux qui commencent entre le début du traitement et la fin de la semaine
+ # Si jamais on traite une semaine spécifique, on limite les
+ # cours sélectionnés à ceux qui commencent entre le début du
+ # traitement et la fin de la semaine
last_update_date = last_update_date.filter(begin__lt=end)
- last_update_date = last_update_date.aggregate(Min("last_update")) \
- ["last_update__min"]
+ last_update_date = last_update_date \
+ .aggregate(Min("last_update"))["last_update__min"]
# Date de mise à jour de Celcat, utilisée à des fins de statistiques
new_update_date = get_update_date(soup)
- # On ne fait pas la mise à jour si jamais la dernière date de MàJ est plus récente
- # que celle indiquée par Celcat.
- # Attention, le champ last_update de la classe Course représente l’heure à laquelle
- # le cours a été inséré dans la base de données, et non pas la date indiquée par
- # Celcat.
- if not force and last_update_date is not None and new_update_date is not None and \
- last_update_date >= new_update_date:
+ # On ne fait pas la mise à jour si jamais la dernière date de MàJ
+ # est plus récente que celle indiquée par Celcat. Attention, le
+ # champ last_update de la classe Course représente l’heure à
+ # laquelle le cours a été inséré dans la base de données, et non
+ # pas la date indiquée par Celcat.
+ if not force and last_update_date is not None and \
+ new_update_date is not None and last_update_date >= new_update_date:
return
if year is not None and week is not None:
@@ -78,7 +83,8 @@ def process_timetable_week(source, soup, weeks_in_soup, force, year=None, week=N
# présente dans Celcat et maintenant.
delete_from = min(weeks_in_soup.values())
if not force:
- # Si jamais on force la MàJ, on efface tout à partir de la première semaine
+ # Si jamais on force la MàJ, on efface tout à partir de la
+ # première semaine
delete_from = max(delete_from, today)
Course.objects.filter(source=source, begin__gte=delete_from).delete()
@@ -91,13 +97,15 @@ def process_timetable_week(source, soup, weeks_in_soup, force, year=None, week=N
source.last_update_date = new_update_date
source.save()
+
def process_timetable(source, force, year=None, weeks=None):
soup = get_xml(source.url)
weeks_in_soup = get_weeks(soup)
if year is not None and weeks is not None:
for week in weeks:
- process_timetable_week(source, soup, weeks_in_soup, force, year, week)
+ process_timetable_week(source, soup, weeks_in_soup, force,
+ year, week)
else:
process_timetable_week(source, soup, weeks_in_soup, force)
@@ -106,9 +114,12 @@ class Command(BaseCommand):
help = "Fetches registered celcat timetables"
def add_arguments(self, parser):
- parser.add_argument("--all", const=True, default=False, action="store_const")
- parser.add_argument("--force", const=True, default=False, action="store_const")
- parser.add_argument("--week", type=int, choices=range(1, 54), nargs="+")
+ parser.add_argument("--all", const=True, default=False,
+ action="store_const")
+ parser.add_argument("--force", const=True, default=False,
+ action="store_const")
+ parser.add_argument("--week", type=int, choices=range(1, 54),
+ nargs="+")
parser.add_argument("--year", type=int, nargs=1)
def handle(self, *args, **options):
@@ -120,7 +131,8 @@ class Command(BaseCommand):
elif options["week"] is None:
_, week, day = tz_now().isocalendar()
if day >= 6:
- year, week, _ = (tz_now() + datetime.timedelta(weeks=1)).isocalendar()
+ year, week, _ = (tz_now() + datetime.timedelta(weeks=1)) \
+ .isocalendar()
weeks = [week]
else:
weeks = options["week"]
@@ -132,7 +144,8 @@ class Command(BaseCommand):
year = options["year"][0]
for source in Source.objects.all():
- self.stdout.write("Processing {0}".format(source.formatted_timetables))
+ self.stdout.write("Processing {0}".format(
+ source.formatted_timetables))
try:
process_timetable(source, options["force"], year, weeks)
@@ -140,7 +153,8 @@ class Command(BaseCommand):
break
except Exception:
self.stderr.write(
- self.style.ERROR("Failed to process {0}:".format(source.formatted_timetables))
+ self.style.ERROR("Failed to process {0}:".format(
+ source.formatted_timetables))
)
self.stderr.write(self.style.ERROR(traceback.format_exc()))
errcount += 1
@@ -148,4 +162,5 @@ class Command(BaseCommand):
if errcount == 0:
self.stdout.write(self.style.SUCCESS("Done."))
else:
- self.stdout.write(self.style.ERROR("Done with {0} errors.".format(errcount)))
+ self.stdout.write(self.style.ERROR("Done with {0} errors.".format(
+ errcount)))
diff --git a/models.py b/models.py
index 4903b11..60be95c 100644
--- a/models.py
+++ b/models.py
@@ -42,7 +42,6 @@ class Year(SlugModel):
def __str__(self):
return self.name
-
class Meta:
verbose_name = "année"
verbose_name_plural = "années"
@@ -50,16 +49,17 @@ class Year(SlugModel):
class Source(models.Model):
url = models.URLField(max_length=255, verbose_name="URL", unique=True)
- last_update_date = models.DateTimeField(verbose_name="dernière mise à jour Celcat",
- null=True, blank=True)
+ last_update_date = models.DateTimeField(null=True, blank=True,
+ verbose_name="dernière mise à jour"
+ "Celcat")
def __str__(self):
return self.url
@property
def formatted_timetables(self):
- return ", ".join([str(timetable) for timetable in self.timetables.iterator()])
-
+ return ", ".join([str(timetable) for timetable in
+ self.timetables.iterator()])
class Meta:
verbose_name = "source d’emploi du temps"
@@ -79,12 +79,12 @@ class Timetable(SlugModel):
name = models.CharField(max_length=64, verbose_name="nom")
slug = models.SlugField(max_length=64, default="")
source = models.ForeignKey(Source, on_delete=models.CASCADE,
- verbose_name="source", related_name="timetables")
+ verbose_name="source",
+ related_name="timetables")
def __str__(self):
return self.year.name + " " + self.name
-
class Meta:
unique_together = (("year", "name"), ("year", "slug"),)
verbose_name = "emploi du temps"
@@ -95,11 +95,12 @@ class GroupManager(Manager):
def get_parents(self, group):
groups_criteria = reduce(lambda x, y: x | y,
[Q(subgroup=group.subgroup[:i])
- for i in range(1, len(group.subgroup) + 1)],
+ for i in range(1, len(group.subgroup) + 1)],
Q(subgroup=""))
return self.get_queryset().filter(groups_criteria,
- Q(semester=None) | Q(semester=group.semester),
+ Q(semester=None) |
+ Q(semester=group.semester),
mention=group.mention,
source=group.source)
@@ -115,7 +116,8 @@ class Group(SlugModel):
mention = models.CharField(max_length=128)
semester = models.IntegerField(verbose_name="semestre", null=True)
- subgroup = models.CharField(max_length=16, verbose_name="sous-groupe", default="")
+ subgroup = models.CharField(max_length=16, verbose_name="sous-groupe",
+ default="")
slug = models.SlugField(max_length=64, default="")
@@ -126,10 +128,10 @@ class Group(SlugModel):
if self.subgroup is not None and subgroup is not None:
subgroup_corresponds = self.subgroup.startswith(subgroup)
- return (self.mention.startswith(mention) or \
+ return (self.mention.startswith(mention) or
mention.startswith(self.mention)) and \
- (self.semester == semester or semester is None) and \
- subgroup_corresponds
+ (self.semester == semester or semester is None) and \
+ subgroup_corresponds
@property
def group_info(self):
@@ -148,7 +150,6 @@ class Group(SlugModel):
super(Group, self).save()
-
class Meta:
index_together = ("mention", "semester", "subgroup",)
unique_together = (("name", "source",),
@@ -175,8 +176,8 @@ class CourseManager(Manager):
def get_courses(self, obj, **criteria):
qs = self.get_queryset()
if isinstance(obj, Group):
- qs = qs.filter(groups__in=Group.objects.get_parents(obj), **criteria) \
- .prefetch_related("rooms")
+ qs = qs.filter(groups__in=Group.objects.get_parents(obj),
+ **criteria).prefetch_related("rooms")
elif isinstance(obj, Room):
qs = qs.filter(rooms__in=(obj,), **criteria)
else:
@@ -197,7 +198,8 @@ class CourseManager(Manager):
class Course(models.Model):
objects = CourseManager()
- name = models.CharField(max_length=255, verbose_name="nom", default="Sans nom")
+ name = models.CharField(max_length=255, verbose_name="nom",
+ default="Sans nom")
type_ = models.CharField(name="type", max_length=255,
verbose_name="type de cours", null=True)
source = models.ForeignKey(Source, on_delete=models.CASCADE,
@@ -225,7 +227,6 @@ class Course(models.Model):
super(Course, self).save(*args, **kwargs)
-
class Meta:
verbose_name = "cours"
verbose_name_plural = "cours"
diff --git a/templatetags/dt_week.py b/templatetags/dt_week.py
index e8d13ac..de0db08 100644
--- a/templatetags/dt_week.py
+++ b/templatetags/dt_week.py
@@ -17,10 +17,12 @@ from django import template
register = template.Library()
+
@register.filter
def dt_week(dt):
return dt.isocalendar()[1]
+
@register.filter
def dt_prettyprint(dt):
return "{0}/{1:02d}/{2:02d}".format(dt.year, dt.month, dt.day)
diff --git a/templatetags/rooms.py b/templatetags/rooms.py
index 5108c92..f0e1b2e 100644
--- a/templatetags/rooms.py
+++ b/templatetags/rooms.py
@@ -17,10 +17,12 @@ from django import template
register = template.Library()
+
@register.filter
def format_rooms(rooms):
amphi_list = [room.name for room in rooms if room.name.startswith("Amphi")]
- room_list = [room.name for room in rooms if not room.name.startswith("Amphi")]
+ room_list = [room.name for room in rooms
+ if not room.name.startswith("Amphi")]
amphis = ", ".join(amphi_list)
joined = ", ".join(room_list)
diff --git a/tests.py b/tests.py
index 8a21a3f..e671973 100644
--- a/tests.py
+++ b/tests.py
@@ -28,29 +28,42 @@ class CourseTestCase(TestCase):
source = Source(url="http://example.org/")
source.save()
- self.timetable = Timetable(year=self.year, name="Test timetable 2", source=source, slug="test-timetable2")
+ self.timetable = Timetable(year=self.year, name="Test timetable 2",
+ source=source, slug="test-timetable2")
self.timetable.save()
cma = Group.objects.create(celcat_name="L1 info s2 CMA", source=source)
- tda2 = Group.objects.create(celcat_name="L1 info s2 TDA2", source=source)
- self.tpa21 = Group.objects.create(celcat_name="L1 info s2 TPA21", source=source)
+ tda2 = Group.objects.create(celcat_name="L1 info s2 TDA2",
+ source=source)
+ self.tpa21 = Group.objects.create(celcat_name="L1 info s2 TPA21",
+ source=source)
cmb = Group.objects.create(celcat_name="L1 info s2 CMB", source=source)
- tdb2 = Group.objects.create(celcat_name="L1 info s2 TDB2", source=source)
- self.tpb21 = Group.objects.create(celcat_name="L1 info s2 TPB21", source=source)
+ tdb2 = Group.objects.create(celcat_name="L1 info s2 TDB2",
+ source=source)
+ self.tpb21 = Group.objects.create(celcat_name="L1 info s2 TPB21",
+ source=source)
for group in (cma, tda2, self.tpa21, cmb, tdb2, self.tpb21,):
- course = Course.objects.create(name="{0} course".format(group.name), type="cours", source=source, begin=dt, end=dt)
+ course = Course.objects.create(name="{0} course"
+ .format(group.name),
+ type="cours", source=source,
+ begin=dt, end=dt)
course.groups.add(group)
def test_get_courses_for_group(self):
tpa21_courses = Course.objects.get_courses(self.tpa21)
tpb21_courses = Course.objects.get_courses(self.tpb21)
- tpa21_course_names = ["L1 info s2 CMA course", "L1 info s2 TDA2 course", "L1 info s2 TPA21 course"]
- tpb21_course_names = ["L1 info s2 CMB course", "L1 info s2 TDB2 course", "L1 info s2 TPB21 course"]
+ tpa21_course_names = ["L1 info s2 CMA course",
+ "L1 info s2 TDA2 course",
+ "L1 info s2 TPA21 course"]
+ tpb21_course_names = ["L1 info s2 CMB course",
+ "L1 info s2 TDB2 course",
+ "L1 info s2 TPB21 course"]
- for courses, names in ((tpa21_courses, tpa21_course_names,), (tpb21_courses, tpb21_course_names,),):
+ for courses, names in ((tpa21_courses, tpa21_course_names,),
+ (tpb21_courses, tpb21_course_names,),):
for course in courses:
self.assertIn(course.name, names)
names.remove(course.name)
@@ -64,29 +77,40 @@ class GroupTestCase(TestCase):
self.source = Source(url="http://example.org/")
self.source.save()
- self.timetable = Timetable(year=self.year, name="Test timetable", source=self.source, slug="test-timetable")
+ self.timetable = Timetable(year=self.year, name="Test timetable",
+ source=self.source, slug="test-timetable")
self.timetable.save()
Group.objects.create(celcat_name="L1 info s2 CMA", source=self.source)
Group.objects.create(celcat_name="L1 info s2 TDA2", source=self.source)
- Group.objects.create(celcat_name="L1 info s2 TPA21", source=self.source)
+ Group.objects.create(celcat_name="L1 info s2 TPA21",
+ source=self.source)
Group.objects.create(celcat_name="L1 info s2 CMB", source=self.source)
Group.objects.create(celcat_name="L1 info s2 TDB2", source=self.source)
- Group.objects.create(celcat_name="L1 info s2 TPB21", source=self.source)
+ Group.objects.create(celcat_name="L1 info s2 TPB21",
+ source=self.source)
- Group.objects.create(celcat_name="L1 info (toutes sections et semestres confondus)", source=self.source)
+ Group.objects.create(celcat_name="L1 info (toutes sections et "
+ "semestres confondus)", source=self.source)
def test_corresponds(self):
- cma = Group.objects.get(celcat_name="L1 info s2 CMA", source=self.source)
- tda2 = Group.objects.get(celcat_name="L1 info s2 TDA2", source=self.source)
- tpa21 = Group.objects.get(celcat_name="L1 info s2 TPA21", source=self.source)
-
- cmb = Group.objects.get(celcat_name="L1 info s2 CMB", source=self.source)
- tdb2 = Group.objects.get(celcat_name="L1 info s2 TDB2", source=self.source)
- tpb21 = Group.objects.get(celcat_name="L1 info s2 TPB21", source=self.source)
-
- general = Group.objects.get(celcat_name="L1 info (toutes sections et semestres confondus)", source=self.source)
+ cma = Group.objects.get(celcat_name="L1 info s2 CMA",
+ source=self.source)
+ tda2 = Group.objects.get(celcat_name="L1 info s2 TDA2",
+ source=self.source)
+ tpa21 = Group.objects.get(celcat_name="L1 info s2 TPA21",
+ source=self.source)
+
+ cmb = Group.objects.get(celcat_name="L1 info s2 CMB",
+ source=self.source)
+ tdb2 = Group.objects.get(celcat_name="L1 info s2 TDB2",
+ source=self.source)
+ tpb21 = Group.objects.get(celcat_name="L1 info s2 TPB21",
+ source=self.source)
+
+ general = Group.objects.get(celcat_name="L1 info (toutes sections et "
+ "semestres confondus)", source=self.source)
self.assertFalse(cma.corresponds_to(*tda2.group_info))
self.assertFalse(cma.corresponds_to(*tpa21.group_info))
@@ -135,7 +159,8 @@ class GroupTestCase(TestCase):
tdb2 = Group.objects.get(name="L1 info s2 TDB2", source=self.source)
tpb21 = Group.objects.get(name="L1 info s2 TPB21", source=self.source)
- general = Group.objects.get(celcat_name="L1 info (toutes sections et semestres confondus)", source=self.source)
+ general = Group.objects.get(celcat_name="L1 info (toutes sections et "
+ "semestres confondus)", source=self.source)
self.assertEqual(cma.celcat_name, "L1 info s2 CMA")
self.assertEqual(tda2.celcat_name, "L1 info s2 TDA2")
@@ -145,18 +170,26 @@ class GroupTestCase(TestCase):
self.assertEqual(tdb2.celcat_name, "L1 info s2 TDB2")
self.assertEqual(tpb21.celcat_name, "L1 info s2 TPB21")
- self.assertEqual(general.celcat_name, "L1 info (toutes sections et semestres confondus)")
+ self.assertEqual(general.celcat_name, "L1 info (toutes sections et "
+ "semestres confondus)")
def test_parse(self):
- cma = Group.objects.get(celcat_name="L1 info s2 CMA", source=self.source)
- tda2 = Group.objects.get(celcat_name="L1 info s2 TDA2", source=self.source)
- tpa21 = Group.objects.get(celcat_name="L1 info s2 TPA21", source=self.source)
-
- cmb = Group.objects.get(celcat_name="L1 info s2 CMB", source=self.source)
- tdb2 = Group.objects.get(celcat_name="L1 info s2 TDB2", source=self.source)
- tpb21 = Group.objects.get(celcat_name="L1 info s2 TPB21", source=self.source)
-
- general = Group.objects.get(celcat_name="L1 info (toutes sections et semestres confondus)", source=self.source)
+ cma = Group.objects.get(celcat_name="L1 info s2 CMA",
+ source=self.source)
+ tda2 = Group.objects.get(celcat_name="L1 info s2 TDA2",
+ source=self.source)
+ tpa21 = Group.objects.get(celcat_name="L1 info s2 TPA21",
+ source=self.source)
+
+ cmb = Group.objects.get(celcat_name="L1 info s2 CMB",
+ source=self.source)
+ tdb2 = Group.objects.get(celcat_name="L1 info s2 TDB2",
+ source=self.source)
+ tpb21 = Group.objects.get(celcat_name="L1 info s2 TPB21",
+ source=self.source)
+
+ general = Group.objects.get(celcat_name="L1 info (toutes sections et "
+ "semestres confondus)", source=self.source)
self.assertEqual(cma.group_info, ("L1 info", 2, "A"))
self.assertEqual(tda2.group_info, ("L1 info", 2, "A2"))
diff --git a/utils.py b/utils.py
index 9f0a6b5..839d8bc 100644
--- a/utils.py
+++ b/utils.py
@@ -18,9 +18,11 @@ import re
from django.utils import timezone
+
def get_current_week():
return tz_now().isocalendar()[:2]
+
def get_current_or_next_week():
year, week, day = tz_now().isocalendar()
if day >= 6:
@@ -28,6 +30,7 @@ def get_current_or_next_week():
return year, week
+
def get_week(year, week):
start = timezone.make_aware(datetime.datetime.strptime(
"{0}-W{1}-1".format(year, week), "%Y-W%W-%w"))
@@ -35,6 +38,7 @@ def get_week(year, week):
return start, end
+
def group_courses(courses):
grouped_courses = []
for i, course in enumerate(courses):
@@ -45,6 +49,7 @@ def group_courses(courses):
return grouped_courses
+
def parse_group(name):
# Explication de la regex
#
@@ -66,7 +71,8 @@ def parse_group(name):
parts = search.groups()
- # On retourne la section (parts[0]), le semestre (parts[2]) et le groupe (parts[5])
+ # On retourne la section (parts[0]), le semestre (parts[2]) et le
+ # groupe (parts[5])
if parts[2] is not None:
return parts[0], int(parts[2]), parts[5]
else:
@@ -75,6 +81,7 @@ def parse_group(name):
# une erreur.
return parts[0], None, parts[5]
+
def tz_now():
"""Retourne la date et l’heure avec le bon fuseau horaire"""
return timezone.make_aware(datetime.datetime.now())