From 8cd882672b2b256319228c5d756f15035c0772a9 Mon Sep 17 00:00:00 2001 From: olen Date: Thu, 14 May 2026 16:46:06 +0200 Subject: [PATCH 1/3] docs: remove PR/issue references from public docstrings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The expanded docstrings landed in #237/#241 inlined references to issue and PR numbers (e.g. \"see #205\", \"PR #236 changes ...\", \"fixed in #235\"). Those references publish to the docs site via pdoc and rot the moment issues are renumbered, repos are renamed, or the codebase moves — exactly the kind of incidental-link maintainence burden the project's general rule against in-code issue references is meant to prevent. Rewrote each docstring to describe the behaviour/limitation directly in prose, so a reader of the published docs learns the same thing without having to chase a number into the issue tracker. Touched docstrings: - AuthenticationError (`spond/__init__.py`): dropped \"see #205\"; the surrounding bullet already explains the 2FA gap. - `Spond.__init__`: dropped \"see #205\"; replaced with \"Spond's TOTP flow is not yet supported\". - `Spond.get_events`: dropped the PR #236 forward-reference; replaced with a direct description of the cache-vs-direct trade-off. - `Spond.get_event`: dropped \"see #137 and #138\" and the PR #236 forward-reference; rewrote to describe how to reach events outside the default window directly. - `Spond.get_event_attendance_xlsx`: dropped \"see closed issue #227\"; the prose already names the limitation. - `Spond._get_entity`: dropped \"#136, fixed in #235\"; described the empty-cache behaviour directly. No code changes, no test changes, all 30 tests still pass. --- spond/__init__.py | 2 +- spond/spond.py | 35 +++++++++++++++++------------------ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/spond/__init__.py b/spond/__init__.py index 47b2a47..70bd3ef 100644 --- a/spond/__init__.py +++ b/spond/__init__.py @@ -17,7 +17,7 @@ class AuthenticationError(Exception): - Incorrect username/password. - 2FA enabled on the account (the library does not currently support - Spond's TOTP flow — see #205). + Spond's TOTP flow). - The account has hit Spond's login rate limit (`outOfLoginAttempts`). - The Spond login API has changed shape and the response no longer contains an `accessToken`. diff --git a/spond/spond.py b/spond/spond.py index 6348291..052c5ba 100644 --- a/spond/spond.py +++ b/spond/spond.py @@ -82,7 +82,7 @@ def __init__(self, username: str, password: str) -> None: Spond account email address. password : str Spond account password. For accounts with 2FA enabled, login will - currently fail — see #205. + currently fail — Spond's TOTP flow is not yet supported. """ super().__init__(username, password, self._API_BASE_URL) self._chat_url = None @@ -449,13 +449,11 @@ async def get_events( and by visibility (scheduled, hidden). The full response is cached on `self.events`. - Note: `get_event(uid)` is a wrapper around this method via the cache, - so it inherits these defaults — an event that doesn't appear in the + Note: `get_event(uid)` looks up events via this method's cache, so + it inherits these defaults — an event that doesn't appear in the first `max_events` results or is excluded by `include_scheduled=False` - is unreachable through `get_event()` on current main. PR #236 changes - `get_event()` to fetch the singular `sponds/{uid}` endpoint directly, - removing that coupling; until it lands, pass appropriate filters here - when you need broader visibility. + is unreachable through `get_event()`. If you need broader visibility, + call this method directly with appropriate filters. Parameters ---------- @@ -542,11 +540,11 @@ async def get_events( async def get_event(self, uid: str) -> JSONDict: """Look up a single event by its unique id. - Currently routes through the cached events list (populated by - `get_events()`). Note this means events outside the `max_events=100` - default or with `scheduled=true` may not be findable — see #137 and - #138 (fix in PR #236 routes this through the singular `sponds/{uid}` - endpoint instead). + Routes through the cached events list (populated by `get_events()`), + which means events outside the `max_events=100` default or those + with `scheduled=true` may not be findable. To reach those events, + call `get_events()` directly with appropriate filters first to + populate the cache, then call this method. Parameters ---------- @@ -614,9 +612,9 @@ async def get_event_attendance_xlsx(self, uid: str) -> bytes: Thin wrapper around Spond's own "Export attendance history" feature in the web UI. The columns and format are determined by Spond, not by - this library — for example, the export does not include member ids - (see closed issue #227). For a customisable CSV alternative built - from `get_event()` data, see `examples/attendance.py`. + this library — for example, the export does not include member ids. + For a customisable CSV alternative built from `get_event()` data, + see `examples/attendance.py`. Parameters ---------- @@ -680,9 +678,10 @@ async def _get_entity(self, entity_type: str, uid: str) -> JSONDict: Routes to the relevant cache (`self.events` or `self.groups`), triggers a fetch via `get_events()` / `get_groups()` if the cache is - empty, then linearly scans for a matching `id`. The empty-cache case - is handled explicitly to avoid the `TypeError: 'NoneType' object is - not iterable` that previously occurred (see #136, fixed in #235). + empty, then linearly scans for a matching `id`. Raises `KeyError` + cleanly (rather than `TypeError`) when the cache remains empty after + the fetch attempt — the underlying `get_*s()` method may legitimately + return `None` if the account has no events/groups available. Parameters ---------- From 252ed84d25797ba5f99eda56788ab7cf50888e90 Mon Sep 17 00:00:00 2001 From: olen Date: Thu, 14 May 2026 16:49:09 +0200 Subject: [PATCH 2/3] ci+docs: render NumPy-style docstrings with pdoc --docformat numpy The docstrings throughout `spond/` use the NumPy convention (`Parameters` heading followed by an `----` underline, parameter name on one line, type+description indented). pdoc supports that dialect but it's opt-in via `--docformat`; without the flag pdoc treats the section headings as plain text, so the rendered docs show all parameters running together as one flat paragraph. Add `--docformat numpy` to both invocations: - `.github/workflows/publish-docs.yml` so the hosted site renders with structured Parameters / Returns / Raises sections. - `README.md` so contributors running pdoc locally see the same output, with a note explaining why the flag is needed. Verified locally: with the flag, `get_events` renders as an `
` header followed by a `
    ` where each parameter is its own `
  • ` with the name bolded and type in parentheses. Without it, the same docstring renders as a single paragraph of run-together text. --- .github/workflows/publish-docs.yml | 4 +++- README.md | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml index 06377b7..c22b5f4 100644 --- a/.github/workflows/publish-docs.yml +++ b/.github/workflows/publish-docs.yml @@ -42,7 +42,9 @@ jobs: - name: 📝 Generate static HTML # `./spond` (not `spond`) forces pdoc to document the local checkout # instead of any same-named module that might be importable. - run: poetry run pdoc -o site/ ./spond + # `--docformat numpy` parses NumPy-style Parameters/Returns/Raises + # sections as structured lists rather than flat paragraphs. + run: poetry run pdoc --docformat numpy -o site/ ./spond - name: ⚙️ Configure Pages uses: actions/configure-pages@v5 diff --git a/README.md b/README.md index 644301d..d6273f4 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ install the dev dependencies and start the pdoc dev server: ```shell poetry install -poetry run pdoc ./spond +poetry run pdoc --docformat numpy ./spond ``` A browser tab opens at `http://localhost:8080` with a searchable, navigable @@ -114,9 +114,13 @@ next to each one. Pages update automatically when the docstrings change. To generate static HTML instead: ```shell -poetry run pdoc -o docs/ ./spond +poetry run pdoc --docformat numpy -o docs/ ./spond ``` +The `--docformat numpy` flag parses NumPy-style `Parameters`, `Returns`, and +`Raises` sections as structured lists — omit it and the param list renders as +one flat paragraph. + The leading `./` is important when developing inside the repo — without it, pdoc would document the *installed* `spond` package from `site-packages` rather than your local checkout. From 86df2230bf641b0cc6919970d96dd1106f277170 Mon Sep 17 00:00:00 2001 From: olen Date: Thu, 14 May 2026 16:57:18 +0200 Subject: [PATCH 3/3] docs: use Python parameter name (include_scheduled) in get_event docstring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address Copilot review on #245: the docstring referenced `scheduled=true`, which is the raw HTTP API parameter name. The Python-facing knob is `include_scheduled` on `get_events()`. Mixing the two namespaces in a user-facing docstring is confusing — a reader could reasonably assume `get_event()` accepts a `scheduled` keyword arg. Rephrased to `include_scheduled=False` (the actual Python default that excludes those events from the cache). --- spond/spond.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spond/spond.py b/spond/spond.py index 052c5ba..5570406 100644 --- a/spond/spond.py +++ b/spond/spond.py @@ -542,9 +542,9 @@ async def get_event(self, uid: str) -> JSONDict: Routes through the cached events list (populated by `get_events()`), which means events outside the `max_events=100` default or those - with `scheduled=true` may not be findable. To reach those events, - call `get_events()` directly with appropriate filters first to - populate the cache, then call this method. + excluded by `include_scheduled=False` may not be findable. To reach + those events, call `get_events()` directly with appropriate filters + first to populate the cache, then call this method. Parameters ----------