aboutsummaryrefslogtreecommitdiff
path: root/scripts/gen_map/gen_map.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/gen_map/gen_map.py')
-rwxr-xr-xscripts/gen_map/gen_map.py142
1 files changed, 86 insertions, 56 deletions
diff --git a/scripts/gen_map/gen_map.py b/scripts/gen_map/gen_map.py
index 2f1089de..75aa7a48 100755
--- a/scripts/gen_map/gen_map.py
+++ b/scripts/gen_map/gen_map.py
@@ -1,4 +1,16 @@
#!/usr/bin/env python3
+# Copyright 2023 Florian Fischer
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program. If not, see <https://www.gnu.org/licenses/>.
+"""simple script to generate a rough markdown map of a school year"""
import argparse
from datetime import datetime, timedelta
@@ -7,6 +19,7 @@ import os
import re
import sys
import urllib
+import typing as t
from bs4 import BeautifulSoup
import icalevents
@@ -45,6 +58,12 @@ WEEKLY_HOURS = {
}
+def die(msg: str, status=1):
+ """Exit with status printing a msg to stderr"""
+ print(msg, file=sys.stderr)
+ sys.exit(status)
+
+
def default_year() -> int:
"""return the default year"""
now = datetime.now()
@@ -107,6 +126,7 @@ def get_public_holidays(land: int, start: datetime,
class LehrplanSection:
+ """Representation of a section of Lehrplanplus"""
def __init__(self, num, summary, duration, subsections=None):
self.num = num
@@ -114,18 +134,37 @@ class LehrplanSection:
self.duration = duration
self.subsections = subsections or []
- def has_subsections(self) -> bool:
- return bool(self.subsections)
-
def __str__(self):
return f'{self.num}: {self.summary} ({self.duration}h) {self.subsections}'
def __repr__(self):
- return f'LehrplanSection({self.num}, {self.summary}, {self.duration}h, {self.subsections})'
+ return (f'LehrplanSection({self.num}, {self.summary}, '
+ f'{self.duration}h, {self.subsections})')
Lehrplan = list[LehrplanSection]
+SUMMARY_RE = re.compile(r'(.*) \(ca\. ([1-9][0-9]*) Std\.\)')
+
+
+def parse_section_html(section, summary_class: str) -> t.Tuple[str, str, int]:
+ """Parse the html for a section from the Lehrplanplus webpage"""
+ num = list(section.find(**{
+ 'class': 'head-absatz-num'
+ }).children)[2].strip()
+
+ summary = section.find(**{'class': summary_class}).string.strip()
+ summary = summary.replace('\xa0', ' ')
+
+ match = SUMMARY_RE.match(summary)
+ if not match is None:
+ summary = match.group(1)
+ duration = int(match.group(2))
+ else:
+ die(f'summary: {summary} does not match our re')
+
+ return num, summary, duration
+
def get_lehrplan(subject: str, form: str) -> Lehrplan:
"""Retrieve the sections and expected duration from lehrplanplus"""
@@ -134,51 +173,44 @@ def get_lehrplan(subject: str, form: str) -> Lehrplan:
resp = requests.get(lpp_url, timeout=10)
html = BeautifulSoup(resp.text)
- summary_re = re.compile(r'(.*) \(ca\. ([1-9][0-9]*) Std\.\)')
-
lehrplan: Lehrplan = []
top_level_sections = html.find_all(**{'class': 'headline_lvl1'})
for section in top_level_sections:
- num = list(section.find(**{
- 'class': 'head-absatz-num'
- }).children)[2].strip()
-
- summary = section.find(**{
- 'class': 'head-absatz-title-short'
- }).string.strip()
- summary = summary.replace('\xa0', ' ')
-
- m = summary_re.match(summary)
- summary = m.group(1)
- duration = int(m.group(2))
+ num, summary, duration = parse_section_html(section,
+ 'head-absatz-title-short')
lehrplan.append(LehrplanSection(num, summary, duration))
second_level_sections = html.find_all(**{'class': 'headline_lvl2'})
for section in second_level_sections:
- summary = section.find(**{
- 'class': 'head-absatz-title-long'
- }).string.strip()
- summary = summary.replace('\xa0', ' ')
-
- m = summary_re.match(summary)
- summary = m.group(1)
- duration = int(m.group(2))
- num = list(section.find(**{
- 'class': 'head-absatz-num'
- }).children)[2].strip()
+ num, summary, duration = parse_section_html(section,
+ 'head-absatz-title-long')
lehrplan[int(num.split('.')[0]) - 1].subsections.append(
LehrplanSection(num, summary, duration))
return lehrplan
-def gen_section_iter(lehrplan):
- sections = []
+def gen_section_iter(lehrplan, inter_section_buffer_duration: int):
+ """Create an iterator returning the current section"""
+ end_section_buffer = LehrplanSection('', 'Puffer', 0)
+ inter_section_buffer = LehrplanSection('', 'Puffer',
+ inter_section_buffer_duration)
+
+ _sections = []
for s in lehrplan:
- if not s.has_subsections():
- sections.append(s)
+ if not s.subsections:
+ _sections.append(s)
else:
- sections.extend(s.subsections)
+ _sections.extend(s.subsections)
+
+ # Add buffer sections to the lehrplan
+ sections = []
+ for s in _sections:
+ sections.append(s)
+ if inter_section_buffer_duration:
+ sections.append(inter_section_buffer)
+
+ sections.append(end_section_buffer)
next_section_in = sections[0].duration
cur = 0
@@ -186,29 +218,27 @@ def gen_section_iter(lehrplan):
def _section_iter(weekly_hours, total_hours) -> list[LehrplanSection]:
nonlocal cur
if cur == len(sections) - 1:
- return [sections[-1]]
-
- cur_sections = []
+ return sections[-1]
nonlocal next_section_in
# advance section
- if total_hours > next_section_in:
- if total_hours - weekly_hours < next_section_in:
- cur_sections.append(sections[cur])
-
+ if total_hours > next_section_in + (weekly_hours -
+ next_section_in % weekly_hours):
cur += 1
next_section_in += sections[cur].duration
- cur_sections.append(sections[cur])
-
- return cur_sections
+ return sections[cur]
return _section_iter
-def gen_latex_table(weekly_hours: int, lehrplan: Lehrplan, school_holidays,
- public_holidays) -> list[str]:
- """generate a latex table matching lehrplan section on kalendarweeks"""
+def gen_latex_table(
+ weekly_hours: int,
+ lehrplan: Lehrplan,
+ school_holidays: list[icalevents.icalparser.Event],
+ public_holidays: list[icalevents.icalparser.Event], # # pylint: disable=unused-argument
+ inter_section_buffer: int) -> list[str]:
+ """generate a latex table matching lehrplan section on calendar weeks"""
rows: list[str] = []
@@ -220,7 +250,7 @@ def gen_latex_table(weekly_hours: int, lehrplan: Lehrplan, school_holidays,
holiday_iter = iter(school_holidays[1:])
next_holiday = next(holiday_iter)
- section_iter = gen_section_iter(lehrplan)
+ section_iter = gen_section_iter(lehrplan, inter_section_buffer)
total_hours = 0
week_iter = start + timedelta(days=1)
@@ -234,13 +264,11 @@ def gen_latex_table(weekly_hours: int, lehrplan: Lehrplan, school_holidays,
next_holiday = next(holiday_iter)
continue
- lp_sections = section_iter(weekly_hours, total_hours)
-
- lp_level = ' \\& '.join([s.num for s in lp_sections])
- lp_summary = ' \\& '.join([s.summary for s in lp_sections])
+ lp_section = section_iter(weekly_hours, total_hours)
rows.append(
- f'{week_iter.isocalendar().week} & {lp_level} & {lp_summary} \\\\')
+ f'{week_iter.isocalendar().week} & {lp_section.num} & {lp_section.summary} \\\\'
+ )
week_iter += timedelta(days=7)
total_hours += weekly_hours
@@ -248,8 +276,9 @@ def gen_latex_table(weekly_hours: int, lehrplan: Lehrplan, school_holidays,
return rows
-def print_map(rows: list[str], template: Path, outfile):
- with open(template, 'r', encoding='utf-8') as template_file:
+def print_map(rows: list[str], template_path: Path, outfile):
+ """Print the template including the generated table"""
+ with open(template_path, 'r', encoding='utf-8') as template_file:
template = template_file.readlines()
template_prefix = template[:-6]
@@ -269,6 +298,7 @@ def main():
parser.add_argument('--year', default=default_year())
parser.add_argument('--land', default=BAYERN)
parser.add_argument('-o', '--output', default=sys.stdout)
+ parser.add_argument('-b', '--inter-section-buffer', type=int)
args = parser.parse_args()
@@ -280,7 +310,7 @@ def main():
lehrplan = get_lehrplan(args.subject, str(args.form))
rows = gen_latex_table(weekly_hours, lehrplan, school_holidays,
- public_holidays)
+ public_holidays, args.inter_section_buffer)
if args.template_dir:
template_path = Path(args.template_dir) / TEMPLATE_FILE