refactor: replace isort, black and flake8 with ruff (#1346)
Some checks are pending
Docs - build & deploy / docs (push) Waiting to run
Run tests / build (ubuntu-latest, 3.10) (push) Waiting to run
Run tests / build (ubuntu-latest, 3.11) (push) Waiting to run
Run tests / build (ubuntu-latest, 3.12) (push) Waiting to run
Run tests / build (ubuntu-latest, 3.13) (push) Waiting to run
Run tests / build (ubuntu-latest, 3.8) (push) Waiting to run
Run tests / test_sampleproject (3.13) (push) Waiting to run
Run tests / build (ubuntu-latest, 3.9) (push) Waiting to run
Run tests / build (windows-latest, 3.10) (push) Waiting to run
Run tests / build (windows-latest, 3.11) (push) Waiting to run
Run tests / build (windows-latest, 3.12) (push) Waiting to run
Run tests / build (windows-latest, 3.13) (push) Waiting to run
Run tests / build (windows-latest, 3.8) (push) Waiting to run
Run tests / build (windows-latest, 3.9) (push) Waiting to run
Run tests / test_docs (3.13) (push) Waiting to run

This commit is contained in:
Juro Oravec 2025-09-10 14:06:53 +02:00 committed by GitHub
parent 5279fd372a
commit f100cc1836
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
128 changed files with 3076 additions and 2599 deletions

View file

@ -42,19 +42,21 @@ from argparse import ArgumentParser
from importlib import import_module
from pathlib import Path
from textwrap import dedent
from typing import Any, Dict, List, NamedTuple, Optional, Sequence, Tuple, Type, Union
from typing import TYPE_CHECKING, Any, Dict, List, NamedTuple, Optional, Sequence, Tuple, Type, Union
import mkdocs_gen_files
from django.conf import settings
from django.core.management.base import BaseCommand
from django.urls import URLPattern, URLResolver
from django_components import Component, ComponentVars, ComponentCommand, TagFormatterABC
from django_components import Component, ComponentCommand, ComponentVars, TagFormatterABC
from django_components.commands.components import ComponentsRootCommand
from django_components.node import BaseNode
from django_components.util.command import setup_parser_from_command
from django_components.util.misc import get_import_path
if TYPE_CHECKING:
from django.core.management.base import BaseCommand
# NOTE: This file is an entrypoint for the `gen-files` plugin in `mkdocs.yml`.
# However, `gen-files` plugin runs this file as a script, NOT as a module.
# That means that:
@ -71,7 +73,7 @@ from extensions import _format_source_code_html # noqa: E402
root = Path(__file__).parent.parent.parent
def gen_reference_api():
def gen_reference_api() -> None:
"""
Generate documentation for the Python API of `django_components`.
@ -109,14 +111,14 @@ def gen_reference_api():
# options:
# show_if_no_docstring: true
# ```
f.write(f"::: {module.__name__}.{name}\n" f" options:\n" f" show_if_no_docstring: true\n")
f.write(f"::: {module.__name__}.{name}\n options:\n show_if_no_docstring: true\n")
f.write("\n")
mkdocs_gen_files.set_edit_path(out_path, template_path)
def gen_reference_testing_api():
def gen_reference_testing_api() -> None:
"""
Generate documentation for the Python API of `django_components.testing`.
@ -142,17 +144,15 @@ def gen_reference_testing_api():
# options:
# show_if_no_docstring: true
# ```
f.write(f"::: {module.__name__}.{name}\n" f" options:\n" f" show_if_no_docstring: true\n")
f.write(f"::: {module.__name__}.{name}\n options:\n show_if_no_docstring: true\n")
f.write("\n")
mkdocs_gen_files.set_edit_path(out_path, template_path)
def gen_reference_exceptions():
"""
Generate documentation for the Exception classes included in the Python API of `django_components`.
"""
def gen_reference_exceptions() -> None:
"""Generate documentation for the Exception classes included in the Python API of `django_components`."""
module = import_module("django_components")
preface = "<!-- Autogenerated by reference.py -->\n\n"
@ -178,14 +178,14 @@ def gen_reference_exceptions():
# options:
# show_if_no_docstring: true
# ```
f.write(f"::: {module.__name__}.{name}\n" f" options:\n" f" show_if_no_docstring: true\n")
f.write(f"::: {module.__name__}.{name}\n options:\n show_if_no_docstring: true\n")
f.write("\n")
mkdocs_gen_files.set_edit_path(out_path, template_path)
def gen_reference_components():
def gen_reference_components() -> None:
"""
Generate documentation for the Component classes (AKA pre-defined components) included
in the Python API of `django_components`.
@ -200,7 +200,7 @@ def gen_reference_components():
with mkdocs_gen_files.open(out_path, "w", encoding="utf-8") as f:
f.write(preface + "\n\n")
for name, obj in inspect.getmembers(module):
for _name, obj in inspect.getmembers(module):
if not _is_component_cls(obj):
continue
@ -236,7 +236,7 @@ def gen_reference_components():
f" show_root_heading: true\n"
f" show_signature: false\n"
f" separate_signature: false\n"
f" members: {members}\n"
f" members: {members}\n",
)
f.write("\n")
@ -244,10 +244,8 @@ def gen_reference_components():
mkdocs_gen_files.set_edit_path(out_path, template_path)
def gen_reference_settings():
"""
Generate documentation for the settings of django-components, as defined by the `ComponentsSettings` class.
"""
def gen_reference_settings() -> None:
"""Generate documentation for the settings of django-components, as defined by the `ComponentsSettings` class."""
module = import_module("django_components.app_settings")
preface = "<!-- Autogenerated by reference.py -->\n\n"
@ -293,7 +291,7 @@ def gen_reference_settings():
f" show_symbol_type_heading: false\n"
f" show_symbol_type_toc: false\n"
f" show_if_no_docstring: true\n"
f" show_labels: false\n"
f" show_labels: false\n",
)
f.write("\n")
@ -301,7 +299,7 @@ def gen_reference_settings():
# Get attributes / methods that are unique to the subclass
def _get_unique_methods(base_class: Type, sub_class: Type):
def _get_unique_methods(base_class: Type, sub_class: Type) -> List[str]:
base_methods = set(dir(base_class))
subclass_methods = set(dir(sub_class))
unique_methods = subclass_methods - base_methods
@ -332,25 +330,25 @@ def _gen_default_settings_section(app_settings_filepath: str) -> str:
#
# However, for the documentation, we need to remove those.
dynamic_re = re.compile(r"Dynamic\(lambda\: (?P<code>.+)\)")
cleaned_snippet_lines = []
cleaned_snippet_lines: List[str] = []
for line in defaults_snippet_lines:
line = comment_re.split(line)[0].rstrip()
line = dynamic_re.sub(
curr_line = comment_re.split(line)[0].rstrip()
curr_line = dynamic_re.sub(
lambda m: m.group("code"),
line,
curr_line,
)
cleaned_snippet_lines.append(line)
cleaned_snippet_lines.append(curr_line)
clean_defaults_snippet = "\n".join(cleaned_snippet_lines)
return (
"### Settings defaults\n\n"
"Here's overview of all available settings and their defaults:\n\n"
+ f"```py\n{clean_defaults_snippet}\n```"
+ "\n\n"
f"```py\n{clean_defaults_snippet}\n```"
"\n\n"
)
def gen_reference_tagformatters():
def gen_reference_tagformatters() -> None:
"""
Generate documentation for all pre-defined TagFormatters included
in the Python API of `django_components`.
@ -387,7 +385,7 @@ def gen_reference_tagformatters():
formatted_instances = "\n".join(formatted_instances_lines)
f.write("### Available tag formatters\n\n" + formatted_instances)
for name, obj in tag_formatter_classes.items():
for obj in tag_formatter_classes.values():
class_name = get_import_path(obj)
# Generate reference entry for each TagFormatter class.
@ -408,7 +406,7 @@ def gen_reference_tagformatters():
f" show_symbol_type_toc: false\n"
f" show_if_no_docstring: true\n"
f" show_labels: false\n"
f" members: false\n"
f" members: false\n",
)
f.write("\n")
@ -416,10 +414,8 @@ def gen_reference_tagformatters():
mkdocs_gen_files.set_edit_path(out_path, template_path)
def gen_reference_urls():
"""
Generate documentation for all URLs (`urlpattern` entries) defined by django-components.
"""
def gen_reference_urls() -> None:
"""Generate documentation for all URLs (`urlpattern` entries) defined by django-components."""
module = import_module("django_components.urls")
preface = "<!-- Autogenerated by reference.py -->\n\n"
@ -437,7 +433,7 @@ def gen_reference_urls():
f.write("\n".join([f"- `{url_path}`\n" for url_path in all_urls]))
def gen_reference_commands():
def gen_reference_commands() -> None:
"""
Generate documentation for all Django admin commands defined by django-components.
@ -474,7 +470,7 @@ def gen_reference_commands():
# becomes this:
# `usage: python manage.py components ext run [-h]`
cmd_usage = cmd_usage[:7] + "python manage.py " + " ".join(cmd_path) + " " + cmd_usage[7:]
formatted_args = _format_command_args(cmd_parser, cmd_path + (cmd_def_cls.name,))
formatted_args = _format_command_args(cmd_parser, (*cmd_path, cmd_def_cls.name))
# Add link to source code
module_abs_path = import_module(cmd_def_cls.__module__).__file__
@ -483,7 +479,7 @@ def gen_reference_commands():
# NOTE: Raises `OSError` if the file is not found.
try:
obj_lineno = inspect.findsource(cmd_def_cls)[1]
except Exception:
except Exception: # noqa: BLE001
obj_lineno = None
source_code_link = _format_source_code_html(module_rel_path, obj_lineno)
@ -498,12 +494,12 @@ def gen_reference_commands():
f"{source_code_link}\n\n"
f"{cmd_summary}\n\n"
f"{formatted_args}\n\n"
f"{cmd_desc}\n\n"
f"{cmd_desc}\n\n",
)
# Add subcommands
for subcmd_cls in reversed(cmd_def_cls.subcommands):
commands_stack.append((subcmd_cls, cmd_path + (cmd_def_cls.name,)))
commands_stack.append((subcmd_cls, (*cmd_path, cmd_def_cls.name)))
# TODO_v1 - REMOVE - This this section as it only for legacy commands `startcomponent` and `upgradecomponent`
command_files = Path("./src/django_components/management/commands").glob("*.py")
@ -540,13 +536,13 @@ def gen_reference_commands():
f"{source_code_link}\n\n"
f"{cmd_summary}\n\n"
f"{formatted_args}\n\n"
f"{cmd_desc}\n\n"
f"{cmd_desc}\n\n",
)
mkdocs_gen_files.set_edit_path(out_path, template_path)
def gen_reference_template_tags():
def gen_reference_template_tags() -> None:
"""
Generate documentation for all Django template tags defined by django-components,
like `{% slot %}`, `{% component %}`, etc.
@ -573,7 +569,7 @@ def gen_reference_template_tags():
f.write(
f"All following template tags are defined in\n\n"
f"`{mod_path}`\n\n"
f"Import as\n```django\n{{% load {mod_name} %}}\n```\n\n"
f"Import as\n```django\n{{% load {mod_name} %}}\n```\n\n",
)
for _, obj in inspect.getmembers(tags_module):
@ -597,19 +593,21 @@ def gen_reference_template_tags():
# {% component [arg, ...] **kwargs [only] %}
# {% endcomponent %}
# ```
# fmt: off
f.write(
f"## {name}\n\n"
f"```django\n"
f"{tag_signature}\n"
f"```\n\n"
f"{source_code_link}\n\n"
f"{docstring}\n\n"
f"{docstring}\n\n",
)
# fmt: on
mkdocs_gen_files.set_edit_path(out_path, template_path)
def gen_reference_template_variables():
def gen_reference_template_variables() -> None:
"""
Generate documentation for all variables that are available inside the component templates
under the `{{ component_vars }}` variable, as defined by `ComponentVars`.
@ -628,10 +626,8 @@ def gen_reference_template_variables():
mkdocs_gen_files.set_edit_path(out_path, template_path)
def gen_reference_extension_hooks():
"""
Generate documentation for the hooks that are available to the extensions.
"""
def gen_reference_extension_hooks() -> None:
"""Generate documentation for the hooks that are available to the extensions."""
module = import_module("django_components.extension")
preface = "<!-- Autogenerated by reference.py -->\n\n"
@ -691,7 +687,7 @@ def gen_reference_extension_hooks():
f" show_symbol_type_heading: false\n"
f" show_symbol_type_toc: false\n"
f" show_if_no_docstring: true\n"
f" show_labels: false\n"
f" show_labels: false\n",
)
f.write("\n")
f.write(available_data)
@ -714,7 +710,7 @@ def gen_reference_extension_hooks():
f"::: {module.__name__}.{name}\n"
f" options:\n"
f" heading_level: 3\n"
f" show_if_no_docstring: true\n"
f" show_if_no_docstring: true\n",
)
f.write("\n")
@ -722,10 +718,8 @@ def gen_reference_extension_hooks():
mkdocs_gen_files.set_edit_path(out_path, template_path)
def gen_reference_extension_commands():
"""
Generate documentation for the objects related to defining extension commands.
"""
def gen_reference_extension_commands() -> None:
"""Generate documentation for the objects related to defining extension commands."""
module = import_module("django_components")
preface = "<!-- Autogenerated by reference.py -->\n\n"
@ -753,7 +747,7 @@ def gen_reference_extension_commands():
f"::: {module.__name__}.{name}\n"
f" options:\n"
f" heading_level: 3\n"
f" show_if_no_docstring: true\n"
f" show_if_no_docstring: true\n",
)
f.write("\n")
@ -761,10 +755,8 @@ def gen_reference_extension_commands():
mkdocs_gen_files.set_edit_path(out_path, template_path)
def gen_reference_extension_urls():
"""
Generate documentation for the objects related to defining extension URLs.
"""
def gen_reference_extension_urls() -> None:
"""Generate documentation for the objects related to defining extension URLs."""
module = import_module("django_components")
preface = "<!-- Autogenerated by reference.py -->\n\n"
@ -792,7 +784,7 @@ def gen_reference_extension_urls():
f"::: {module.__name__}.{name}\n"
f" options:\n"
f" heading_level: 3\n"
f" show_if_no_docstring: true\n"
f" show_if_no_docstring: true\n",
)
f.write("\n")
@ -855,7 +847,7 @@ def _extract_property_docstrings(cls: Type) -> Dict[str, str]:
and that the body is indented with 4 spaces.
"""
lines, start_line_index = inspect.getsourcelines(cls)
attrs_lines = []
attrs_lines: List[str] = []
ignore = True
for line in lines:
if ignore:
@ -863,10 +855,9 @@ def _extract_property_docstrings(cls: Type) -> Dict[str, str]:
ignore = False
continue
# Ignore comments
elif line.strip().startswith("#"):
if line.strip().startswith("#"):
continue
else:
attrs_lines.append(line)
attrs_lines.append(line)
attrs_docstrings = {}
curr_attr = None
@ -886,7 +877,7 @@ def _extract_property_docstrings(cls: Type) -> Dict[str, str]:
attrs_docstrings[curr_attr] = ""
state = "before_attr_docstring"
elif state == "before_attr_docstring":
if not is_one_indent or not (line.startswith("'''") or line.startswith('"""')):
if not is_one_indent or not line.startswith(("'''", '"""')):
continue
# Found start of docstring
docstring_delimiter = line[0:3]
@ -909,7 +900,7 @@ def _extract_property_docstrings(cls: Type) -> Dict[str, str]:
# NOTE: Unlike other references, the API of Signals is not yet codified (AKA source of truth defined
# as Python code). Instead, we manually list all signals that are sent by django-components.
def gen_reference_signals():
def gen_reference_signals() -> None:
"""
Generate documentation for all [Django Signals](https://docs.djangoproject.com/en/5.2/ref/signals) that are
send by or during the use of django-components.
@ -925,7 +916,7 @@ def gen_reference_signals():
mkdocs_gen_files.set_edit_path(out_path, template_path)
def _list_urls(urlpatterns: Sequence[Union[URLPattern, URLResolver]], prefix=""):
def _list_urls(urlpatterns: Sequence[Union[URLPattern, URLResolver]], prefix: str = "") -> List[str]:
"""Recursively extract all URLs and their associated views from Django's urlpatterns"""
urls: List[str] = []
@ -1077,7 +1068,7 @@ def _parse_command_args(cmd_inputs: str) -> Dict[str, List[Dict]]:
return data
def _format_command_args(cmd_parser: ArgumentParser, cmd_path: Optional[Sequence[str]] = None):
def _format_command_args(cmd_parser: ArgumentParser, cmd_path: Optional[Sequence[str]] = None) -> str:
cmd_inputs: str = _gen_command_args(cmd_parser)
parsed_cmd_inputs = _parse_command_args(cmd_inputs)
@ -1131,9 +1122,8 @@ 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() -> None:
"""The entrypoint to generate all the reference documentation."""
# Set up Django settings so we can import `extensions`
if not settings.configured:
settings.configure(