Fix #113: Fix badge names returning null in profile endpoint #129

Open
typosaurus wants to merge 1 commits from typosaurus/ticket-113 into master
Collaborator

Resolves #113.

Plan

Implementation Plan: Fix Null Badge Names in Profile JSON Response

1. Code Change – Add Pydantic Alias to BadgeOut.name

File: devplacepy/schemas/content.py

  • Line 65 – Change the field definition from:
    name: Optional[str] = None
    
    to:
    name: Optional[str] = Field(None, alias="badge_name")
    
  • Imports – Ensure from pydantic import Field is present at the top of the file (it is already imported elsewhere in the module, but confirm the import is available. If not, add it.)

This alias tells Pydantic to accept the key badge_name from the input dict (the raw database row) and serialize it as name in the JSON output. HTML rendering is unaffected because it reads badge['badge_name'] directly from the raw dict before Pydantic processing.

2. Verify No Existing BadgeOut Constructions Use name= Keyword Argument

Search the entire codebase for all occurrences of BadgeOut(.
If any call site passes name= as a keyword argument (e.g., BadgeOut(name="something")), the alias will reject that input unless the model config includes populate_by_name=True.

  • If none exist → no further config change is needed.
  • If some exist → either:
    • Change those call sites to use badge_name= instead, or
    • Add model_config = ConfigDict(populate_by_name=True) to the BadgeOut class (or its parent _Out).

Given the investigation flow (data comes from database dicts, not programmatic construction), it is expected no such keyword constructions exist. However, this must be confirmed.

3. Add a JSON‑Serialization Test for Badge Names

New test location: tests/api/profile.py (or a dedicated schema test, e.g. tests/unit/schemas/test_badge_out.py).
The test must:

  • Use the project’s TestClient to send a GET request to the profile endpoint with Accept: application/json.
  • Verify HTTP 200.
  • Parse the JSON response and confirm that each entry in badges[] has a non‑null name that matches the expected badge text for the test user’s badges.

If the test database does not guarantee a badge for the test user, either:

  • Insert a temporary badge via fixture/database setup, or
  • Assert that if badges is non‑empty, all name fields are non‑null.

Existing test pattern: Look at tests/api/streaks.py:130 for how API tests are structured.

4. Run Verification Commands

Execute the project’s test command as specified:

pip install -e '.[dev]' -q && python -m pytest {test_files}

Initially, run only the modified/new tests to confirm they pass, then run the full suite to ensure no regressions. If any unrelated failures appear (e.g. those seen in earlier attempts), verify they predate this change (should match baseline).

No lint command is explicitly required, but if a lint step is part of CI, ensure the change introduces no lint violations (e.g. unused imports, formatting). Run make lint or equivalent if available.


Definition of Done

  • The BadgeOut.name field in devplacepy/schemas/content.py has an alias "badge_name".
  • The codebase has been scanned for BadgeOut(name=...) constructions; if found, either those sites have been updated or populate_by_name=True has been added to the model config.
  • A test exists that calls the profile endpoint with Accept: application/json and asserts that every badge in the response has a non‑null name.
  • The new test passes when run in isolation.
  • The project’s full test suite (python -m pytest as specified) passes with no new failures.
  • No lint violations are introduced by the change.

Opened automatically by Typosaurus.

Resolves #113. ## Plan ## Implementation Plan: Fix Null Badge Names in Profile JSON Response ### 1. Code Change – Add Pydantic Alias to `BadgeOut.name` **File:** `devplacepy/schemas/content.py` - **Line 65** – Change the field definition from: ```python name: Optional[str] = None ``` to: ```python name: Optional[str] = Field(None, alias="badge_name") ``` - **Imports** – Ensure `from pydantic import Field` is present at the top of the file (it is already imported elsewhere in the module, but confirm the import is available. If not, add it.) This alias tells Pydantic to accept the key `badge_name` from the input dict (the raw database row) and serialize it as `name` in the JSON output. HTML rendering is unaffected because it reads `badge['badge_name']` directly from the raw dict before Pydantic processing. ### 2. Verify No Existing `BadgeOut` Constructions Use `name=` Keyword Argument Search the entire codebase for all occurrences of `BadgeOut(`. If any call site passes `name=` as a keyword argument (e.g., `BadgeOut(name="something")`), the alias will reject that input unless the model config includes `populate_by_name=True`. - **If none exist** → no further config change is needed. - **If some exist** → either: - Change those call sites to use `badge_name=` instead, or - Add `model_config = ConfigDict(populate_by_name=True)` to the `BadgeOut` class (or its parent `_Out`). Given the investigation flow (data comes from database dicts, not programmatic construction), it is expected no such keyword constructions exist. However, this must be confirmed. ### 3. Add a JSON‑Serialization Test for Badge Names **New test location:** `tests/api/profile.py` (or a dedicated schema test, e.g. `tests/unit/schemas/test_badge_out.py`). The test must: - Use the project’s `TestClient` to send a GET request to the profile endpoint with `Accept: application/json`. - Verify HTTP 200. - Parse the JSON response and confirm that each entry in `badges[]` has a non‑null `name` that matches the expected badge text for the test user’s badges. If the test database does not guarantee a badge for the test user, either: - Insert a temporary badge via fixture/database setup, or - Assert that if `badges` is non‑empty, all `name` fields are non‑null. **Existing test pattern:** Look at `tests/api/streaks.py:130` for how API tests are structured. ### 4. Run Verification Commands Execute the project’s test command as specified: ``` pip install -e '.[dev]' -q && python -m pytest {test_files} ``` Initially, run only the modified/new tests to confirm they pass, then run the full suite to ensure no regressions. If any unrelated failures appear (e.g. those seen in earlier attempts), verify they predate this change (should match baseline). No lint command is explicitly required, but if a lint step is part of CI, ensure the change introduces no lint violations (e.g. unused imports, formatting). Run `make lint` or equivalent if available. --- ## Definition of Done - [ ] The `BadgeOut.name` field in `devplacepy/schemas/content.py` has an alias `"badge_name"`. - [ ] The codebase has been scanned for `BadgeOut(name=...)` constructions; if found, either those sites have been updated or `populate_by_name=True` has been added to the model config. - [ ] A test exists that calls the profile endpoint with `Accept: application/json` and asserts that every badge in the response has a non‑null `name`. - [ ] The new test passes when run in isolation. - [ ] The project’s full test suite (`python -m pytest` as specified) passes with no new failures. - [ ] No lint violations are introduced by the change. Opened automatically by Typosaurus.
typosaurus added 1 commit 2026-07-23 05:20:24 +02:00
ticket #113 attempt 1
Some checks failed
DevPlace CI / test (pull_request) Failing after 11s
08b791d67a
Some checks failed
DevPlace CI / test (pull_request) Failing after 11s
This pull request has changes conflicting with the target branch.
  • .dpc/verify_cache.json
  • devplacepy/schemas/content.py
  • tests/api/profile/index.py

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin typosaurus/ticket-113:typosaurus/ticket-113
git checkout typosaurus/ticket-113
Sign in to join this conversation.
No reviewers
No Label
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: retoor/devplacepy#129
No description provided.