docs: move extension command- and url-related API to own API pages (#1093)

* docs: move extension command- and url-related API to own API pages

* refactor: fix linters
This commit is contained in:
Juro Oravec 2025-04-06 14:12:15 +02:00 committed by GitHub
parent 0ed46e4d30
commit 3555411f1e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 312 additions and 97 deletions

View file

@ -394,7 +394,7 @@ Where:
### Defining Commands
To define a command, subclass from [`ComponentCommand`](../../../reference/api#django_components.ComponentCommand).
To define a command, subclass from [`ComponentCommand`](../../../reference/extension_commands#django_components.ComponentCommand).
This subclass should define:
- `name` - the command's name
@ -419,12 +419,12 @@ class MyExt(ComponentExtension):
### Defining Command Arguments and Options
Commands can accept positional arguments and options (e.g. `--foo`), which are defined using the
[`arguments`](../../../reference/api#django_components.ComponentCommand.arguments)
attribute of the [`ComponentCommand`](../../../reference/api#django_components.ComponentCommand) class.
[`arguments`](../../../reference/extension_commands#django_components.ComponentCommand.arguments)
attribute of the [`ComponentCommand`](../../../reference/extension_commands#django_components.ComponentCommand) class.
The arguments are parsed with [`argparse`](https://docs.python.org/3/library/argparse.html)
into a dictionary of arguments and options. These are then available
as keyword arguments to the [`handle`](../../../reference/api#django_components.ComponentCommand.handle)
as keyword arguments to the [`handle`](../../../reference/extension_commands#django_components.ComponentCommand.handle)
method of the command.
```python
@ -470,20 +470,20 @@ python manage.py components ext run my_ext hello John --shout
See the [argparse documentation](https://docs.python.org/3/library/argparse.html) for more information.
django-components defines types as
[`CommandArg`](../../../reference/api#django_components.CommandArg),
[`CommandArgGroup`](../../../reference/api#django_components.CommandArgGroup),
[`CommandSubcommand`](../../../reference/api#django_components.CommandSubcommand),
and [`CommandParserInput`](../../../reference/api#django_components.CommandParserInput)
[`CommandArg`](../../../reference/extension_commands#django_components.CommandArg),
[`CommandArgGroup`](../../../reference/extension_commands#django_components.CommandArgGroup),
[`CommandSubcommand`](../../../reference/extension_commands#django_components.CommandSubcommand),
and [`CommandParserInput`](../../../reference/extension_commands#django_components.CommandParserInput)
to help with type checking.
!!! note
If a command doesn't have the [`handle`](../../../reference/api#django_components.ComponentCommand.handle)
If a command doesn't have the [`handle`](../../../reference/extension_commands#django_components.ComponentCommand.handle)
method defined, the command will print a help message and exit.
### Grouping Arguments
Arguments can be grouped using [`CommandArgGroup`](../../../reference/api#django_components.CommandArgGroup)
Arguments can be grouped using [`CommandArgGroup`](../../../reference/extension_commands#django_components.CommandArgGroup)
to provide better organization and help messages.
Read more on [argparse argument groups](https://docs.python.org/3/library/argparse.html#argument-groups).
@ -539,12 +539,12 @@ class HelloCommand(ComponentCommand):
Extensions can define subcommands, allowing for more complex command structures.
Subcommands are defined similarly to root commands, as subclasses of
[`ComponentCommand`](../../../reference/api#django_components.ComponentCommand) class.
[`ComponentCommand`](../../../reference/extension_commands#django_components.ComponentCommand) class.
However, instead of defining the subcommands in the
[`commands`](../../../reference/api#django_components.ComponentExtension.commands)
[`commands`](../../../reference/extension_commands#django_components.ComponentExtension.commands)
attribute of the extension, you define them in the
[`subcommands`](../../../reference/api#django_components.ComponentCommand.subcommands)
[`subcommands`](../../../reference/extension_commands#django_components.ComponentCommand.subcommands)
attribute of the parent command:
```python
@ -663,7 +663,7 @@ def test_hello_command(self):
Extensions can define custom views and endpoints that can be accessed through the Django application.
To define URLs for an extension, set them in the [`urls`](../../../reference/api#django_components.ComponentExtension.urls) attribute of your [`ComponentExtension`](../../../reference/api#django_components.ComponentExtension) class. Each URL is defined using the [`URLRoute`](../../../reference/api#django_components.URLRoute) class, which specifies the path, handler, and optional name for the route.
To define URLs for an extension, set them in the [`urls`](../../../reference/api#django_components.ComponentExtension.urls) attribute of your [`ComponentExtension`](../../../reference/api#django_components.ComponentExtension) class. Each URL is defined using the [`URLRoute`](../../../reference/extension_urls#django_components.URLRoute) class, which specifies the path, handler, and optional name for the route.
Here's an example of how to define URLs within an extension:
@ -685,13 +685,13 @@ class MyExtension(ComponentExtension):
!!! warning
The [`URLRoute`](../../../reference/api#django_components.URLRoute) objects
The [`URLRoute`](../../../reference/extension_urls#django_components.URLRoute) objects
are different from objects created with Django's
[`django.urls.path()`](https://docs.djangoproject.com/en/5.1/ref/urls/#path).
Do NOT use `URLRoute` objects in Django's [`urlpatterns`](https://docs.djangoproject.com/en/5.1/topics/http/urls/#example)
and vice versa!
django-components uses a custom [`URLRoute`](../../../reference/api#django_components.URLRoute) class to define framework-agnostic routing rules.
django-components uses a custom [`URLRoute`](../../../reference/extension_urls#django_components.URLRoute) class to define framework-agnostic routing rules.
As of v0.131, `URLRoute` objects are directly converted to Django's `URLPattern` and `URLResolver` objects.
@ -713,9 +713,9 @@ For example, if you have defined a URL with the path `my-view/<str:name>/` in an
Extensions can also define nested URLs to allow for more complex routing structures.
To define nested URLs, set the [`children`](../../../reference/api#django_components.URLRoute.children)
attribute of the [`URLRoute`](../../../reference/api#django_components.URLRoute) object to
a list of child [`URLRoute`](../../../reference/api#django_components.URLRoute) objects:
To define nested URLs, set the [`children`](../../../reference/extension_urls#django_components.URLRoute.children)
attribute of the [`URLRoute`](../../../reference/extension_urls#django_components.URLRoute) object to
a list of child [`URLRoute`](../../../reference/extension_urls#django_components.URLRoute) objects:
```python
class MyExtension(ComponentExtension):
@ -742,15 +742,15 @@ would call the `my_view` handler with the parameter `name` set to `"John"`.
### Passing kwargs and other extra fields to URL routes
The [`URLRoute`](../../../reference/api#django_components.URLRoute) class is framework-agnostic,
The [`URLRoute`](../../../reference/extension_urls#django_components.URLRoute) class is framework-agnostic,
so that extensions could be used with non-Django frameworks in the future.
However, that means that there may be some extra fields that Django's
[`django.urls.path()`](https://docs.djangoproject.com/en/5.1/ref/urls/#path)
accepts, but which are not defined on the `URLRoute` object.
To address this, the [`URLRoute`](../../../reference/api#django_components.URLRoute) object has
an [`extra`](../../../reference/api#django_components.URLRoute.extra) attribute,
To address this, the [`URLRoute`](../../../reference/extension_urls#django_components.URLRoute) object has
an [`extra`](../../../reference/extension_urls#django_components.URLRoute.extra) attribute,
which is a dictionary that can be used to pass any extra kwargs to `django.urls.path()`:
```python

View file

@ -4,7 +4,9 @@ nav:
- Commands: commands.md
- Components: components.md
- Exceptions: exceptions.md
- Extension commands: extension_commands.md
- Extension hooks: extension_hooks.md
- Extension URLs: extension_urls.md
- Middlewares: middlewares.md
- Settings: settings.md
- Signals: signals.md

View file

@ -7,38 +7,14 @@
options:
show_if_no_docstring: true
::: django_components.CommandArg
options:
show_if_no_docstring: true
::: django_components.CommandArgGroup
options:
show_if_no_docstring: true
::: django_components.CommandHandler
options:
show_if_no_docstring: true
::: django_components.CommandLiteralAction
options:
show_if_no_docstring: true
::: django_components.CommandParserInput
options:
show_if_no_docstring: true
::: django_components.CommandSubcommand
options:
show_if_no_docstring: true
::: django_components.Component
options:
show_if_no_docstring: true
::: django_components.ComponentCommand
options:
show_if_no_docstring: true
::: django_components.ComponentExtension
options:
show_if_no_docstring: true
@ -87,38 +63,6 @@
options:
show_if_no_docstring: true
::: django_components.OnComponentClassCreatedContext
options:
show_if_no_docstring: true
::: django_components.OnComponentClassDeletedContext
options:
show_if_no_docstring: true
::: django_components.OnComponentDataContext
options:
show_if_no_docstring: true
::: django_components.OnComponentInputContext
options:
show_if_no_docstring: true
::: django_components.OnComponentRegisteredContext
options:
show_if_no_docstring: true
::: django_components.OnComponentUnregisteredContext
options:
show_if_no_docstring: true
::: django_components.OnRegistryCreatedContext
options:
show_if_no_docstring: true
::: django_components.OnRegistryDeletedContext
options:
show_if_no_docstring: true
::: django_components.RegistrySettings
options:
show_if_no_docstring: true
@ -151,14 +95,6 @@
options:
show_if_no_docstring: true
::: django_components.URLRoute
options:
show_if_no_docstring: true
::: django_components.URLRouteHandler
options:
show_if_no_docstring: true
::: django_components.all_components
options:
show_if_no_docstring: true

View file

@ -54,7 +54,8 @@ python manage.py components ext run <extension> <command>
## `components create`
```txt
usage: python manage.py components create [-h] [--path PATH] [--js JS] [--css CSS] [--template TEMPLATE] [--force] [--verbose] [--dry-run] name
usage: python manage.py components create [-h] [--path PATH] [--js JS] [--css CSS] [--template TEMPLATE] [--force] [--verbose] [--dry-run]
name
```
@ -461,8 +462,8 @@ ProjectDashboardAction project.components.dashboard_action.ProjectDashboardAc
## `upgradecomponent`
```txt
usage: upgradecomponent [-h] [--path PATH] [--version] [-v {0,1,2,3}] [--settings SETTINGS] [--pythonpath PYTHONPATH] [--traceback] [--no-color] [--force-color]
[--skip-checks]
usage: upgradecomponent [-h] [--path PATH] [--version] [-v {0,1,2,3}] [--settings SETTINGS]
[--pythonpath PYTHONPATH] [--traceback] [--no-color] [--force-color] [--skip-checks]
```
@ -506,8 +507,9 @@ Deprecated. Use `components upgrade` instead.
## `startcomponent`
```txt
usage: startcomponent [-h] [--path PATH] [--js JS] [--css CSS] [--template TEMPLATE] [--force] [--verbose] [--dry-run] [--version] [-v {0,1,2,3}]
[--settings SETTINGS] [--pythonpath PYTHONPATH] [--traceback] [--no-color] [--force-color] [--skip-checks]
usage: startcomponent [-h] [--path PATH] [--js JS] [--css CSS] [--template TEMPLATE] [--force] [--verbose]
[--dry-run] [--version] [-v {0,1,2,3}] [--settings SETTINGS] [--pythonpath PYTHONPATH]
[--traceback] [--no-color] [--force-color] [--skip-checks]
name
```

View file

@ -0,0 +1,39 @@
<!-- Autogenerated by reference.py -->
# Extension commands
Overview of all classes, functions, and other objects related to defining extension commands.
Read more on [Extensions](../../concepts/advanced/extensions).
::: django_components.CommandArg
options:
heading_level: 3
show_if_no_docstring: true
::: django_components.CommandArgGroup
options:
heading_level: 3
show_if_no_docstring: true
::: django_components.CommandHandler
options:
heading_level: 3
show_if_no_docstring: true
::: django_components.CommandParserInput
options:
heading_level: 3
show_if_no_docstring: true
::: django_components.CommandSubcommand
options:
heading_level: 3
show_if_no_docstring: true
::: django_components.ComponentCommand
options:
heading_level: 3
show_if_no_docstring: true

View file

@ -1,14 +1,17 @@
<!-- Autogenerated by reference.py -->
# Extension Hooks
# Extension hooks
Overview of all the extension hooks available in Django Components.
Read more on [Extensions](../../concepts/advanced/extensions).
## Hooks
::: django_components.extension.ComponentExtension.on_component_class_created
options:
heading_level: 3
show_root_heading: true
show_signature: true
separate_signature: true
@ -25,6 +28,7 @@ name | type | description
::: django_components.extension.ComponentExtension.on_component_class_deleted
options:
heading_level: 3
show_root_heading: true
show_signature: true
separate_signature: true
@ -41,6 +45,7 @@ name | type | description
::: django_components.extension.ComponentExtension.on_component_data
options:
heading_level: 3
show_root_heading: true
show_signature: true
separate_signature: true
@ -62,6 +67,7 @@ name | type | description
::: django_components.extension.ComponentExtension.on_component_input
options:
heading_level: 3
show_root_heading: true
show_signature: true
separate_signature: true
@ -84,6 +90,7 @@ name | type | description
::: django_components.extension.ComponentExtension.on_component_registered
options:
heading_level: 3
show_root_heading: true
show_signature: true
separate_signature: true
@ -102,6 +109,7 @@ name | type | description
::: django_components.extension.ComponentExtension.on_component_unregistered
options:
heading_level: 3
show_root_heading: true
show_signature: true
separate_signature: true
@ -120,6 +128,7 @@ name | type | description
::: django_components.extension.ComponentExtension.on_registry_created
options:
heading_level: 3
show_root_heading: true
show_signature: true
separate_signature: true
@ -136,6 +145,7 @@ name | type | description
::: django_components.extension.ComponentExtension.on_registry_deleted
options:
heading_level: 3
show_root_heading: true
show_signature: true
separate_signature: true
@ -150,3 +160,45 @@ name | type | description
--|--|--
`registry` | [`ComponentRegistry`](../api#django_components.ComponentRegistry) | The to-be-deleted ComponentRegistry instance
## Objects
::: django_components.extension.OnComponentClassCreatedContext
options:
heading_level: 3
show_if_no_docstring: true
::: django_components.extension.OnComponentClassDeletedContext
options:
heading_level: 3
show_if_no_docstring: true
::: django_components.extension.OnComponentDataContext
options:
heading_level: 3
show_if_no_docstring: true
::: django_components.extension.OnComponentInputContext
options:
heading_level: 3
show_if_no_docstring: true
::: django_components.extension.OnComponentRegisteredContext
options:
heading_level: 3
show_if_no_docstring: true
::: django_components.extension.OnComponentUnregisteredContext
options:
heading_level: 3
show_if_no_docstring: true
::: django_components.extension.OnRegistryCreatedContext
options:
heading_level: 3
show_if_no_docstring: true
::: django_components.extension.OnRegistryDeletedContext
options:
heading_level: 3
show_if_no_docstring: true

View file

@ -0,0 +1,19 @@
<!-- Autogenerated by reference.py -->
# Extension URLs
Overview of all classes, functions, and other objects related to defining extension URLs.
Read more on [Extensions](../../concepts/advanced/extensions).
::: django_components.URLRoute
options:
heading_level: 3
show_if_no_docstring: true
::: django_components.URLRouteHandler
options:
heading_level: 3
show_if_no_docstring: true

View file

@ -20,7 +20,7 @@ Import as
<a href="https://github.com/django-components/django-components/tree/master/src/django_components/templatetags/component_tags.py#L1053" target="_blank">See source code</a>
<a href="https://github.com/django-components/django-components/tree/master/src/django_components/templatetags/component_tags.py#L1037" target="_blank">See source code</a>
@ -43,7 +43,7 @@ If you insert this tag multiple times, ALL CSS links will be duplicately inserte
<a href="https://github.com/django-components/django-components/tree/master/src/django_components/templatetags/component_tags.py#L1075" target="_blank">See source code</a>
<a href="https://github.com/django-components/django-components/tree/master/src/django_components/templatetags/component_tags.py#L1059" target="_blank">See source code</a>
@ -67,7 +67,7 @@ If you insert this tag multiple times, ALL JS scripts will be duplicately insert
<a href="https://github.com/django-components/django-components/tree/master/src/django_components/templatetags/component_tags.py#L1494" target="_blank">See source code</a>
<a href="https://github.com/django-components/django-components/tree/master/src/django_components/templatetags/component_tags.py#L1564" target="_blank">See source code</a>

View file

@ -95,6 +95,9 @@ def gen_reference_api():
or _is_error_cls(obj)
or _is_tag_formatter_instance(obj)
or _is_tag_formatter_cls(obj)
or _is_extension_command_api(obj)
or _is_extension_hook_api(obj)
or _is_extension_url_api(obj)
):
continue
@ -660,6 +663,7 @@ def gen_reference_extension_hooks():
# All hooks start with `on_`, so filter out the rest
unique_methods = [name for name in unique_methods if name.startswith("on_")]
f.write("## Hooks\n\n")
for name in sorted(unique_methods):
# Programmatically get the data available inside the hook, so we can generate
# a table of available data.
@ -691,6 +695,7 @@ def gen_reference_extension_hooks():
f.write(
f"::: {class_name}.{name}\n"
f" options:\n"
f" heading_level: 3\n"
f" show_root_heading: true\n"
f" show_signature: true\n"
f" separate_signature: true\n"
@ -703,6 +708,102 @@ def gen_reference_extension_hooks():
f.write(available_data)
f.write("\n")
# 3. Print the context objects for each hook
f.write("## Objects\n\n")
main_module = import_module("django_components")
for name, obj in inspect.getmembers(main_module):
if not _is_extension_hook_api(obj):
continue
# For each entry, generate a mkdocstrings entry, e.g.
# ```
# ::: django_components.extension.OnComponentClassCreatedContext
# options:
# show_if_no_docstring: true
# ```
f.write(
f"::: {module.__name__}.{name}\n"
f" options:\n"
f" heading_level: 3\n"
f" show_if_no_docstring: true\n"
)
f.write("\n")
def gen_reference_extension_commands():
"""
Generate documentation for the objects related to defining extension commands.
"""
module = import_module("django_components")
preface = "<!-- Autogenerated by reference.py -->\n\n"
preface += (root / "docs/templates/reference_extension_commands.md").read_text()
out_file = root / "docs/reference/extension_commands.md"
out_file.parent.mkdir(parents=True, exist_ok=True)
with out_file.open("w", encoding="utf-8") as f:
# 1. Insert section from `reference_extension_commands.md`
f.write(preface + "\n\n")
# 2. Print the context objects for each hook
main_module = import_module("django_components")
for name, obj in inspect.getmembers(main_module):
if not _is_extension_command_api(obj):
continue
# For each entry, generate a mkdocstrings entry, e.g.
# ```
# ::: django_components.util.command.CommandLiteralAction
# options:
# show_if_no_docstring: true
# ```
f.write(
f"::: {module.__name__}.{name}\n"
f" options:\n"
f" heading_level: 3\n"
f" show_if_no_docstring: true\n"
)
f.write("\n")
def gen_reference_extension_urls():
"""
Generate documentation for the objects related to defining extension URLs.
"""
module = import_module("django_components")
preface = "<!-- Autogenerated by reference.py -->\n\n"
preface += (root / "docs/templates/reference_extension_urls.md").read_text()
out_file = root / "docs/reference/extension_urls.md"
out_file.parent.mkdir(parents=True, exist_ok=True)
with out_file.open("w", encoding="utf-8") as f:
# 1. Insert section from `reference_extension_urls.md`
f.write(preface + "\n\n")
# 2. Print the context objects for each hook
main_module = import_module("django_components")
for name, obj in inspect.getmembers(main_module):
if not _is_extension_url_api(obj):
continue
# For each entry, generate a mkdocstrings entry, e.g.
# ```
# ::: django_components.util.routing.URLRoute
# options:
# show_if_no_docstring: true
# ```
f.write(
f"::: {module.__name__}.{name}\n"
f" options:\n"
f" heading_level: 3\n"
f" show_if_no_docstring: true\n"
)
f.write("\n")
forward_ref_pattern = re.compile(r"ForwardRef\('(.+?)'\)")
class_repr_pattern = re.compile(r"<class '(.+?)'>")
@ -1018,6 +1119,18 @@ def _is_template_tag(obj: Any) -> bool:
return inspect.isclass(obj) and issubclass(obj, BaseNode)
def _is_extension_hook_api(obj: Any) -> bool:
return inspect.isclass(obj) and getattr(obj, "_extension_hook_api", False)
def _is_extension_command_api(obj: Any) -> bool:
return inspect.isclass(obj) and getattr(obj, "_extension_command_api", False)
def _is_extension_url_api(obj: Any) -> bool:
return inspect.isclass(obj) and getattr(obj, "_extension_url_api", False)
def gen_reference():
"""The entrypoint to generate all the reference documentation."""
gen_reference_api()
@ -1033,6 +1146,8 @@ def gen_reference():
gen_reference_signals()
gen_reference_testing_api()
gen_reference_extension_hooks()
gen_reference_extension_commands()
gen_reference_extension_urls()
# This is run when `gen-files` plugin is run in mkdocs.yml

View file

@ -0,0 +1,5 @@
# Extension commands
Overview of all classes, functions, and other objects related to defining extension commands.
Read more on [Extensions](../../concepts/advanced/extensions).

View file

@ -1,4 +1,4 @@
# Extension Hooks
# Extension hooks
Overview of all the extension hooks available in Django Components.

View file

@ -0,0 +1,5 @@
# Extension URLs
Overview of all classes, functions, and other objects related to defining extension URLs.
Read more on [Extensions](../../concepts/advanced/extensions).

View file

@ -27,26 +27,38 @@ TCallable = TypeVar("TCallable", bound=Callable)
################################################
# Mark a class as an extension hook context so we can place these in
# a separate documentation section
def mark_extension_hook_api(cls: Type[Any]) -> Type[Any]:
cls._extension_hook_api = True
return cls
@mark_extension_hook_api
class OnComponentClassCreatedContext(NamedTuple):
component_cls: Type["Component"]
"""The created Component class"""
@mark_extension_hook_api
class OnComponentClassDeletedContext(NamedTuple):
component_cls: Type["Component"]
"""The to-be-deleted Component class"""
@mark_extension_hook_api
class OnRegistryCreatedContext(NamedTuple):
registry: "ComponentRegistry"
"""The created ComponentRegistry instance"""
@mark_extension_hook_api
class OnRegistryDeletedContext(NamedTuple):
registry: "ComponentRegistry"
"""The to-be-deleted ComponentRegistry instance"""
@mark_extension_hook_api
class OnComponentRegisteredContext(NamedTuple):
registry: "ComponentRegistry"
"""The registry the component was registered to"""
@ -56,6 +68,7 @@ class OnComponentRegisteredContext(NamedTuple):
"""The registered Component class"""
@mark_extension_hook_api
class OnComponentUnregisteredContext(NamedTuple):
registry: "ComponentRegistry"
"""The registry the component was unregistered from"""
@ -65,6 +78,7 @@ class OnComponentUnregisteredContext(NamedTuple):
"""The unregistered Component class"""
@mark_extension_hook_api
class OnComponentInputContext(NamedTuple):
component: "Component"
"""The Component instance that received the input and is being rendered"""
@ -82,6 +96,7 @@ class OnComponentInputContext(NamedTuple):
"""The Django template Context object"""
@mark_extension_hook_api
class OnComponentDataContext(NamedTuple):
component: "Component"
"""The Component instance that is being rendered"""
@ -209,7 +224,8 @@ class ComponentExtension:
These commands will be available to the user as `components ext run <extension> <command>`.
Commands are defined as subclasses of [`ComponentCommand`](../api#django_components.ComponentCommand).
Commands are defined as subclasses of
[`ComponentCommand`](../extension_commands#django_components.ComponentCommand).
**Example:**

View file

@ -6,6 +6,14 @@ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Literal, Optional,
if TYPE_CHECKING:
from argparse import _ArgumentGroup, _FormatterClass
# Mark object as related to extension commands so we can place these in
# a separate documentation section
def mark_extension_command_api(obj: Any) -> Any:
obj._extension_command_api = True
return obj
#############################
# Argparse typing
#############################
@ -19,8 +27,10 @@ The basic type of action to be taken when this argument is encountered at the co
This is a subset of the values for `action` in
[`ArgumentParser.add_argument()`](https://docs.python.org/3/library/argparse.html#the-add-argument-method).
"""
mark_extension_command_api(CommandLiteralAction)
@mark_extension_command_api
@dataclass
class CommandArg:
"""
@ -77,6 +87,7 @@ class CommandArg:
return _remove_none_values(asdict(self))
@mark_extension_command_api
@dataclass
class CommandArgGroup:
"""
@ -102,6 +113,7 @@ class CommandArgGroup:
return _remove_none_values(asdict(self))
@mark_extension_command_api
@dataclass
class CommandSubcommand:
"""
@ -158,6 +170,7 @@ class CommandSubcommand:
return _remove_none_values(asdict(self))
@mark_extension_command_api
@dataclass
class CommandParserInput:
"""
@ -203,10 +216,12 @@ class CommandParserInput:
#############################
@mark_extension_command_api
class CommandHandler(Protocol):
def __call__(self, *args: Any, **kwargs: Any) -> None: ... # noqa: E704
@mark_extension_command_api
class ComponentCommand:
"""
Definition of a CLI command.

View file

@ -2,12 +2,21 @@ from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional, Protocol
# Mark object as related to extension URLs so we can place these in
# a separate documentation section
def mark_extension_url_api(obj: Any) -> Any:
obj._extension_url_api = True
return obj
@mark_extension_url_api
class URLRouteHandler(Protocol):
"""Framework-agnostic 'view' function for routes"""
def __call__(self, request: Any, *args: Any, **kwargs: Any) -> Any: ... # noqa: E704
@mark_extension_url_api
@dataclass
class URLRoute:
"""