Skip to content

refactor(api): enforce type annotations on whitelisted methods - #303

Merged
harshtandiya merged 2 commits into
developfrom
refactor/api-enforce-types
Jul 29, 2026
Merged

refactor(api): enforce type annotations on whitelisted methods#303
harshtandiya merged 2 commits into
developfrom
refactor/api-enforce-types

Conversation

@harshtandiya

@harshtandiyaharshtandiya commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Stacked on #302 — read that first.

Turns on require_type_annotated_api_methods for buzz, the last step of the API
refactor, plus the dead surface the plan parked here.

The plan expected this PR to annotate eight whitelisted controller methods. It
annotates none: typing_validations.py:114-115 skips the first parameter when it
is self/cls, and every one of those methods takes only self. The two
module-level ones were already typed. An AST pass and a live frappe.whitelisted
walk both found zero unannotated arguments, so the hook flip is inert on today's
code — which is the point.

  • CI already blocks this statically.frappe/semgrep-rules'
    missing-argument-type-hint (rules/security/whitelisted.yml) is inside the path
    linter.yml:38-41 already scans. Verified: it catches an unannotated argument
    plain, behind an intervening decorator, and alongside *args/**kwargs, and
    semgrep ci exits 1 with the findings marked blocking. The hook is the runtime
    half — it sees what a syntactic rule cannot, and # nosemgrep doesn't silence it.
    A test asserting the same thing was written and then dropped as redundant.
  • The hook resolves per the defining function's app (typing_validations.py:31,44
    splits func.__module__), so setting it in buzz/hooks.py binds buzz.* only.
    It checks argument presence, never return annotations, and skips *args/**kwargs.
  • It fires inside the frappe.whitelist wrapper at call time
    (frappe/__init__.py:609, apply_condition=_in_request_or_test), so it is inert
    outside a request or test.
  • BuzzEvent.after_insert loses its whitelist — it made a lifecycle hook re-runnable
    via run_doc_method, duplicating default tiers and ticket types.
  • frappe.parse_json already returns a frappe._dict (frappe/utils/data.py:2661),
    so payments.py collapses to one call. orjson.JSONDecodeError subclasses
    json.JSONDecodeError, so widening event_booking.py's except to ValueError is
    a no-op that lets the json import go.
  • Deliberate non-change: payments.mark_payment_as_received early-returns on
    frappe.in_test (payments.py:126), so its parse_json swap has no test. Making
    that path testable is refactor(payments): clean up buzz/payments.py and make the settlement path testable #299.
  • The plan's fourth item, a commented buzz.api.download_ticket block in
    TicketDetails.vue, was already gone.

Checks: 354 Python tests green (run-tests --app buzz, 2 crm-gated skips); ruff
check and format clean; semgrep clean; Playwright 81/85 locally, the 4 failures
reproduced identically with this PR stashed (2 are the known guest-OTP
frappe.in_test gap, 2 are UI-login specs Harsh asked to ignore).

🤖 Generated with Claude Code

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@harshtandiyaharshtandiya added the backport main backport to main branch label Jul 29, 2026
@harshtandiya
harshtandiyaforce-pushed the refactor/api-enforce-types branch from e991297 to 2d5d39bCompareJuly 29, 2026 13:43

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@harshtandiya
harshtandiyaforce-pushed the refactor/api-enforce-types branch from 2d5d39b to 9448943CompareJuly 29, 2026 16:38

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@harshtandiya
harshtandiyaforce-pushed the refactor/api-enforce-types branch from 9448943 to ac5d02cCompareJuly 29, 2026 16:45

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@harshtandiya
harshtandiyaforce-pushed the refactor/api-enforce-types branch from ac5d02c to ece5d45CompareJuly 29, 2026 16:53

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@harshtandiya
harshtandiyaforce-pushed the refactor/api-enforce-types branch from ece5d45 to 11da4dbCompareJuly 29, 2026 17:00

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@harshtandiya
harshtandiyaforce-pushed the refactor/api-enforce-types branch from 11da4db to b1796daCompareJuly 29, 2026 17:17

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@harshtandiya
harshtandiyaforce-pushed the refactor/api-enforce-types branch from b1796da to f98f005CompareJuly 29, 2026 18:12

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

Base automatically changed from refactor/api-booking to developJuly 29, 2026 18:17
harshtandiyaand others added 2 commits July 29, 2026 23:48
Turn on require_type_annotated_api_methods so Frappe rejects any whitelisted
method whose arguments are not annotated. No annotations had to be added:
typing_validations.py skips the first parameter when it is self/cls, and every
whitelisted controller method in the app takes only self.
This is runtime cover for what CI already blocks statically. The Linters
workflow runs frappe/semgrep-rules, whose missing-argument-type-hint rule
(rules/security/whitelisted.yml) fails the build on an unannotated whitelisted
argument. The hook catches what a syntactic rule cannot see, and unlike semgrep
it cannot be silenced with a nosemgrep comment.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
BuzzEvent.after_insert was whitelisted, which made a lifecycle hook remotely
re-runnable through run_doc_method. Re-running it duplicates the default
sponsorship tiers and ticket types and then calls save(ignore_permissions=True).
Nothing calls it remotely.
Replace the last two json.loads calls with frappe.parse_json. It already returns
a frappe._dict for dict payloads, so payments.py collapses to a single call and
its function-local import goes with it. In event_booking.py the except clause
widens to (ValueError, TypeError): orjson.JSONDecodeError subclasses
json.JSONDecodeError so the old clause still caught it, but naming json there
was the last reason to keep the module imported.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@harshtandiya
harshtandiyaforce-pushed the refactor/api-enforce-types branch from f98f005 to 30f3175CompareJuly 29, 2026 18:18

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@harshtandiya
harshtandiya merged commit a4f52b2 into developJul 29, 2026
7 checks passed
@harshtandiya
harshtandiya deleted the refactor/api-enforce-types branch July 29, 2026 18:23
@github-actions

Copy link
Copy Markdown
Contributor

Successfully created backport PR for main:

harshtandiya added a commit that referenced this pull request Jul 29, 2026
Brings main to parity with develop at a4f52b2: the buzz/api domain package
split (#295-#303), the shared bench setup action (#305), and the backport
workflow (#273, #291). Tree is identical to develop at a4f52b2.
harshtandiya added a commit that referenced this pull request Jul 29, 2026
Brings main to parity with develop at a4f52b2: the buzz/api domain package
split (#295-#303), the shared bench setup action (#305), and the backport
workflow (#273, #291). Tree is identical to develop at a4f52b2.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport mainbackport to main branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@harshtandiya