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 ### 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: This subclass should define:
- `name` - the command's name - `name` - the command's name
@ -419,12 +419,12 @@ class MyExt(ComponentExtension):
### Defining Command Arguments and Options ### Defining Command Arguments and Options
Commands can accept positional arguments and options (e.g. `--foo`), which are defined using the Commands can accept positional arguments and options (e.g. `--foo`), which are defined using the
[`arguments`](../../../reference/api#django_components.ComponentCommand.arguments) [`arguments`](../../../reference/extension_commands#django_components.ComponentCommand.arguments)
attribute of the [`ComponentCommand`](../../../reference/api#django_components.ComponentCommand) class. 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) 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 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. method of the command.
```python ```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. See the [argparse documentation](https://docs.python.org/3/library/argparse.html) for more information.
django-components defines types as django-components defines types as
[`CommandArg`](../../../reference/api#django_components.CommandArg), [`CommandArg`](../../../reference/extension_commands#django_components.CommandArg),
[`CommandArgGroup`](../../../reference/api#django_components.CommandArgGroup), [`CommandArgGroup`](../../../reference/extension_commands#django_components.CommandArgGroup),
[`CommandSubcommand`](../../../reference/api#django_components.CommandSubcommand), [`CommandSubcommand`](../../../reference/extension_commands#django_components.CommandSubcommand),
and [`CommandParserInput`](../../../reference/api#django_components.CommandParserInput) and [`CommandParserInput`](../../../reference/extension_commands#django_components.CommandParserInput)
to help with type checking. to help with type checking.
!!! note !!! 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. method defined, the command will print a help message and exit.
### Grouping Arguments ### 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. to provide better organization and help messages.
Read more on [argparse argument groups](https://docs.python.org/3/library/argparse.html#argument-groups). 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. Extensions can define subcommands, allowing for more complex command structures.
Subcommands are defined similarly to root commands, as subclasses of 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 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 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: attribute of the parent command:
```python ```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. 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: Here's an example of how to define URLs within an extension:
@ -685,13 +685,13 @@ class MyExtension(ComponentExtension):
!!! warning !!! 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 are different from objects created with Django's
[`django.urls.path()`](https://docs.djangoproject.com/en/5.1/ref/urls/#path). [`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) Do NOT use `URLRoute` objects in Django's [`urlpatterns`](https://docs.djangoproject.com/en/5.1/topics/http/urls/#example)
and vice versa! 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. 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. 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) To define nested URLs, set the [`children`](../../../reference/extension_urls#django_components.URLRoute.children)
attribute of the [`URLRoute`](../../../reference/api#django_components.URLRoute) object to attribute of the [`URLRoute`](../../../reference/extension_urls#django_components.URLRoute) object to
a list of child [`URLRoute`](../../../reference/api#django_components.URLRoute) objects: a list of child [`URLRoute`](../../../reference/extension_urls#django_components.URLRoute) objects:
```python ```python
class MyExtension(ComponentExtension): 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 ### 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. 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 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) [`django.urls.path()`](https://docs.djangoproject.com/en/5.1/ref/urls/#path)
accepts, but which are not defined on the `URLRoute` object. accepts, but which are not defined on the `URLRoute` object.
To address this, the [`URLRoute`](../../../reference/api#django_components.URLRoute) object has To address this, the [`URLRoute`](../../../reference/extension_urls#django_components.URLRoute) object has
an [`extra`](../../../reference/api#django_components.URLRoute.extra) attribute, 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()`: which is a dictionary that can be used to pass any extra kwargs to `django.urls.path()`:
```python ```python

View file

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

View file

@ -7,38 +7,14 @@
options: options:
show_if_no_docstring: true 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 ::: django_components.CommandLiteralAction
options: options:
show_if_no_docstring: true 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 ::: django_components.Component
options: options:
show_if_no_docstring: true show_if_no_docstring: true
::: django_components.ComponentCommand
options:
show_if_no_docstring: true
::: django_components.ComponentExtension ::: django_components.ComponentExtension
options: options:
show_if_no_docstring: true show_if_no_docstring: true
@ -87,38 +63,6 @@
options: options:
show_if_no_docstring: true 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 ::: django_components.RegistrySettings
options: options:
show_if_no_docstring: true show_if_no_docstring: true
@ -151,14 +95,6 @@
options: options:
show_if_no_docstring: true 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 ::: django_components.all_components
options: options:
show_if_no_docstring: true show_if_no_docstring: true

View file

@ -54,7 +54,8 @@ python manage.py components ext run <extension> <command>
## `components create` ## `components create`
```txt ```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` ## `upgradecomponent`
```txt ```txt
usage: upgradecomponent [-h] [--path PATH] [--version] [-v {0,1,2,3}] [--settings SETTINGS] [--pythonpath PYTHONPATH] [--traceback] [--no-color] [--force-color] usage: upgradecomponent [-h] [--path PATH] [--version] [-v {0,1,2,3}] [--settings SETTINGS]
[--skip-checks] [--pythonpath PYTHONPATH] [--traceback] [--no-color] [--force-color] [--skip-checks]
``` ```
@ -506,8 +507,9 @@ Deprecated. Use `components upgrade` instead.
## `startcomponent` ## `startcomponent`
```txt ```txt
usage: startcomponent [-h] [--path PATH] [--js JS] [--css CSS] [--template TEMPLATE] [--force] [--verbose] [--dry-run] [--version] [-v {0,1,2,3}] usage: startcomponent [-h] [--path PATH] [--js JS] [--css CSS] [--template TEMPLATE] [--force] [--verbose]
[--settings SETTINGS] [--pythonpath PYTHONPATH] [--traceback] [--no-color] [--force-color] [--skip-checks] [--dry-run] [--version] [-v {0,1,2,3}] [--settings SETTINGS] [--pythonpath PYTHONPATH]
[--traceback] [--no-color] [--force-color] [--skip-checks]
name 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 --> <!-- Autogenerated by reference.py -->
# Extension Hooks # Extension hooks
Overview of all the extension hooks available in Django Components. Overview of all the extension hooks available in Django Components.
Read more on [Extensions](../../concepts/advanced/extensions). Read more on [Extensions](../../concepts/advanced/extensions).
## Hooks
::: django_components.extension.ComponentExtension.on_component_class_created ::: django_components.extension.ComponentExtension.on_component_class_created
options: options:
heading_level: 3
show_root_heading: true show_root_heading: true
show_signature: true show_signature: true
separate_signature: true separate_signature: true
@ -25,6 +28,7 @@ name | type | description
::: django_components.extension.ComponentExtension.on_component_class_deleted ::: django_components.extension.ComponentExtension.on_component_class_deleted
options: options:
heading_level: 3
show_root_heading: true show_root_heading: true
show_signature: true show_signature: true
separate_signature: true separate_signature: true
@ -41,6 +45,7 @@ name | type | description
::: django_components.extension.ComponentExtension.on_component_data ::: django_components.extension.ComponentExtension.on_component_data
options: options:
heading_level: 3
show_root_heading: true show_root_heading: true
show_signature: true show_signature: true
separate_signature: true separate_signature: true
@ -62,6 +67,7 @@ name | type | description
::: django_components.extension.ComponentExtension.on_component_input ::: django_components.extension.ComponentExtension.on_component_input
options: options:
heading_level: 3
show_root_heading: true show_root_heading: true
show_signature: true show_signature: true
separate_signature: true separate_signature: true
@ -84,6 +90,7 @@ name | type | description
::: django_components.extension.ComponentExtension.on_component_registered ::: django_components.extension.ComponentExtension.on_component_registered
options: options:
heading_level: 3
show_root_heading: true show_root_heading: true
show_signature: true show_signature: true
separate_signature: true separate_signature: true
@ -102,6 +109,7 @@ name | type | description
::: django_components.extension.ComponentExtension.on_component_unregistered ::: django_components.extension.ComponentExtension.on_component_unregistered
options: options:
heading_level: 3
show_root_heading: true show_root_heading: true
show_signature: true show_signature: true
separate_signature: true separate_signature: true
@ -120,6 +128,7 @@ name | type | description
::: django_components.extension.ComponentExtension.on_registry_created ::: django_components.extension.ComponentExtension.on_registry_created
options: options:
heading_level: 3
show_root_heading: true show_root_heading: true
show_signature: true show_signature: true
separate_signature: true separate_signature: true
@ -136,6 +145,7 @@ name | type | description
::: django_components.extension.ComponentExtension.on_registry_deleted ::: django_components.extension.ComponentExtension.on_registry_deleted
options: options:
heading_level: 3
show_root_heading: true show_root_heading: true
show_signature: true show_signature: true
separate_signature: true separate_signature: true
@ -150,3 +160,45 @@ name | type | description
--|--|-- --|--|--
`registry` | [`ComponentRegistry`](../api#django_components.ComponentRegistry) | The to-be-deleted ComponentRegistry instance `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_error_cls(obj)
or _is_tag_formatter_instance(obj) or _is_tag_formatter_instance(obj)
or _is_tag_formatter_cls(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 continue
@ -660,6 +663,7 @@ def gen_reference_extension_hooks():
# All hooks start with `on_`, so filter out the rest # All hooks start with `on_`, so filter out the rest
unique_methods = [name for name in unique_methods if name.startswith("on_")] unique_methods = [name for name in unique_methods if name.startswith("on_")]
f.write("## Hooks\n\n")
for name in sorted(unique_methods): for name in sorted(unique_methods):
# Programmatically get the data available inside the hook, so we can generate # Programmatically get the data available inside the hook, so we can generate
# a table of available data. # a table of available data.
@ -691,6 +695,7 @@ def gen_reference_extension_hooks():
f.write( f.write(
f"::: {class_name}.{name}\n" f"::: {class_name}.{name}\n"
f" options:\n" f" options:\n"
f" heading_level: 3\n"
f" show_root_heading: true\n" f" show_root_heading: true\n"
f" show_signature: true\n" f" show_signature: true\n"
f" separate_signature: true\n" f" separate_signature: true\n"
@ -703,6 +708,102 @@ def gen_reference_extension_hooks():
f.write(available_data) f.write(available_data)
f.write("\n") 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\('(.+?)'\)") forward_ref_pattern = re.compile(r"ForwardRef\('(.+?)'\)")
class_repr_pattern = re.compile(r"<class '(.+?)'>") 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) 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(): def gen_reference():
"""The entrypoint to generate all the reference documentation.""" """The entrypoint to generate all the reference documentation."""
gen_reference_api() gen_reference_api()
@ -1033,6 +1146,8 @@ def gen_reference():
gen_reference_signals() gen_reference_signals()
gen_reference_testing_api() gen_reference_testing_api()
gen_reference_extension_hooks() gen_reference_extension_hooks()
gen_reference_extension_commands()
gen_reference_extension_urls()
# This is run when `gen-files` plugin is run in mkdocs.yml # 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. 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): class OnComponentClassCreatedContext(NamedTuple):
component_cls: Type["Component"] component_cls: Type["Component"]
"""The created Component class""" """The created Component class"""
@mark_extension_hook_api
class OnComponentClassDeletedContext(NamedTuple): class OnComponentClassDeletedContext(NamedTuple):
component_cls: Type["Component"] component_cls: Type["Component"]
"""The to-be-deleted Component class""" """The to-be-deleted Component class"""
@mark_extension_hook_api
class OnRegistryCreatedContext(NamedTuple): class OnRegistryCreatedContext(NamedTuple):
registry: "ComponentRegistry" registry: "ComponentRegistry"
"""The created ComponentRegistry instance""" """The created ComponentRegistry instance"""
@mark_extension_hook_api
class OnRegistryDeletedContext(NamedTuple): class OnRegistryDeletedContext(NamedTuple):
registry: "ComponentRegistry" registry: "ComponentRegistry"
"""The to-be-deleted ComponentRegistry instance""" """The to-be-deleted ComponentRegistry instance"""
@mark_extension_hook_api
class OnComponentRegisteredContext(NamedTuple): class OnComponentRegisteredContext(NamedTuple):
registry: "ComponentRegistry" registry: "ComponentRegistry"
"""The registry the component was registered to""" """The registry the component was registered to"""
@ -56,6 +68,7 @@ class OnComponentRegisteredContext(NamedTuple):
"""The registered Component class""" """The registered Component class"""
@mark_extension_hook_api
class OnComponentUnregisteredContext(NamedTuple): class OnComponentUnregisteredContext(NamedTuple):
registry: "ComponentRegistry" registry: "ComponentRegistry"
"""The registry the component was unregistered from""" """The registry the component was unregistered from"""
@ -65,6 +78,7 @@ class OnComponentUnregisteredContext(NamedTuple):
"""The unregistered Component class""" """The unregistered Component class"""
@mark_extension_hook_api
class OnComponentInputContext(NamedTuple): class OnComponentInputContext(NamedTuple):
component: "Component" component: "Component"
"""The Component instance that received the input and is being rendered""" """The Component instance that received the input and is being rendered"""
@ -82,6 +96,7 @@ class OnComponentInputContext(NamedTuple):
"""The Django template Context object""" """The Django template Context object"""
@mark_extension_hook_api
class OnComponentDataContext(NamedTuple): class OnComponentDataContext(NamedTuple):
component: "Component" component: "Component"
"""The Component instance that is being rendered""" """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>`. 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:** **Example:**

View file

@ -6,6 +6,14 @@ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Literal, Optional,
if TYPE_CHECKING: if TYPE_CHECKING:
from argparse import _ArgumentGroup, _FormatterClass 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 # 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 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). [`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 @dataclass
class CommandArg: class CommandArg:
""" """
@ -77,6 +87,7 @@ class CommandArg:
return _remove_none_values(asdict(self)) return _remove_none_values(asdict(self))
@mark_extension_command_api
@dataclass @dataclass
class CommandArgGroup: class CommandArgGroup:
""" """
@ -102,6 +113,7 @@ class CommandArgGroup:
return _remove_none_values(asdict(self)) return _remove_none_values(asdict(self))
@mark_extension_command_api
@dataclass @dataclass
class CommandSubcommand: class CommandSubcommand:
""" """
@ -158,6 +170,7 @@ class CommandSubcommand:
return _remove_none_values(asdict(self)) return _remove_none_values(asdict(self))
@mark_extension_command_api
@dataclass @dataclass
class CommandParserInput: class CommandParserInput:
""" """
@ -203,10 +216,12 @@ class CommandParserInput:
############################# #############################
@mark_extension_command_api
class CommandHandler(Protocol): class CommandHandler(Protocol):
def __call__(self, *args: Any, **kwargs: Any) -> None: ... # noqa: E704 def __call__(self, *args: Any, **kwargs: Any) -> None: ... # noqa: E704
@mark_extension_command_api
class ComponentCommand: class ComponentCommand:
""" """
Definition of a CLI command. Definition of a CLI command.

View file

@ -2,12 +2,21 @@ from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional, Protocol 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): class URLRouteHandler(Protocol):
"""Framework-agnostic 'view' function for routes""" """Framework-agnostic 'view' function for routes"""
def __call__(self, request: Any, *args: Any, **kwargs: Any) -> Any: ... # noqa: E704 def __call__(self, request: Any, *args: Any, **kwargs: Any) -> Any: ... # noqa: E704
@mark_extension_url_api
@dataclass @dataclass
class URLRoute: class URLRoute:
""" """