Fix #111: Add optionality info to API definition for nullable properties #126

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

Resolves #111.

Plan

Implementation Plan: Add Nullable Annotations to Custom /docs API Definition

1. Modified Files & Changes

File Change
devplacepy/docs_api/_shared.py Add nullable: bool = False parameter to field(). Store it in the field metadata dictionary.
devplacepy/docs_examples.py Update schema_example(): after generating a sample value via _unwrap_optional(), if the field has nullable=True and the generated value is not already None, replace it with None (JSON null). Also append " (nullable)" to the field’s label or description in the generated example dict.
devplacepy/routers/profile.py (or wherever ProfileOut endpoint is defined) In the field() call for the projects list member (or the relevant response field), add nullable=True for each Optional field that is currently nullable. For example: field(name="updated_at", type=str, nullable=True). If the router uses a shared schema definition, add annotations there.
static/js/ApiTester.js (approximate path: devplacepy/static/ or docs_api/static/) In renderExpected() (line ~318), check if the field object has a nullable property. If true, append a small badge or label like [nullable] next to the field name in the JSON sample (e.g., as a comment or in a separate column). Alternative: render the sample value as null with a tooltip.
New test file: tests/unit/test_docs_nullable.py Write unit tests that:
– Verify field(nullable=True) sets the metadata correctly.
– Verify schema_example() produces null for a nullable field.
– Verify the rendered JSON snippet in ApiTester.js includes a nullability indicator (requires a Playwright screenshot or DOM assertion – optional if unit tests for Python logic are sufficient).

2. Detailed Steps (for a competent engineer)

Step A – In devplacepy/docs_api/_shared.py:

  • Add nullable: bool = False to the function signature of field().
  • Inside field(), add a key "nullable" to the returned dict (or to the field metadata) set to the value of nullable.

Step B – In devplacepy/docs_examples.py:

  • Locate the _unwrap_optional() call (line ~45). After resolving the final type and generating a default sample, check if the field’s metadata dict has "nullable": True.
  • If so, replace the generated sample value with None (JSON null) in the output dict.
  • Also modify the field’s label string (if any) to append " (nullable)".

Step C – Update router definitions:

  • Find all endpoints that use ProjectOut or ProfileOut and whose field() calls currently lack nullable=True for Optional fields.
  • Add nullable=True to field(name="updated_at", ...).
  • Repeat for other fields that are Optional[...] in the Pydantic schemas but are only referenced through the field() function for /docs (the router might not use field() at all – if that’s the case, skip and the sample generator will infer nullability from the Pydantic model if the model is used directly. The ticket’s custom docs may not use Pydantic models directly; it uses field() calls. We must assume that each endpoint manually lists fields via field() – verify in the code).

Step D – Modify ApiTester.js:

  • In the renderExpected() method, iterate over the fields of the example response (the sample object). If a field metadata has nullable: true, add a small attribute or CSS class to the rendered <code> element, or insert a <span class="nullable-badge">nullable</span> after the field name for human readers.

Step E – Write unit tests:

  • test_field_nullable_parameter() calls field(nullable=True) and checks returned dict.
  • test_schema_example_nullable_field() creates a mock schema with a nullable field and calls schema_example(), asserts None appears in output.
  • (Optional) test_api_tester_renders_nullable() uses Playwright to open the /docs page for a known endpoint and checks that the nullable badge is present.

3. Definition of Done

  • The field() function in devplacepy/docs_api/_shared.py accepts nullable: bool = False and stores it.
  • The schema_example() function in devplacepy/docs_examples.py returns null in JSON for any field marked nullable=True.
  • All endpoints that return ProjectOut or ProfileOut have their field() definitions updated to pass nullable=True on fields like updated_at.
  • The custom /docs page displays a visual indicator (badge or label) next to nullable fields in the sample response.
  • All existing unit tests pass.
  • The project’s verification command succeeds:
    pip install -e '.[dev]' -q && python -m pytest tests/unit/test_docs_nullable.py tests/unit/test_docs_examples.py tests/unit/test_shared.py
    
    (or the minimal set of test files that cover the changed modules; if no such files exist, create them as part of the plan and ensure they pass.)
  • No regression in the previously failed e2e tests (those tests failed due to Playwright environment issues unrelated to this change; the new code must not introduce additional Playwright failures – run pytest tests/e2e/ in a compatible environment to confirm).

Opened automatically by Typosaurus.

