Skip to content

Implement urls module with reverse and reverse_lazy#234

Open
dbrun3 wants to merge 3 commits into
dj-bolt:masterfrom
dbrun3:url-reverse-template-tag
Open

Implement urls module with reverse and reverse_lazy#234
dbrun3 wants to merge 3 commits into
dj-bolt:masterfrom
dbrun3:url-reverse-template-tag

Conversation

@dbrun3
Copy link
Copy Markdown
Contributor

@dbrun3 dbrun3 commented Jun 2, 2026

Fixes #114

Implements a bolt urls module with reverse and reverse_lazy, wrapping the original functionality while handling bolt routes with a synthetic URLconf. Monkey patches new implementations over Django's, which allows {% url %} tags to resolve to their correct bolt routes. Adds the ability to add names to routes, but will also auto-resolve by function name, including namespace support (module containing api.py) for cases with ambiguity. Additionally handles viewsets with action suffixes like '-list' and '-retrieve'.

Note: Auto-resolved names are slugs such that CamelCase and snake_case class names and functions get 'resolved-to-this-format'. Totally cool with changing if controversial.

How was this tested?

  • just lint-lib and just test-py pass
  • If Rust was changed: just rebuild succeeds
  • If a new feature is added: tested manually in the example project (python/example/)

Performance consideration

Should cost the same as 'native' Django reversal, which is cached.

Hot Request Path Impact: YES, but Efficiently Designed

Does This PR Touch the Hot Request Path?

YES — The reverse() function is called during every request that uses the {% url %} template tag or explicitly calls reverse() in views. This PR monkey-patches Django's global reverse() function, so the new code executes in these scenarios.

Is the Work Required and Justified?

YES — This PR solves issue #114 by making Bolt routes discoverable through Django's standard URL reversing mechanism. Without this, the template tag would fail for any Bolt routes.

Performance Verdict: EFFICIENT — Minimal Hot-Path Overhead

The implementation demonstrates excellent performance design with clear separation between startup and request-time costs:

