meeting_ics (provenage-meeting-ics)
Generic civic meeting records to an RFC 5545 iCalendar feed. Part of Provenage. Python 3 standard library only, deterministic, jurisdiction- and source-agnostic.
Purpose and boundary: this library builds the public calendar feed and nothing else. It has no RSVP,
attendance, ATTENDEE or member features, and never will: those belong to an install's member layer inside a
Provenage deployment, not to the public feed. Source-specific knowledge lives only in adapters/.
License: Apache-2.0 (see the repository root).
Layout
model.pyMeetingRecord, the source-agnostic input recordical.pyescape, fold, VTIMEZONE generationledger.pySEQUENCE ledgerbuild.pybuild(records, options) -> bytescli.py/__main__.pycommand lineadapters/primegov_normalized.pythe only PrimeGov-aware codetests/unittest suite
Input schema (one record)
uid_namespace, record_id, body, meeting_type, date (YYYY-MM-DD local), start_time (HH:MM local),
timezone (IANA), status, retrieved_at (UTC YYYY-MM-DDTHH:MM:SSZ), and optional location,
links {portal, agenda, packet, minutes, video}, documents [{kind, url, publish_date}], end_time
(observed local end), end_basis, topics (reserved), provenance (free-form, carried, never emitted or hashed).
Status values: cancelled (STATUS:CANCELLED, kept), confirmed (CONFIRMED, observed),
scheduled_not_cancelled (CONFIRMED plus a STATUS-BASIS note, derived not observed); anything else gets no
STATUS and an AMBIGUITY note. Full field docs are in model.py.
Options (BuildOptions, or --config JSON)
prodid; uid_domain; default_duration (JSON: default_duration_hours or _minutes); end_rules, a list of
(meeting_type substring, case-insensitive) to a fixed local end "HH:MM" or {duration_minutes|end_local, basis},
first match wins; x_prefix (default X-MEETING-ICS; a host project may set its own, for example X-EXAMPLE); calendar_name; detail: links (implemented),
topics and full (stubs that raise NotImplementedError, pending a design decision).
End precedence: record end_time, then end rule, then default duration. The end basis is always declared in
<x_prefix>-DTEND-BASIS.
Rules (the contract; as implemented in build.py)
- One VEVENT per record in input order; UID
<uid_namespace>-<record_id>@<uid_domain>. Two records in one input with the same UID are an error (ValueError). - DTSTAMP is
retrieved_at, never the wall clock. - DTSTART/DTEND carry
TZID; a VTIMEZONE is emitted for each zone present. - DTEND derived as above and always labelled as assumed, rule-set or observed.
- SUMMARY is meeting_type, prefixed by body unless it already starts with it. Links level shows no agenda text.
- DESCRIPTION is labelled authoritative links only (Portal, Agenda, Packet, Minutes, Video); null is omitted.
- URL is the portal link; if absent, an AMBIGUITY note records it.
- Status mapping as above.
- LOCATION when present, else AMBIGUITY
no-location. - SEQUENCE from the ledger, keyed by UID, storing critical_hash, docs_hash, sequence, last_modified. First sight is 0; if the critical hash (body, date, start_time, timezone, status, location, meeting_type, derived end and its basis) or the docs hash (links and sorted documents) changes, SEQUENCE increments and last_modified becomes this run's DTSTAMP. UIDs absent from input stay in the ledger.
- LAST-MODIFIED is the ledger last_modified.
- Fold at 75 octets without splitting UTF-8, CRLF line ends, TEXT escapes for backslash, semicolon, comma, newline.
- VTIMEZONE: built-in US-rule blocks (Denver, New_York, Chicago, Los_Angeles; Denver is exact), fixed zones (Phoenix, Honolulu, UTC), any other IANA zone derived from zoneinfo transitions for the years present. If zoneinfo or tz data is unavailable it raises RuntimeError.
Use
python3 -m meeting_ics build --input records.json --output feed.ics --ledger sequence.json --config opts.json
or, once installed, meeting-ics build .... --adapter primegov_normalized --uid-namespace NAME reads a source file through an adapter instead; the namespace is required.
Writing an adapter
Add adapters/<name>.py exposing load(path) -> list[MeetingRecord] (and ideally convert(data)). Do all
source knowledge there: unwrap source envelopes, choose the record_id, and take uid_namespace from the caller (the PrimeGov adapter requires it as a parameter, with no default), map the source's status
vocabulary onto the values above, map its URLs into links, flatten documents, take retrieved_at from the
fetch time. Put anything else the caller should keep in provenance. Nothing outside the adapter may mention the source.
Tests
cd packages/meeting-ics && python3 -m unittest discover -s tests -t .
cd packages/meeting-ics && python3 -m pytest -q
Metadata
Release files for provenage-meeting-ics 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| provenage_meeting_ics-0.1.0.tar.gz | 15.9 kB | Without provenance | Details for provenage_meeting_ics-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| provenage_meeting_ics-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for provenage_meeting_ics-0.1.0-py3-none-any.whl |
Total release size: 30.8 kB
Release files / provenage_meeting_ics-0.1.0.tar.gz
| Download URL | provenage_meeting_ics-0.1.0.tar.gz |
|---|---|
| Size | 15.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4c86c245ccaebb173fe6f2d1da8e3b11a74291350926e9866c6d8f93e9323f73
|
|
BLAKE2b-256 checksum How to use checksums |
177de260235508e0008a8d3157847b626f9c7686bef4bd78a930051b96831f42
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Release files / provenage_meeting_ics-0.1.0-py3-none-any.whl
| Download URL | provenage_meeting_ics-0.1.0-py3-none-any.whl |
|---|---|
| Size | 14.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0f4e988f8a55c2b8446d6ab3c5de923554e9650686a7db4a5e9a271d77d74a00
|
|
BLAKE2b-256 checksum How to use checksums |
fb58c4c73e9927ed523d8888d85d456d50913a42be64137040c32c93af19b8ea
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Security for provenage-meeting-ics 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.