Resolves #111. ## Plan ## Implementation Plan: Add Nullable Annotations to Custom /docs API Definition ### 1. Modified Files & Changes | File | Change | |---|---| | `devplacepy/docs_api/_shared.py` | Add `nullable: bool = False` parameter to `field()`. Store it in the field metadata dictionary. | | `devplacepy/docs_examples.py` | Update `schema_example()`: after generating a sample value via `_unwrap_optional()`, if the field has `nullable=True` and the generated value is not already `None`, replace it with `None` (JSON `null`). Also append `" (nullable)"` to the field’s label or description in the generated example dict. | | `devplacepy/routers/profile.py` (or wherever `ProfileOut` endpoint is defined) | In the `field()` call for the `projects` list member (or the relevant response field), add `nullable=True` for each Optional field that is currently nullable. For example: `field(name="updated_at", type=str, nullable=True)`. If the router uses a shared schema definition, add annotations there. | | `static/js/ApiTester.js` (approximate path: `devplacepy/static/` or `docs_api/static/`) | In `renderExpected()` (line ~318), check if the field object has a `nullable` property. If true, append a small badge or label like `[nullable]` next to the field name in the JSON sample (e.g., as a comment or in a separate column). Alternative: render the sample value as `null` with a tooltip. | | New test file: `tests/unit/test_docs_nullable.py` | Write unit tests that: <br>– Verify `field(nullable=True)` sets the metadata correctly.<br>– Verify `schema_example()` produces `null` for a nullable field.<br>– Verify the rendered JSON snippet in `ApiTester.js` includes a nullability indicator (requires a Playwright screenshot or DOM assertion – optional if unit tests for Python logic are sufficient). | ### 2. Detailed Steps (for a competent engineer) **Step A** – In `devplacepy/docs_api/_shared.py`: - Add `nullable: bool = False` to the function signature of `field()`. - Inside `field()`, add a key `"nullable"` to the returned dict (or to the field metadata) set to the value of `nullable`. **Step B** – In `devplacepy/docs_examples.py`: - Locate the `_unwrap_optional()` call (line ~45). After resolving the final type and generating a default sample, check if the field’s metadata dict has `"nullable": True`. - If so, replace the generated sample value with `None` (JSON `null`) in the output dict. - Also modify the field’s label string (if any) to append `" (nullable)"`. **Step C** – Update router definitions: - Find all endpoints that use `ProjectOut` or `ProfileOut` and whose `field()` calls currently lack `nullable=True` for Optional fields. - Add `nullable=True` to `field(name="updated_at", ...)`. - Repeat for other fields that are `Optional[...]` in the Pydantic schemas but are only referenced through the `field()` function for /docs (the router might not use `field()` at all – if that’s the case, skip and the sample generator will infer nullability from the Pydantic model if the model is used directly. The ticket’s custom docs may not use Pydantic models directly; it uses `field()` calls. We must assume that each endpoint manually lists fields via `field()` – verify in the code). **Step D** – Modify `ApiTester.js`: - In the `renderExpected()` method, iterate over the fields of the example response (the sample object). If a field metadata has `nullable: true`, add a small attribute or CSS class to the rendered `<code>` element, or insert a `<span class="nullable-badge">nullable</span>` after the field name for human readers. **Step E** – Write unit tests: - `test_field_nullable_parameter()` calls `field(nullable=True)` and checks returned dict. - `test_schema_example_nullable_field()` creates a mock schema with a nullable field and calls `schema_example()`, asserts `None` appears in output. - (Optional) `test_api_tester_renders_nullable()` uses Playwright to open the /docs page for a known endpoint and checks that the nullable badge is present. ### 3. Definition of Done - [ ] The `field()` function in `devplacepy/docs_api/_shared.py` accepts `nullable: bool = False` and stores it. - [ ] The `schema_example()` function in `devplacepy/docs_examples.py` returns `null` in JSON for any field marked `nullable=True`. - [ ] All endpoints that return `ProjectOut` or `ProfileOut` have their `field()` definitions updated to pass `nullable=True` on fields like `updated_at`. - [ ] The custom /docs page displays a visual indicator (badge or label) next to nullable fields in the sample response. - [ ] All existing unit tests pass. - [ ] The project’s verification command succeeds: ``` pip install -e '.[dev]' -q && python -m pytest tests/unit/test_docs_nullable.py tests/unit/test_docs_examples.py tests/unit/test_shared.py ``` (or the minimal set of test files that cover the changed modules; if no such files exist, create them as part of the plan and ensure they pass.) - [ ] No regression in the previously failed e2e tests (those tests failed due to Playwright environment issues unrelated to this change; the new code must not introduce additional Playwright failures – run `pytest tests/e2e/` in a compatible environment to confirm). Opened automatically by Typosaurus.
typosaurus added 1 commit 2026-07-23 05:08:23 +02:00
ticket #111 attempt 1
Some checks failed
DevPlace CI / test (pull_request) Failing after 11s
38c2bab503
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

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin typosaurus/ticket-111:typosaurus/ticket-111
git checkout typosaurus/ticket-111
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#126
No description provided.