style: limit line length to 79 characters

Limited the lengths of all lines to 79 characters (if possible).
Additionally, some other lines were breaked for consistence.
This commit is contained in:
jakob.scheid committed 2026-09-18 16:57:45 +02:00
1 parent 8930efc7e6
commit caa8e04047
25 files changed
+6726 -1071

No files matched your search

+206 -49
View File
@@ -16,11 +16,16 @@ from __future__ import annotations
from ...utils import non_empty_str, get_relative_path_segments
from ...exceptions import PythonArgumentStructureError, InvalidNamespaceError
from .namespaces import PythonModuleNamespace, PythonPackageNamespace
from .definitions import PythonDefinition, PythonFunctionDefinition, PythonAsyncFunctionDefinition, PythonClassDefinition
from .definitions import (
PythonAsyncFunctionDefinition,
PythonClassDefinition,
PythonDefinition,
PythonFunctionDefinition
)
from .arguments import PythonArgumentKind, PythonFunctionArgument
from .docstrings import PythonDocstring
from collections.abc import Iterator
from typing import Union
from typing import TypeAlias, Union
from dataclasses import dataclass
from enum import Enum
import docstring_parser
@@ -53,7 +58,17 @@ def _collect_definitions(tree_or_node) -> Iterator[PythonDefinition]:
if isinstance(node, ast.ClassDef):
yield PythonClassDefinition.from_node(node)
def _group_argument_list(argument_list: list[PythonFunctionArgument]) -> tuple[list[PythonFunctionArgument], list[PythonFunctionArgument], Union[PythonFunctionArgument, None], list[PythonFunctionArgument], Union[PythonFunctionArgument, None]]:
_Arguments: TypeAlias = tuple[
list[PythonFunctionArgument],
list[PythonFunctionArgument],
Union[PythonFunctionArgument, None],
list[PythonFunctionArgument],
Union[PythonFunctionArgument, None]
]
def _group_argument_list(
argument_list: list[PythonFunctionArgument]
) -> _Arguments:
'''
Groups the argument list into a list of positional-only arguments, a
list of normal arguments, the * argument if there is one, a list of
@@ -62,7 +77,7 @@ def _group_argument_list(argument_list: list[PythonFunctionArgument]) -> tuple[l
:param argument_list: The argument list.
:type argument_list: list[PythonFunctionArgument]
:rtype: tuple[list[PythonFunctionArgument], list[PythonFunctionArgument], Union[PythonFunctionArgument, None], list[PythonFunctionArgument], Union[PythonFunctionArgument, None]]
:rtype: _Arguments
'''
if argument_list:
@@ -70,7 +85,9 @@ def _group_argument_list(argument_list: list[PythonFunctionArgument]) -> tuple[l
arg.kind == PythonArgumentKind.KWARGS
for arg in argument_list
]):
raise PythonArgumentStructureError('arguments cannot follow var-keyword argument')
raise PythonArgumentStructureError(
'arguments cannot follow var-keyword argument'
)
positional_only_args = []
normal_args = []
@@ -87,7 +104,10 @@ def _group_argument_list(argument_list: list[PythonFunctionArgument]) -> tuple[l
if arg.kind == PythonArgumentKind.VARARG:
if vararg is not None:
raise PythonArgumentStructureError('* argument may only appear once', definition = arg)
raise PythonArgumentStructureError(
'* argument may only appear once',
definition = arg
)
vararg = arg
if arg.kind == PythonArgumentKind.KEYWORD_ONLY:
@@ -96,9 +116,17 @@ def _group_argument_list(argument_list: list[PythonFunctionArgument]) -> tuple[l
if arg.kind == PythonArgumentKind.KWARGS:
kwargs = arg
return positional_only_args, normal_args, vararg, keyword_only_args, kwargs
return (
positional_only_args,
normal_args,
vararg,
keyword_only_args,
kwargs
)
def _signature_argument_list(argument_list: list[PythonFunctionArgument]) -> list[str]:
def _signature_argument_list(
argument_list: list[PythonFunctionArgument]
) -> list[str]:
'''
Returns a list of the arguments as strings for a function signature.
@@ -109,7 +137,13 @@ def _signature_argument_list(argument_list: list[PythonFunctionArgument]) -> lis
:rtype: list[str]
'''
positional_only_args, normal_args, vararg, keyword_only_args, kwargs = _group_argument_list(argument_list)
(
positional_only_args,
normal_args,
vararg,
keyword_only_args,
kwargs
) = _group_argument_list(argument_list)
args = []
@@ -157,7 +191,15 @@ def _fit_row_length(expected: int, row: tuple) -> tuple:
else:
return row + (None,) * (expected - len(row))
def _markdown_table(header: tuple, body: list[tuple], *, allow_markdown_table: bool = False, force_row_lengths: bool = False, one_line_values: bool = True, missing_value: str = '--') -> str:
def _markdown_table(
header: tuple,
body: list[tuple],
*,
allow_markdown_table: bool = False,
force_row_lengths: bool = False,
one_line_values: bool = True,
missing_value: str = '--'
) -> str:
'''
Generates a table.
@@ -188,18 +230,34 @@ def _markdown_table(header: tuple, body: list[tuple], *, allow_markdown_table: b
header_len = len(header)
if allow_markdown_table:
table = '| ' + ' | '.join(header) + ' |\n|' + ' --- |' * len(header) + '\n'
table = (
'| ' \
+ ' | '.join(header) \
+ ' |\n|' \
+ ' --- |' * len(header) \
+ '\n'
)
for row in body:
if len(row) != header_len:
if force_row_lengths:
raise ValueError(f'expected {header_len} value{"s" if header_len > 1 else ""}, got {len(row)}')
raise ValueError(
f'expected {header_len} value{
"s"
if header_len > 1
else ""
}, got {len(row)}'
)
else:
row = _fit_row_length(header_len, row)
table += '| ' + ' | '.join([
str(col if col is not None else missing_value).replace('\n', ' ')
str(
col
if col is not None
else missing_value
).replace('\n', ' ')
if one_line_values
else str(col if col is not None else missing_value)
for col in row
@@ -210,15 +268,36 @@ def _markdown_table(header: tuple, body: list[tuple], *, allow_markdown_table: b
for row in body:
if len(row) != header_len:
if force_row_lengths:
raise ValueError(f'expected {header_len} value{"s" if header_len > 1 else ""}, got {len(row)}')
raise ValueError(
f'expected {header_len} value{
"s"
if header_len > 1
else ""
}, got {len(row)}'
)
else:
row = _fit_row_length(header_len, row)
sep = '- '
for i, col in enumerate(row):
table += sep + header[i] + ': ' + (str(col if col is not None else missing_value).replace('\n', ' ') \
if one_line_values \
else str(col if col is not None else missing_value)) + '\n\n'
table += (
sep \
+ header[i] \
+ ': ' \
+ (
str(
col
if col is not None
else missing_value
).replace('\n', ' ') \
if one_line_values \
else str(
col
if col is not None
else missing_value
)
) + '\n\n'
)
sep = ' '
return table.strip()
@@ -277,7 +356,10 @@ def _argument_kind_human_readable(argument_kind: PythonArgumentKind) -> str:
return argument_kind.name.lower().replace('_', '-')
def _function_params_info(arg_list: list[PythonFunctionArgument], docstring_arg_list: list[docstring_parser.DocstringParam]) -> dict[str, _FunctionParamInfo]:
def _function_params_info(
arg_list: list[PythonFunctionArgument],
docstring_arg_list: list[docstring_parser.DocstringParam]
) -> dict[str, _FunctionParamInfo]:
'''
Returns a dictionary with the parameter info.
@@ -297,7 +379,10 @@ def _function_params_info(arg_list: list[PythonFunctionArgument], docstring_arg_
:rtype: dict[str, _FunctionParamInfo]
'''
arg_annotations = {arg.name: _FunctionParamInfo(arg.annotation, None) for arg in arg_list}
arg_annotations = {
arg.name: _FunctionParamInfo(arg.annotation, None)
for arg in arg_list
}
for arg in docstring_arg_list:
if arg.arg_name in arg_annotations.keys():
@@ -375,7 +460,10 @@ class PythonDefinitionDocumentationIncludeSections:
) + ')'
def __eq__(self, value) -> str:
if not isinstance(value, PythonDefinitionDocumentationIncludeSections):
if not isinstance(
value,
PythonDefinitionDocumentationIncludeSections
):
return False
return self._args == value._args
@@ -409,7 +497,9 @@ class PythonDefinitionDocumentationGenerator:
def __init__(
self,
definition: PythonDefinition,
include_sections: PythonDefinitionDocumentationIncludeSections = PythonDefinitionDocumentationIncludeSections(),
include_sections: PythonDefinitionDocumentationIncludeSections = (
PythonDefinitionDocumentationIncludeSections()
),
level: int = 1,
*,
allow_html: bool = True,
@@ -431,7 +521,9 @@ class PythonDefinitionDocumentationGenerator:
@property
def _docstring(self):
if self._docstring_cache is None:
self._docstring_cache = self.definition.doc.parse() if _is_docstring(self.definition.doc) else _NoDocstring
self._docstring_cache = self.definition.doc.parse() \
if _is_docstring(self.definition.doc) \
else _NoDocstring
return self._docstring_cache
def generate_signature(self) -> str:
@@ -446,9 +538,15 @@ class PythonDefinitionDocumentationGenerator:
'''
if isinstance(self.definition, PythonClassDefinition):
raise TypeError('Cannot generate a signature of a class definition.')
raise TypeError(
'Cannot generate a signature of a class definition.'
)
signature = self.definition.name + '(' + ', '.join(_signature_argument_list(self.definition.args)) + ')'
signature = self.definition.name + '(' + ', '.join(
_signature_argument_list(
self.definition.args
)
) + ')'
if self.definition.returns is not None:
signature += ' -> ' + self.definition.returns
@@ -463,7 +561,13 @@ class PythonDefinitionDocumentationGenerator:
:rtype: str
'''
return self.level * '#' + '# ' + ('Function' if not self.is_method else 'Method') +' signature\n\n```python\n' + self.generate_signature() + '\n```'
definition_type = 'Function' if not self.is_method else 'Method'
heading = self.level * '#' + '# ' + (definition_type) +' signature'
return f'''{heading}
```python
{self.generate_signature()}
```'''
def _generate_docstring_section(self) -> str:
'''
@@ -477,7 +581,11 @@ class PythonDefinitionDocumentationGenerator:
if _is_docstring(self.definition.doc) or not self.skip_empty_sections:
if self.allow_html:
md += '<details><summary><h' + str(self.level + 1) + ' style="display:inline">Docstring' + '</h' + str(self.level + 1) + '></summary>'
md += f'<details><summary><h{str(
self.level + 1
)} style="display:inline">Docstring</h{str(
self.level + 1
)}></summary>'
else:
md += self.level * '#' + '# Docstring\n\n'
@@ -506,19 +614,30 @@ class PythonDefinitionDocumentationGenerator:
if self.definition.args or not self.skip_empty_sections:
md += self.level * '#' + '# Parameters\n\n'
params_types = _function_params_info(self.definition.args, self._docstring.params)
params_types = _function_params_info(
self.definition.args,
self._docstring.params
)
if params_types:
md += _markdown_table(['Parameter', 'Type', 'Kind', 'Default value', 'Description'], [
(
'`' + arg.name + '`',
('`' + params_types.get(arg.name).annotation + '`') if params_types.get(arg.name).annotation is not None else None,
_argument_kind_human_readable(arg.kind),
('`' + arg.default + '`') if arg.default is not None else None,
non_empty_str(params_types.get(arg.name).description)
)
for arg in self.definition.args
], allow_markdown_table = self.allow_tables)
md += _markdown_table(
['Parameter', 'Type', 'Kind', 'Default value', 'Description'],
[
(
'`' + arg.name + '`',
('`' + params_types.get(arg.name).annotation + '`')
if params_types.get(arg.name).annotation is not None
else None,
_argument_kind_human_readable(arg.kind),
('`' + arg.default + '`')
if arg.default is not None
else None,
non_empty_str(params_types.get(arg.name).description)
)
for arg in self.definition.args
],
allow_markdown_table = self.allow_tables
)
md += '\n\n'
@@ -537,7 +656,11 @@ class PythonDefinitionDocumentationGenerator:
md = ''
if self._docstring.returns or self.definition.returns or not self.skip_empty_sections:
if (
self._docstring.returns
or self.definition.returns
or not self.skip_empty_sections
):
md += self.level * '#' + '# Returns\n\n'
returns = False
@@ -555,7 +678,10 @@ class PythonDefinitionDocumentationGenerator:
md += 'Return type: `' + rtype + '`'
if not self.skip_empty_sections and not returns:
md += 'This function does not provide any information about its return value.'
md += (
'This function does not provide any '
'information about its return value.'
)
return md.strip()
@@ -574,7 +700,11 @@ class PythonDefinitionDocumentationGenerator:
if self._docstring.raises:
md += _markdown_table(('Exception', 'Description'), [
(('`' + exception.type_name + '`') if exception.type_name is not None else None, non_empty_str(exception.description))
(
('`' + exception.type_name + '`')
if exception.type_name is not None
else None, non_empty_str(exception.description)
)
for exception in self._docstring.raises
], allow_markdown_table = self.allow_tables)
elif not self.skip_empty_sections:
@@ -689,7 +819,9 @@ class PythonDefinitionDocumentationGenerator:
md = self.level * '#' + ' '
if isinstance(self.definition, PythonAsyncFunctionDefinition):
md += 'Asynchronous ' + ('function' if not self.is_method else 'method')
md += 'Asynchronous ' + (
'function' if not self.is_method else 'method'
)
elif isinstance(self.definition, PythonFunctionDefinition):
if self.is_method and self.definition.name == '__init__':
md += 'Constructor (method'
@@ -699,7 +831,12 @@ class PythonDefinitionDocumentationGenerator:
md += 'Class'
md += ' `' + self.definition.name + '`'
if isinstance(self.definition, PythonFunctionDefinition) and not isinstance(self.definition, PythonAsyncFunctionDefinition) and self.is_method and self.definition.name == '__init__':
if (
isinstance(self.definition, PythonFunctionDefinition)
and not isinstance(self.definition, PythonAsyncFunctionDefinition)
and self.is_method
and self.definition.name == '__init__'
):
md += ')'
md += '\n\n'
@@ -756,14 +893,23 @@ class PythonModuleDocumentationGenerator:
self,
module_path: pathlib.Path,
src_directory: Union[pathlib.Path, None] = None,
include_sections: PythonDefinitionDocumentationIncludeSections = PythonDefinitionDocumentationIncludeSections(),
include_sections: PythonDefinitionDocumentationIncludeSections = (
PythonDefinitionDocumentationIncludeSections()
),
**kwargs
) -> None:
if module_path.name.count('.') > 1:
raise InvalidNamespaceError('namespace identifier cannot contain more than one dot', namespace_identifier = module_path.name)
raise InvalidNamespaceError(
'namespace identifier cannot contain more than one dot',
namespace_identifier = module_path.name
)
self.module_path = pathlib.Path(str(module_path))
self.src_directory = pathlib.Path(str(src_directory)) if src_directory is not None else None
self.src_directory = (
pathlib.Path(str(src_directory))
if src_directory is not None
else None
)
self.include_sections = include_sections
self.kwargs = kwargs
@@ -807,7 +953,12 @@ class PythonModuleDocumentationGenerator:
md = '# Module `'
if self.src_directory is not None:
module_identifier = '.'.join(get_relative_path_segments(self.module_path, self.src_directory))
module_identifier = '.'.join(
get_relative_path_segments(
self.module_path,
self.src_directory
)
)
if module_identifier.endswith('.py'):
md += module_identifier[:-3]
else:
@@ -836,7 +987,9 @@ def _generate_package_namespace_documentation(
documentation_directory: pathlib.Path,
root_directory: pathlib.Path,
dir: pathlib.Path,
include_sections: PythonDefinitionDocumentationIncludeSections = PythonDefinitionDocumentationIncludeSections(),
include_sections: PythonDefinitionDocumentationIncludeSections = (
PythonDefinitionDocumentationIncludeSections()
),
kwargs: dict = {}
) -> None:
'''
@@ -860,7 +1013,9 @@ def _generate_package_namespace_documentation(
for sub_namespace in namespace.sub_namespaces:
if isinstance(sub_namespace, PythonPackageNamespace):
(documentation_directory / sub_namespace.name).mkdir(mode = 0o700, exist_ok = True)
(
documentation_directory / sub_namespace.name
).mkdir(mode = 0o700, exist_ok = True)
_generate_package_namespace_documentation(
sub_namespace,
documentation_directory / sub_namespace.name,
@@ -897,7 +1052,9 @@ class PythonDocumentationGenerator:
self,
project_directory: pathlib.Path,
docs_directory: pathlib.Path,
include_sections: PythonDefinitionDocumentationIncludeSections = PythonDefinitionDocumentationIncludeSections(),
include_sections: PythonDefinitionDocumentationIncludeSections = (
PythonDefinitionDocumentationIncludeSections()
),
**kwargs
) -> None:
self.project_directory = pathlib.Path(str(project_directory))
+136 -24
View File
@@ -17,7 +17,11 @@ from enum import Enum
from typing import Union
import ast
from ...utils import assert_that_is_instance
from ...exceptions import InvalidPythonIdentifierError, InvalidPythonAnnotationError, PythonArgumentStructureError
from ...exceptions import (
InvalidPythonAnnotationError,
InvalidPythonIdentifierError,
PythonArgumentStructureError
)
import keyword
import types
@@ -48,7 +52,13 @@ class PythonFunctionArgument:
:type annotation: Union[str, None]
'''
def __init__(self, name: str, kind: PythonArgumentKind, default: Union[str, None], annotation: Union[str, None]) -> None:
def __init__(
self,
name: str,
kind: PythonArgumentKind,
default: Union[str, None],
annotation: Union[str, None]
) -> None:
assert_that_is_instance(name, str)
assert_that_is_instance(kind, PythonArgumentKind)
assert_that_is_instance(default, (str, types.NoneType))
@@ -56,26 +66,43 @@ class PythonFunctionArgument:
# check whether name is a valid identifier
if not name or not name.isidentifier() or keyword.iskeyword(name):
raise InvalidPythonIdentifierError('invalid identifier', identifier = name)
raise InvalidPythonIdentifierError(
'invalid identifier',
identifier = name
)
# check whether the annotation is a valid annotation
# Currently, it is only checked whether the parameter is not
# empty.
if annotation is not None and not annotation:
raise InvalidPythonAnnotationError('invalid annotation', annotation = annotation)
raise InvalidPythonAnnotationError(
'invalid annotation',
annotation = annotation
)
self.name = name
self.kind = kind
self.default = default
self.annotation = annotation
if self.kind in (PythonArgumentKind.VARARG, PythonArgumentKind.KWARGS) and self.default is not None:
raise PythonArgumentStructureError('* or ** arguments cannot have default values', definition = self.signature_repr())
if self.kind in (
PythonArgumentKind.VARARG,
PythonArgumentKind.KWARGS
) and self.default is not None:
raise PythonArgumentStructureError(
'* or ** arguments cannot have default values',
definition = self.signature_repr()
)
def __eq__(self, value: PythonFunctionArgument) -> bool:
if not isinstance(value, PythonFunctionArgument):
return False
return self.name == value.name and self.kind == value.kind and self.default == value.default and self.annotation == value.annotation
return (
self.name == value.name
and self.kind == value.kind
and self.default == value.default
and self.annotation == value.annotation
)
def __repr__(self) -> str:
return type(self).__name__ + repr((
@@ -131,43 +158,128 @@ class PythonASTArgumentsListParser:
:rtype: list[PythonFunctionArgument]
'''
defaults = [None for _ in range(len(
self.ast_arguments_list.posonlyargs +
self.ast_arguments_list.args +
self.ast_arguments_list.kwonlyargs
) - len(self.ast_arguments_list.defaults) - len(self.ast_arguments_list.kw_defaults))] + \
[ast.unparse(d) for d in self.ast_arguments_list.defaults] + \
[ast.unparse(d) if d is not None else None for d in self.ast_arguments_list.kw_defaults]
defaults = (
[
None
for _ in range(len(
self.ast_arguments_list.posonlyargs +
self.ast_arguments_list.args +
self.ast_arguments_list.kwonlyargs
) - len(
self.ast_arguments_list.defaults
) - len(
self.ast_arguments_list.kw_defaults
))
]
+ [
ast.unparse(d)
for d in self.ast_arguments_list.defaults
]
+ [
ast.unparse(d)
if d is not None
else None
for d in self.ast_arguments_list.kw_defaults
]
)
i = 0
arguments = []
for arg in self.ast_arguments_list.posonlyargs:
if arg.annotation is None:
arguments.append(PythonFunctionArgument(arg.arg, PythonArgumentKind.POSITIONAL_ONLY, defaults[i], None))
arguments.append(
PythonFunctionArgument(
arg.arg,
PythonArgumentKind.POSITIONAL_ONLY,
defaults[i],
None
)
)
else:
arguments.append(PythonFunctionArgument(arg.arg, PythonArgumentKind.POSITIONAL_ONLY, defaults[i], ast.unparse(arg.annotation)))
arguments.append(
PythonFunctionArgument(
arg.arg,
PythonArgumentKind.POSITIONAL_ONLY,
defaults[i],
ast.unparse(arg.annotation)))
i += 1
for arg in self.ast_arguments_list.args:
if arg.annotation is None:
arguments.append(PythonFunctionArgument(arg.arg, PythonArgumentKind.NORMAL, defaults[i], None))
arguments.append(
PythonFunctionArgument(
arg.arg,
PythonArgumentKind.NORMAL,
defaults[i],
None
)
)
else:
arguments.append(PythonFunctionArgument(arg.arg, PythonArgumentKind.NORMAL, defaults[i], ast.unparse(arg.annotation)))
arguments.append(
PythonFunctionArgument(
arg.arg,
PythonArgumentKind.NORMAL,
defaults[i],
ast.unparse(arg.annotation)
)
)
i += 1
if self.ast_arguments_list.vararg is not None:
if self.ast_arguments_list.vararg.annotation is None:
arguments.append(PythonFunctionArgument(self.ast_arguments_list.vararg.arg, PythonArgumentKind.VARARG, None, None))
arguments.append(
PythonFunctionArgument(
self.ast_arguments_list.vararg.arg,
PythonArgumentKind.VARARG,
None,
None
)
)
else:
arguments.append(PythonFunctionArgument(self.ast_arguments_list.vararg.arg, PythonArgumentKind.VARARG, None, ast.unparse(self.ast_arguments_list.vararg.annotation)))
arguments.append(
PythonFunctionArgument(
self.ast_arguments_list.vararg.arg,
PythonArgumentKind.VARARG,
None,
ast.unparse(self.ast_arguments_list.vararg.annotation)
)
)
for arg in self.ast_arguments_list.kwonlyargs:
if arg.annotation is None:
arguments.append(PythonFunctionArgument(arg.arg, PythonArgumentKind.KEYWORD_ONLY, defaults[i], None))
arguments.append(
PythonFunctionArgument(
arg.arg,
PythonArgumentKind.KEYWORD_ONLY,
defaults[i],
None
)
)
else:
arguments.append(PythonFunctionArgument(arg.arg, PythonArgumentKind.KEYWORD_ONLY, defaults[i], ast.unparse(arg.annotation)))
arguments.append(
PythonFunctionArgument(
arg.arg,
PythonArgumentKind.KEYWORD_ONLY,
defaults[i],
ast.unparse(arg.annotation)
)
)
i += 1
if self.ast_arguments_list.kwarg is not None:
if self.ast_arguments_list.kwarg.annotation is None:
arguments.append(PythonFunctionArgument(self.ast_arguments_list.kwarg.arg, PythonArgumentKind.KWARGS, None, None))
arguments.append(
PythonFunctionArgument(
self.ast_arguments_list.kwarg.arg,
PythonArgumentKind.KWARGS,
None,
None
)
)
else:
arguments.append(PythonFunctionArgument(self.ast_arguments_list.kwarg.arg, PythonArgumentKind.KWARGS, None, ast.unparse(self.ast_arguments_list.kwarg.annotation)))
arguments.append(
PythonFunctionArgument(
self.ast_arguments_list.kwarg.arg,
PythonArgumentKind.KWARGS,
None,
ast.unparse(self.ast_arguments_list.kwarg.annotation)
)
)
return arguments
+30 -5
View File
@@ -59,9 +59,17 @@ class PythonDefinition:
Python identifier.
'''
def __init__(self, name: str, doc: Union[PythonDocstring, None], decorators: list[str]) -> None:
def __init__(
self,
name: str,
doc: Union[PythonDocstring, None],
decorators: list[str]
) -> None:
if keyword.iskeyword(name) or not name.isidentifier() or not name:
raise InvalidPythonIdentifierError('invalid identifier', identifier = name)
raise InvalidPythonIdentifierError(
'invalid identifier',
identifier = name
)
assert_that_is_instance(doc, (PythonDocstring, types.NoneType))
@@ -119,7 +127,14 @@ class PythonFunctionDefinition(PythonDefinition):
Python identifier.
'''
def __init__(self, name: str, args: list[PythonFunctionArgument], returns: Union[str, None], doc: Union[PythonDocstring, None], decorators: list[str]) -> None:
def __init__(
self,
name: str,
args: list[PythonFunctionArgument],
returns: Union[str, None],
doc: Union[PythonDocstring, None],
decorators: list[str]
) -> None:
super().__init__(name, doc, decorators)
self.args = args
self.returns = returns
@@ -189,7 +204,14 @@ class PythonClassDefinition(PythonDefinition):
Python identifier.
'''
def __init__(self, name: str, bases: list[str], doc: Union[PythonDocstring, None], decorators: list[str], body: list[PythonDefinition]) -> None:
def __init__(
self,
name: str,
bases: list[str],
doc: Union[PythonDocstring, None],
decorators: list[str],
body: list[PythonDefinition]
) -> None:
super().__init__(name, doc, decorators)
self.bases = bases
self.body = body
@@ -227,6 +249,9 @@ class PythonClassDefinition(PythonDefinition):
else PythonClassDefinition.from_node(expr)
for expr in node.body
if isinstance(expr, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef))
if isinstance(
expr,
(ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)
)
]
)
+38 -8
View File
@@ -13,7 +13,11 @@
# limitations under the License.
from __future__ import annotations
from ...exceptions import InvalidNamespaceError, NamespaceNotFoundError, NamespaceExistsError
from ...exceptions import (
InvalidNamespaceError,
NamespaceNotFoundError,
NamespaceExistsError
)
from ...utils import assert_that_is_instance
from typing import Union, TypeAlias, Dict, List
@@ -34,14 +38,23 @@ class PythonNamespace:
assert_that_is_instance(name, str)
if not name.strip():
raise InvalidNamespaceError('invalid namespace', namespace_identifier = name)
raise InvalidNamespaceError(
'invalid namespace',
namespace_identifier = name
)
self.name = name
def __repr__(self) -> str:
return f'{type(self).__name__}({self.name!r})'
PythonPackageNamespaceDictType: TypeAlias = Dict[str, Union[str, 'PythonPackageNamespaceDictType']]
PythonPackageNamespaceDictType: TypeAlias = Dict[
str,
Union[
str,
'PythonPackageNamespaceDictType'
]
]
class PythonPackageNamespace(PythonNamespace):
'''
@@ -53,7 +66,11 @@ class PythonPackageNamespace(PythonNamespace):
:type sub_namespaces: list[PythonNamespace]
'''
def __init__(self, name: str, sub_namespaces: List[PythonNamespace]) -> None:
def __init__(
self,
name: str,
sub_namespaces: List[PythonNamespace]
) -> None:
assert_that_is_instance(sub_namespaces, list)
super().__init__(name)
@@ -94,7 +111,10 @@ class PythonPackageNamespace(PythonNamespace):
else:
return sub_namespace
def _sub_namespaces_names(self, package: PythonPackageNamespace) -> PythonPackageNamespaceDictType:
def _sub_namespaces_names(
self,
package: PythonPackageNamespace
) -> PythonPackageNamespaceDictType:
'''
Returns the names of all sub-namespaces of the specified package
namespace and keeps the package structure.
@@ -107,7 +127,11 @@ class PythonPackageNamespace(PythonNamespace):
'''
return {
sn.name: self._sub_namespaces_names(sn) if isinstance(sn, PythonPackageNamespace) else sn.name
sn.name: (
self._sub_namespaces_names(sn)
if isinstance(sn, PythonPackageNamespace)
else sn.name
)
for sn in package._sub_namespaces
}
@@ -151,7 +175,10 @@ class PythonPackageNamespace(PythonNamespace):
if sub.name == name:
return sub
raise NamespaceNotFoundError('no such namespace', namespace_identifier = name)
raise NamespaceNotFoundError(
'no such namespace',
namespace_identifier = name
)
def add(self, namespace: PythonNamespace) -> None:
'''
@@ -166,7 +193,10 @@ class PythonPackageNamespace(PythonNamespace):
'''
try:
self.__getitem__(namespace.name)
raise NamespaceExistsError('namespace already exists', namespace_identifier = namespace.name)
raise NamespaceExistsError(
'namespace already exists',
namespace_identifier = namespace.name
)
except NamespaceNotFoundError:
self._sub_namespaces.append(namespace)