Skip to main content

hm-semester

A Python package for generating ICS calendar files for Hochschule München (HM) semesters. Create calendars with semester dates, breaks, holidays, and weekly/biweekly lecture schedules.

Features

  • Semester Calendar: Generate calendars with semester start/end dates and breaks (Christmas, Easter, Pentecost)
  • Lecture Agenda: Create individual lecture events with holiday-aware scheduling
  • Biweekly Support: Handle biweekly lectures that maintain alternating patterns even when holidays interrupt
  • Update Tracking: Deterministic UIDs and SEQUENCE numbers for calendar updates
  • Multi-language: Support for German and English labels

Usage

Semester Calendar (Holidays & Breaks)

Generate a calendar with semester dates and break periods.

CLI

python -m hm_semester --year 2025 --semester winter --lang en

This creates winter_semester_2025_en.ics with:

  • Semester start and end dates
  • Christmas break (Winter semester)
  • Easter and Pentecost breaks (Summer semester)

Python API

from hm_semester.semester import generate_calendar

cal = generate_calendar(2025, "winter", "en")
with open("semester.ics", "wb") as f:
    f.write(cal.to_ical())

Lecture Agenda

Generate individual lecture events with holiday-aware scheduling.

Basic Example

from datetime import time
from hm_semester.agenda import WeeklyEvent, create_agenda

events = [
    WeeklyEvent(
        summary="Algorithms",
        course_id="CS101",
        weekday=0,  # Monday
        start_time=time(9, 0),
        end_time=time(11, 0),
        location="Room 101",
    ),
    WeeklyEvent(
        summary="Database Systems",
        course_id="CS202",
        weekday=2,  # Wednesday
        start_time=time(14, 0),
        end_time=time(16, 0),
        location="Lab 305",
        biweekly=True,  # Every 2 weeks
        start_week=1,
    ),
]

cal = create_agenda(events, 2026, "en", "summer")
with open("lectures.ics", "wb") as f:
    f.write(cal.to_ical())

WeeklyEvent Parameters

  • summary (str): Event title
  • course_id (str): Course identifier for deterministic UID generation
  • weekday (int): Day of week (0=Monday, 6=Sunday)
  • start_time (time): Lecture start time
  • end_time (time): Lecture end time
  • location (str, optional): Room or building
  • biweekly (bool, optional): If True, event occurs every 2 weeks
  • start_week (int, optional): For biweekly, which week to start (1, 2, 3, ...)
  • timezone (str, optional): Timezone name (default: "Europe/Berlin")
  • sequence (int, optional): Version number for updates (default: 0)

Holiday-Aware Scheduling

Lectures automatically skip semester breaks:

  • Individual events are generated (no RRULE)
  • Holidays are excluded from the schedule
  • Biweekly lectures maintain alternating pattern even when holidays interrupt
    • Example: If a biweekly lecture would be in week 7 (holiday), it shifts to week 8

Biweekly Patterns

Use start_week to stagger multiple biweekly groups:

# Four groups meeting every 2 weeks, staggered by 1 week
groups = [
    WeeklyEvent("Group A", "grpA", 0, time(10, 0), time(12, 0), 
                biweekly=True, start_week=1),
    WeeklyEvent("Group B", "grpB", 0, time(10, 0), time(12, 0), 
                biweekly=True, start_week=2),
    WeeklyEvent("Group C", "grpC", 0, time(10, 0), time(12, 0), 
                biweekly=True, start_week=3),
    WeeklyEvent("Group D", "grpD", 0, time(10, 0), time(12, 0), 
                biweekly=True, start_week=4),
]

Updating Calendars

When room locations or times change, increment the sequence parameter:

# Initial calendar
events = [
    WeeklyEvent("Algorithms", "CS101", 0, time(9, 0), time(11, 0), 
                location="Room 101", sequence=0),
]
cal = create_agenda(events, 2026, "en", "summer")

# Later: room changed
events[0].location = "Room 999"
events[0].sequence = 1
updated_cal = create_agenda(events, 2026, "en", "summer")

For Thunderbird/local calendar apps: Delete the old calendar and import the new one.

For CalDAV/subscribed calendars: Events with the same UID and higher SEQUENCE are automatically updated.

Examples

See examples/create_agenda_example.py for a complete example.

Output Format

  • Each lecture gets a unique event with format: "Course Name (1)", "Course Name (2)", etc.
  • UIDs are deterministic: {course_id}-{year}-{semester}-lesson-{number}@hm.edu
  • VTIMEZONE components are included for proper timezone handling
  • SEQUENCE field tracks version numbers for updates

Installation

From PyPI

pip install hm-semester

From source

git clone https://github.com/DavidMStraub/hm-semester.git
cd hm-semester
pip install .

Development

Run tests:

pytest tests/

Release Process

This package uses GitHub Actions for automated PyPI releases:

  1. Update version in pyproject.toml
  2. Commit and push changes
  3. Create a new release on GitHub
  4. The workflow automatically builds and publishes to PyPI and TestPyPI

The workflow uses Trusted Publishing (no API tokens needed). Configure trusted publishers:

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hm_semester-26.1.0.tar.gz (12.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hm_semester-26.1.0-py3-none-any.whl (9.2 kB view details)

Uploaded Python 3

File details

Details for the file hm_semester-26.1.0.tar.gz.

File metadata

  • Download URL: hm_semester-26.1.0.tar.gz
  • Upload date:
  • Size: 12.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for hm_semester-26.1.0.tar.gz
Algorithm Hash digest
SHA256 5132e6c99dd7d8d1e09fcbd964c131dfef54b167f6aaa4c60b3020be4e3cfc01
MD5 425aed1268126f996eef9bc674de5c0a
BLAKE2b-256 193abdc859d6de5a2b877f4ed15d3944d378352647d44d5cfe623bb939381cec

See more details on using hashes here.

Provenance

The following attestation bundles were made for hm_semester-26.1.0.tar.gz:

Publisher: pypi-release.yml on DavidMStraub/hm-semester

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file hm_semester-26.1.0-py3-none-any.whl.

File metadata

  • Download URL: hm_semester-26.1.0-py3-none-any.whl
  • Upload date:
  • Size: 9.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for hm_semester-26.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0e989ec0f96231af8eaf41bd985d8e38f72b1418dd8fdea63c4dcf6e057ecb17
MD5 5f5c93c5aa427f4f22bb510ef8f71411
BLAKE2b-256 e90b06d117ffecf0a10bbbf4754f892e7a46c9cce9a90193087e20a83f778f7b

See more details on using hashes here.

Provenance

The following attestation bundles were made for hm_semester-26.1.0-py3-none-any.whl:

Publisher: pypi-release.yml on DavidMStraub/hm-semester

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

26.1.0 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page