REQUEST-TIME OVERHEAD (per reverse() call)

  • Minimal: Just 3-4 lightweight operations:

    1. Check if urlconf is None (variable comparison)
    2. Call _bolt_routes_present() (returns cached boolean after first call)
    3. Try _django_reverse() against pre-built Bolt urlconf (Django's resolver caches this)
    4. Optional: Prepend cached django_mount_prefix string on Django fallback
  • Module-level caching: _django_mount_prefix and _has_bolt_routes are computed once at first use and cached as module variables, not recomputed per request

  • Django's resolver cache: The synthetic bolt_urlconf is referenced by name so Django's get_resolver() caches it via LRU, eliminating pattern-matching overhead after first reversal

STARTUP-TIME WORK (One-time, not on request path)

At app initialization (apps.py ready() method):

  • _bolt_urlconf.py imports and runs: autodiscover(), API merging, pattern building, mount-prefix detection
  • These expensive operations happen once at startup and are memoized as module-level variables
  • Subsequent requests reuse cached results

PERFORMANCE CHARACTERISTICS

Best Case (Bolt route matches):

  • O(1) cached lookup via Django's resolver
  • Same cost as native Django reversal

Average Case (Django route fallback):

  • One try/except wrapper + one Django reverse() + string concatenation
  • Overhead: 2-3 extra function calls vs vanilla Django

Worst Case (no match):

  • Two reversal attempts before NoReverseMatch raised
  • Both use Django's cached resolver, so still acceptable

SMART SHORT-CIRCUITS

  • If urlconf explicitly provided → skip Bolt, delegate directly to Django
  • If no Bolt routes discovered → empty urlpatterns causes fast fallback to Django every call
  • Projects without Bolt routes see minimal overhead (just the short-circuit check)

Conclusion

The PR correctly balances functionality and performance. Expensive work (autodiscovery, pattern building) happens at startup, while request-time operations are lightweight and fully cached. This is the right architectural approach for solving URL resolution without impacting application throughput.

dbrun3 added 3 commits June 2, 2026 15:42
…lt urls module with reverse and reverse_lazy wrappers.

notes: monkey patches new functions into django internals allowing url template tags to resolve. auto-resolved names are slugified versions of their functions
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 2, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds URL reversing support for Bolt routes, enabling Django's {% url %} template tag and reverse() function to work with Bolt-defined endpoints. It introduces route naming metadata, extends decorators to accept names, generates a synthetic Django urlconf from Bolt routes, and monkey-patches Django's reversing to query Bolt routes first before falling back to Django routes.

Changes

Django-Bolt URL Reversing

Layer / File(s) Summary
Metadata schema and naming infrastructure
python/django_bolt/typing.py, python/django_bolt/decorators.py, python/django_bolt/api.py
HandlerMetadata TypedDict gains name, name_explicit, and namespace fields for URL reversing. ActionHandler extends to store custom action names. Helper functions _slugify_route_name() and _route_namespace() compute reverse-friendly names from user input or handler module context.
Route registration with naming
python/django_bolt/api.py, python/django_bolt/decorators.py
All HTTP method decorators (get, post, put, patch, delete, head, options), websocket(), view(), and viewset() now accept an optional name parameter. _route_decorator populates naming metadata using the helpers. Viewset standard CRUD actions are auto-named {base}-{action}, and custom actions via @action(name=...) are named {base}-{custom_name}.
Synthetic Django urlconf generation
python/django_bolt/_bolt_urlconf.py
At import time, discovers and merges all Bolt APIs, collects named HTTP and websocket routes, converts Bolt path syntax to Django path converters, generates urlpatterns with deduplication and conflict detection on explicit names, and detects mounted Django apps to extract their URL prefix.
Django URL reversing integration
python/django_bolt/urls.py
Exports reverse() and reverse_lazy() that first attempt to resolve route names against the synthetic Bolt urlconf, then fall back to Django's original reverse() with a cached mount prefix prepended. patch_django_reverse() replaces Django's reverse exports globally and patches already-imported modules in sys.modules.
App initialization hook
python/django_bolt/apps.py
DjangoBoltConfig.ready() invokes patch_django_reverse() during Django startup to activate Bolt-aware URL reversing before any name resolution.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 A clever hare weaves Bolt routes bright,
With names that dance in Django's light,
From metadata traced to patterns sewn,
The synthetic urlconf takes its own,
And reverse() hops both ways with delight!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main change: implementing a urls module with reverse and reverse_lazy functionality.
Linked Issues check ✅ Passed The PR fully addresses issue #114 by making bolt routes resolvable through Django's reverse mechanism via monkey-patching, enabling template url tags to work with bolt routes.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing URL reversing for bolt routes and supporting the url template tag, with no unrelated modifications detected.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@dbrun3
Copy link
Copy Markdown
Contributor Author

dbrun3 commented Jun 2, 2026

Could definitely use some tests, but want to be sure about the auto-resolve naming conventions first

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
python/django_bolt/decorators.py (1)

50-57: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add the repo-standard future import to this file.

This change adds more modern annotations, but python/django_bolt/decorators.py still lacks from __future__ import annotations. Please add it at the module top while touching this file.

Suggested change
+from __future__ import annotations
+
 from collections.abc import Callable
 from typing import Any

As per coding guidelines, **/*.py: Use from __future__ import annotations at the top of Python files for cleaner type hints across the codebase.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/django_bolt/decorators.py` around lines 50 - 57, Add the repo-standard
future import by inserting "from __future__ import annotations" at the very top
of python/django_bolt/decorators.py (above any other imports or code) so the new
forward-style type annotations used in the Decorator class and its __init__
signature (fn: Callable, methods: list[str], detail: bool, path: str | None,
name: str | None, auth: list[Any] | None) are evaluated as postponed annotations
across the module.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@python/django_bolt/_bolt_urlconf.py`:
- Around line 78-90: The code currently appends a bare root-level alias for
every (namespace, name) in chosen which creates duplicate bare names when
different namespaces share the same name; update the loop that builds bare and
by_namespace so you first compute global counts of each name from chosen, then
only call _django_path(route, _reverse_only_view, name=name) and append it to
bare when that name's global count == 1 (otherwise skip creating the bare alias
for that (namespace,name)); still register the namespaced entry into
by_namespace for any namespace using the existing
by_namespace.setdefault(...).append(...) logic so _django_path and
_reverse_only_view usages remain unchanged.

In `@python/django_bolt/api.py`:
- Around line 129-133: The namespace logic in _route_namespace is too coarse;
replace the simple top-level segment rule with detection of the Django app
boundary by checking django.apps.apps.get_app_configs() to find an AppConfig
whose module path is a prefix of getattr(fn, "__module__", "") and use that
app's label (or app.module split) as the namespace; if no AppConfig matches,
fall back to the original _slugify_route_name(top) behavior. Update
_route_namespace to iterate django.apps.apps.get_app_configs(), compare
app.module to the handler module prefix, pick the longest matching app.module to
handle nested packages (e.g., project.apps.missions vs project.apps.billing),
and then slugify that chosen app identifier.
- Around line 1281-1292: The decorator call currently passes only
base_name_explicit to _name_explicit which ignores when an action itself has an
explicit name; update the logic around action_suffix/action_route_name to
compute an action_name_explicit flag (e.g., action_name_explicit = attr.name is
not None) and pass _name_explicit=(base_name_explicit or action_name_explicit)
into self._route_decorator so explicit action names are respected; adjust
references to attr.name, action_route_name, _route_decorator and
base_name_explicit accordingly.

In `@python/django_bolt/apps.py`:
- Around line 9-13: Move the inline import out of ready(): add "from __future__
import annotations" at the top of the module and hoist "from .urls import
patch_django_reverse" to module scope, then simplify ready() to just call
patch_django_reverse(); ensure no other inline imports remain and keep import
ordering consistent with existing style.

---

Outside diff comments:
In `@python/django_bolt/decorators.py`:
- Around line 50-57: Add the repo-standard future import by inserting "from
__future__ import annotations" at the very top of
python/django_bolt/decorators.py (above any other imports or code) so the new
forward-style type annotations used in the Decorator class and its __init__
signature (fn: Callable, methods: list[str], detail: bool, path: str | None,
name: str | None, auth: list[Any] | None) are evaluated as postponed annotations
across the module.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3c64532f-f584-418b-9831-9924c0f3a83a

📥 Commits

Reviewing files that changed from the base of the PR and between 02057c8 and 428e69f.

📒 Files selected for processing (6)
  • python/django_bolt/_bolt_urlconf.py
  • python/django_bolt/api.py
  • python/django_bolt/apps.py
  • python/django_bolt/decorators.py
  • python/django_bolt/typing.py
  • python/django_bolt/urls.py

Comment on lines +78 to +90
for (namespace, name), (route, _explicit) in chosen.items():
# Bare (root) name so {% url 'name' %} works without a prefix, like a
# non-namespaced Django include. Every route also gets a namespaced alias.
bare.append(_django_path(route, _reverse_only_view, name=name))
if namespace:
by_namespace.setdefault(namespace, []).append(
_django_path(route, _reverse_only_view, name=name)
)

# Bare names first; namespaced aliases follow for disambiguation.
urlpatterns: list = list(bare)
for namespace, patterns in by_namespace.items():
urlpatterns.append(_django_path("", include((patterns, namespace))))
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot Jun 2, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't emit bare aliases for namespaced collisions.

This appends a root-level name= entry for every route before adding the namespaced include. If two namespaces both define the same route name, the synthetic urlconf now contains two bare patterns with that name as well, so the unqualified reverse stays ambiguous and can resolve the wrong route. Only create the bare alias when a name is globally unique, or skip the bare alias for namespaced routes entirely.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/django_bolt/_bolt_urlconf.py` around lines 78 - 90, The code currently
appends a bare root-level alias for every (namespace, name) in chosen which
creates duplicate bare names when different namespaces share the same name;
update the loop that builds bare and by_namespace so you first compute global
counts of each name from chosen, then only call _django_path(route,
_reverse_only_view, name=name) and append it to bare when that name's global
count == 1 (otherwise skip creating the bare alias for that (namespace,name));
still register the namespaced entry into by_namespace for any namespace using
the existing by_namespace.setdefault(...).append(...) logic so _django_path and
_reverse_only_view usages remain unchanged.

Copy link
Copy Markdown
Contributor Author

@dbrun3 dbrun3 Jun 2, 2026

Choose a reason for hiding this comment

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

I believe this mimics Django behavior (masking).. Namespacing is also automatic/implicit by module with the autoresolving logic so it should be available when names may mask eachother. However, yes there should be a more concrete spec for how these are handled

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.

@dbrun3, that's a fair point — Django itself lets bare names coexist alongside namespaced ones (e.g. {% url 'list' %} and {% url 'missions:list' %} both resolve), so the current approach is a reasonable parallel.

The residual concern is purely the first-match wins behaviour for unqualified lookups: if two namespaces register the same bare name, the route that lands first in chosen.items() (dict insertion order, i.e. discovery order) silently wins. That's also Django-like — but it's easy to miss for users who don't expect it and don't use the qualified namespace:name form.

A concrete spec clarifying that behaviour would remove the ambiguity. Would you like me to open a follow-up issue to track that?


✏️ Learnings added
Learnt from: dbrun3
Repo: dj-bolt/django-bolt PR: 234
File: python/django_bolt/_bolt_urlconf.py:78-90
Timestamp: 2026-06-02T22:26:00.116Z
Learning: In `python/django_bolt/_bolt_urlconf.py`, bare (root-level) URL aliases are intentionally emitted for every named route, including those that also have a namespace, to mimic Django's behavior where `{% url 'name' %}` and `{% url 'namespace:name' %}` can coexist. When two namespaces share the same bare name, first-match (dict/discovery order) wins for unqualified reversal — this is accepted by design, but a concrete spec for collision resolution is still pending.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: dbrun3
Repo: dj-bolt/django-bolt PR: 234
File: python/django_bolt/api.py:129-133
Timestamp: 2026-06-02T22:19:34.181Z
Learning: In `python/django_bolt/api.py`, the `_route_namespace()` helper is intended to return the **penultimate** module segment — the segment immediately before the last one (e.g. `api`). For `project.apps.missions.api`, the namespace should be `missions`; for `project.apps.billing.api` it should be `billing`. The current implementation (`module.split(".", 1)[0]`) is a known bug that returns the top-level package instead.

Learnt from: CR
Repo: dj-bolt/django-bolt PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-05-26T17:31:31.163Z
Learning: Applies to python/django_bolt/management/commands/runbolt.py : Use Django management command autodiscovery pattern to find `api.py` files in Django project root and installed apps

Learnt from: CR
Repo: dj-bolt/django-bolt PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-05-26T17:31:31.163Z
Learning: Applies to {python/django_bolt/api.py,python/django_bolt/router.py} : Guarantee route metadata keys at registration time: required keys are `mode`, `is_async`, `default_status_code`, `response_type` with direct access in dispatch path

Learnt from: CR
Repo: dj-bolt/django-bolt PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-05-26T17:31:31.163Z
Learning: Applies to {python/django_bolt/api.py,python/django_bolt/router.py} : All route metadata keys must be guaranteed at registration time so the dispatch path uses direct `meta["key"]` access instead of `meta.get("key", default)`. Required keys: `mode`, `is_async`, `default_status_code`, `response_type`

Comment thread python/django_bolt/api.py
Comment on lines +129 to +133
def _route_namespace(fn: Callable) -> str:
"""Derive the URL-reverse namespace for a handler from its module."""
module = getattr(fn, "__module__", "") or ""
top = module.split(".", 1)[0]
return _slugify_route_name(top)
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot Jun 2, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Namespace derivation is too coarse for nested app layouts.

module.split(".", 1)[0] only keeps the top-level package. In layouts like project.apps.missions.api and project.apps.billing.api, both handlers end up in the project namespace, so the ambiguity this feature is meant to resolve is still there. The namespace needs to be derived from the discovered Bolt app/module boundary, not the first module segment.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/django_bolt/api.py` around lines 129 - 133, The namespace logic in
_route_namespace is too coarse; replace the simple top-level segment rule with
detection of the Django app boundary by checking
django.apps.apps.get_app_configs() to find an AppConfig whose module path is a
prefix of getattr(fn, "__module__", "") and use that app's label (or app.module
split) as the namespace; if no AppConfig matches, fall back to the original
_slugify_route_name(top) behavior. Update _route_namespace to iterate
django.apps.apps.get_app_configs(), compare app.module to the handler module
prefix, pick the longest matching app.module to handle nested packages (e.g.,
project.apps.missions vs project.apps.billing), and then slugify that chosen app
identifier.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Should always be second to last (module name prior to api). Noted

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.

@dbrun3, got it — the namespace should always be the penultimate module segment (the one immediately before api), so project.apps.missions.apimissions and project.apps.billing.apibilling. That's a much cleaner rule than walking AppConfigs.

The fix would be something like:

def _route_namespace(fn: Callable) -> str:
    """Derive the URL-reverse namespace for a handler from its module."""
    module = getattr(fn, "__module__", "") or ""
    parts = module.rsplit(".", 1)
    # Use the segment immediately before the last one (e.g. "missions" from "project.apps.missions.api")
    segment = parts[0].rsplit(".", 1)[-1] if len(parts) > 1 else parts[0]
    return _slugify_route_name(segment)

I'll record this for future reviews.


✏️ Learnings added
Learnt from: dbrun3
Repo: dj-bolt/django-bolt PR: 234
File: python/django_bolt/api.py:129-133
Timestamp: 2026-06-02T22:19:34.181Z
Learning: In `python/django_bolt/api.py`, the `_route_namespace()` helper is intended to return the **penultimate** module segment — the segment immediately before the last one (e.g. `api`). For `project.apps.missions.api`, the namespace should be `missions`; for `project.apps.billing.api` it should be `billing`. The current implementation (`module.split(".", 1)[0]`) is a known bug that returns the top-level package instead.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: CR
Repo: dj-bolt/django-bolt PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-05-26T17:31:31.163Z
Learning: Applies to {python/django_bolt/api.py,python/django_bolt/router.py} : All route metadata keys must be guaranteed at registration time so the dispatch path uses direct `meta["key"]` access instead of `meta.get("key", default)`. Required keys: `mode`, `is_async`, `default_status_code`, `response_type`

Learnt from: CR
Repo: dj-bolt/django-bolt PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-05-26T17:31:31.163Z
Learning: Applies to {python/django_bolt/api.py,python/django_bolt/router.py} : Guarantee route metadata keys at registration time: required keys are `mode`, `is_async`, `default_status_code`, `response_type` with direct access in dispatch path

Comment thread python/django_bolt/api.py
Comment on lines +1281 to +1292
# Derive the action's reverse name: base + suffix. The suffix is
# the @action name override (explicit) or the function name
# (derived). attr.path is the URL segment, not a name source.
action_suffix = attr.name or unbound_fn.__name__
action_route_name = f"{base_name}-{action_suffix}" if base_name else action_suffix

# Register using existing route decorator
decorator = self._route_decorator(
http_method,
action_path,
name=action_route_name,
_name_explicit=base_name_explicit,
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot Jun 2, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep @action(name=...) explicit even when the viewset base name is derived.

_name_explicit only reflects whether the viewset itself was named. If the viewset uses its derived base but a custom action sets name=, the final route is still marked as derived. That breaks the explicit-name precedence/collision handling in _bolt_urlconf — e.g. an explicit custom action named "list" on an unnamed viewset is treated the same as the generated -list route.

Suggested change
                     decorator = self._route_decorator(
                         http_method,
                         action_path,
                         name=action_route_name,
-                        _name_explicit=base_name_explicit,
+                        _name_explicit=base_name_explicit or attr.name is not None,
                         response_model=attr.response_model,
                         status_code=attr.status_code,
                         validate_response=final_validate_response,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Derive the action's reverse name: base + suffix. The suffix is
# the @action name override (explicit) or the function name
# (derived). attr.path is the URL segment, not a name source.
action_suffix = attr.name or unbound_fn.__name__
action_route_name = f"{base_name}-{action_suffix}" if base_name else action_suffix
# Register using existing route decorator
decorator = self._route_decorator(
http_method,
action_path,
name=action_route_name,
_name_explicit=base_name_explicit,
# Derive the action's reverse name: base + suffix. The suffix is
# the `@action` name override (explicit) or the function name
# (derived). attr.path is the URL segment, not a name source.
action_suffix = attr.name or unbound_fn.__name__
action_route_name = f"{base_name}-{action_suffix}" if base_name else action_suffix
# Register using existing route decorator
decorator = self._route_decorator(
http_method,
action_path,
name=action_route_name,
_name_explicit=base_name_explicit or attr.name is not None,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/django_bolt/api.py` around lines 1281 - 1292, The decorator call
currently passes only base_name_explicit to _name_explicit which ignores when an
action itself has an explicit name; update the logic around
action_suffix/action_route_name to compute an action_name_explicit flag (e.g.,
action_name_explicit = attr.name is not None) and pass
_name_explicit=(base_name_explicit or action_name_explicit) into
self._route_decorator so explicit action names are respected; adjust references
to attr.name, action_route_name, _route_decorator and base_name_explicit
accordingly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Should also decide whether or not a custom action should still use a derived base or not... I'll let @FarhanAliRaza make the judgement call here.

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.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment on lines +9 to +13
def ready(self):
# Install django_bolt.urls.reverse patch.
from .urls import patch_django_reverse

patch_django_reverse()
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.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Move the patch import to module scope.

The new ready() uses an inline import, which violates the repo import rule and looks unnecessary here. Please hoist patch_django_reverse to the module top and add the standard future import while touching this file.

Suggested change
+from __future__ import annotations
+
 from django.apps import AppConfig
+from .urls import patch_django_reverse
@@
-    def ready(self):
+    def ready(self) -> None:
         # Install django_bolt.urls.reverse patch.
-        from .urls import patch_django_reverse
-
         patch_django_reverse()

As per coding guidelines, **/*.py: Use from __future__ import annotations at the top of Python files for cleaner type hints across the codebase; place all imports at the module top level, never use inline imports.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/django_bolt/apps.py` around lines 9 - 13, Move the inline import out
of ready(): add "from __future__ import annotations" at the top of the module
and hoist "from .urls import patch_django_reverse" to module scope, then
simplify ready() to just call patch_django_reverse(); ensure no other inline
imports remain and keep import ordering consistent with existing style.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Some url related template tag will not work

1 participant