generated from jCloud/repository-template
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:
25 files changed
+6726
-1071
No files matched your search
@@ -35,7 +35,9 @@ def existing_directory(path: str) -> pathlib.Path:
|
||||
_path = path
|
||||
path = pathlib.Path(_path)
|
||||
if not path.exists():
|
||||
raise argparse.ArgumentTypeError(f'{_path}: no such file or directory')
|
||||
raise argparse.ArgumentTypeError(
|
||||
f'{_path}: no such file or directory'
|
||||
)
|
||||
if not path.is_dir():
|
||||
raise argparse.ArgumentTypeError(f'{_path}: not a directory')
|
||||
return path
|
||||
@@ -79,7 +81,10 @@ def create_argument_parser() -> argparse.ArgumentParser:
|
||||
|
||||
argument_parser = argparse.ArgumentParser()
|
||||
|
||||
subparsers = argument_parser.add_subparsers(dest = 'language', required = True)
|
||||
subparsers = argument_parser.add_subparsers(
|
||||
dest = 'language',
|
||||
required = True
|
||||
)
|
||||
|
||||
python_parser = subparsers.add_parser(
|
||||
_LANG_PYTHON,
|
||||
@@ -99,19 +104,29 @@ def create_argument_parser() -> argparse.ArgumentParser:
|
||||
nargs = '+',
|
||||
default = [],
|
||||
choices = VALID_PYTHON_SECTIONS,
|
||||
help = 'the sections to be excluded in the documentation. If a section shall be included AND excluded, it is excluded.'
|
||||
help = (
|
||||
'the sections to be excluded in the documentation. '
|
||||
'If a section shall be included AND excluded, it is excluded.'
|
||||
)
|
||||
)
|
||||
python_parser.add_argument(
|
||||
'-H',
|
||||
'--allow-html',
|
||||
action = 'store_true',
|
||||
help = 'indicates whether HTML is allowed in the documentation. By default, HTML is disabled.'
|
||||
help = (
|
||||
'indicates whether HTML is allowed in the documentation. '
|
||||
'By default, HTML is disabled.'
|
||||
)
|
||||
)
|
||||
python_parser.add_argument(
|
||||
'-T',
|
||||
'--allow-tables',
|
||||
action = 'store_true',
|
||||
help = 'indicates whether Markdown tables are allowed in the documentation. By default, Markdown tables are disabled. Warning: Markdown tables are not CommonMark.'
|
||||
help = (
|
||||
'indicates whether Markdown tables are allowed in the '
|
||||
'documentation. By default, Markdown tables are disabled. '
|
||||
'Warning: Markdown tables are not CommonMark.'
|
||||
)
|
||||
)
|
||||
|
||||
return argument_parser
|
||||
|
||||
@@ -13,7 +13,10 @@
|
||||
# limitations under the License.
|
||||
|
||||
import pathlib
|
||||
from ...core.python import PythonDefinitionDocumentationIncludeSections, PythonDocumentationGenerator
|
||||
from ...core.python import (
|
||||
PythonDefinitionDocumentationIncludeSections,
|
||||
PythonDocumentationGenerator
|
||||
)
|
||||
from typing import Optional
|
||||
|
||||
__all__ = [
|
||||
@@ -22,9 +25,14 @@ __all__ = [
|
||||
'generate'
|
||||
]
|
||||
|
||||
VALID_SECTIONS = list(PythonDefinitionDocumentationIncludeSections()._args.keys())
|
||||
VALID_SECTIONS = list(
|
||||
PythonDefinitionDocumentationIncludeSections()._args.keys()
|
||||
)
|
||||
|
||||
def parse_sections_list(include_sections: Optional[list[str]] = None, exclude_sections: list[str] = []) -> PythonDefinitionDocumentationIncludeSections:
|
||||
def parse_sections_list(
|
||||
include_sections: Optional[list[str]] = None,
|
||||
exclude_sections: list[str] = []
|
||||
) -> PythonDefinitionDocumentationIncludeSections:
|
||||
'''
|
||||
Returns a Python definition documentation sections list from the
|
||||
sections list to be included and the sections list to be excluded.
|
||||
@@ -63,7 +71,9 @@ def _generate(
|
||||
project_directory: pathlib.Path,
|
||||
output_directory: pathlib.Path,
|
||||
*,
|
||||
include_sections: PythonDefinitionDocumentationIncludeSections = PythonDefinitionDocumentationIncludeSections(),
|
||||
include_sections: PythonDefinitionDocumentationIncludeSections = (
|
||||
PythonDefinitionDocumentationIncludeSections()
|
||||
),
|
||||
allow_html: bool = False,
|
||||
allow_tables: bool = False
|
||||
) -> None:
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
)
|
||||
]
|
||||
)
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -24,7 +24,15 @@ class NamespaceError(ValueError):
|
||||
if not self.args:
|
||||
return ''
|
||||
else:
|
||||
return f'{self.args[0]}{": " if self.namespace_identifier and self.args[0] else ""}{self.namespace_identifier if self.args[0] else ""}'
|
||||
return f'{self.args[0]}{
|
||||
": "
|
||||
if self.namespace_identifier and self.args[0]
|
||||
else ""
|
||||
}{
|
||||
self.namespace_identifier
|
||||
if self.args[0]
|
||||
else ""
|
||||
}'
|
||||
|
||||
class InvalidNamespaceError(NamespaceError): ...
|
||||
class NamespaceNotFoundError(NamespaceError): ...
|
||||
@@ -42,7 +50,15 @@ class PythonIdentifierError(ValueError):
|
||||
if not self.args:
|
||||
return ''
|
||||
else:
|
||||
return f'{self.args[0]}{": " if self.identifier and self.args[0] else ""}{self.identifier if self.args[0] else ""}'
|
||||
return f'{self.args[0]}{
|
||||
": "
|
||||
if self.identifier and self.args[0]
|
||||
else ""
|
||||
}{
|
||||
self.identifier
|
||||
if self.args[0]
|
||||
else ""
|
||||
}'
|
||||
|
||||
class InvalidPythonIdentifierError(PythonIdentifierError): ...
|
||||
|
||||
@@ -58,7 +74,15 @@ class PythonAnnotationError(ValueError):
|
||||
if not self.args:
|
||||
return ''
|
||||
else:
|
||||
return f'{self.args[0]}{": " if self.annotation and self.args[0] else ""}{self.annotation if self.args[0] else ""}'
|
||||
return f'{self.args[0]}{
|
||||
": "
|
||||
if self.annotation and self.args[0]
|
||||
else ""
|
||||
}{
|
||||
self.annotation
|
||||
if self.args[0]
|
||||
else ""
|
||||
}'
|
||||
|
||||
class InvalidPythonAnnotationError(PythonAnnotationError): ...
|
||||
|
||||
@@ -74,6 +98,14 @@ class PythonDefinitionError(ValueError):
|
||||
if not self.args:
|
||||
return ''
|
||||
else:
|
||||
return f'{self.args[0]}{": " if self.definition and self.args[0] else ""}{self.definition if self.args[0] else ""}'
|
||||
return f'{self.args[0]}{
|
||||
": "
|
||||
if self.definition and self.args[0]
|
||||
else ""
|
||||
}{
|
||||
self.definition
|
||||
if self.args[0]
|
||||
else ""
|
||||
}'
|
||||
|
||||
class PythonArgumentStructureError(PythonDefinitionError): ...
|
||||
@@ -38,7 +38,11 @@ class ExistingDirectory(pathlib.Path):
|
||||
'''
|
||||
def __init__(self, path, *args, **kwargs) -> None:
|
||||
if not os.path.exists(path):
|
||||
raise FileNotFoundError(errno.ENOENT, 'no such file or directory', path)
|
||||
raise FileNotFoundError(
|
||||
errno.ENOENT,
|
||||
'no such file or directory',
|
||||
path
|
||||
)
|
||||
if not os.path.isdir(path):
|
||||
raise NotADirectoryError(errno.ENOTDIR, 'not a directory', path)
|
||||
super().__init__(*(path, *args), **kwargs)
|
||||
@@ -54,7 +58,11 @@ class ExistingFile(pathlib.Path):
|
||||
'''
|
||||
def __init__(self, path, *args, **kwargs) -> None:
|
||||
if not os.path.exists(path):
|
||||
raise FileNotFoundError(errno.ENOENT, 'no such file or directory', path)
|
||||
raise FileNotFoundError(
|
||||
errno.ENOENT,
|
||||
'no such file or directory',
|
||||
path
|
||||
)
|
||||
if not os.path.isfile(path):
|
||||
raise IsADirectoryError(errno.EISDIR, 'is a directory', path)
|
||||
super().__init__(*(path, *args), **kwargs)
|
||||
@@ -74,7 +82,11 @@ def _quote(string: str, quotation_mark: str) -> str:
|
||||
|
||||
return quotation_mark + string + quotation_mark
|
||||
|
||||
def human_readable_list(ls: list, final_separator: str = 'and', quotation_mark: str = '') -> str:
|
||||
def human_readable_list(
|
||||
ls: list,
|
||||
final_separator: str = 'and',
|
||||
quotation_mark: str = ''
|
||||
) -> str:
|
||||
'''
|
||||
Generates a human-readable list from a list.
|
||||
|
||||
@@ -101,7 +113,10 @@ def human_readable_list(ls: list, final_separator: str = 'and', quotation_mark:
|
||||
|
||||
return ', '.join(
|
||||
[
|
||||
_quote(str(obj), quotation_mark) # quote the string representation of the object
|
||||
_quote(
|
||||
str(obj),
|
||||
quotation_mark
|
||||
) # quote the string representation of the object
|
||||
for obj in ls[:-1] # do not include the last element of the list
|
||||
]
|
||||
) + ' ' + final_separator + ' ' + _quote(str(ls[-1]), quotation_mark)
|
||||
@@ -120,9 +135,19 @@ def _list_type_names(types: list[type]) -> list[str]:
|
||||
|
||||
return [tp.__name__ for tp in types]
|
||||
|
||||
def assert_that_is_instance(obj: object, class_or_tuple: Union[type, types.UnionType, tuple[type, ...]]) -> None:
|
||||
def assert_that_is_instance(
|
||||
obj: object,
|
||||
class_or_tuple: Union[
|
||||
type,
|
||||
types.UnionType,
|
||||
tuple[type, ...]
|
||||
]
|
||||
) -> None:
|
||||
if not isinstance(class_or_tuple, Union[type, types.UnionType, tuple]):
|
||||
raise TypeError(f'class_or_tuple: expected \'Union[type, types.UnionType, tuple[type, ...]]\', \'got {type(class_or_tuple).__name__}\'')
|
||||
raise TypeError(
|
||||
f'class_or_tuple: expected \'Union[type, types.UnionType, '
|
||||
f'tuple[type, ...]]\', \'got {type(class_or_tuple).__name__}\''
|
||||
)
|
||||
if not isinstance(obj, class_or_tuple):
|
||||
if isinstance(class_or_tuple, (tuple, types.UnionType)):
|
||||
if isinstance(class_or_tuple, types.UnionType):
|
||||
@@ -131,10 +156,15 @@ def assert_that_is_instance(obj: object, class_or_tuple: Union[type, types.Union
|
||||
exception_message_expected = 'either '
|
||||
else:
|
||||
exception_message_expected = ''
|
||||
exception_message_expected += human_readable_list(_list_type_names(class_or_tuple), 'or', '\'')
|
||||
exception_message_expected += human_readable_list(
|
||||
_list_type_names(class_or_tuple), 'or', '\'')
|
||||
else:
|
||||
exception_message_expected = '\'' + class_or_tuple.__name__ + '\''
|
||||
raise TypeError(f'expected {exception_message_expected}, got \'{type(obj).__name__}\'')
|
||||
raise TypeError(
|
||||
f'expected {exception_message_expected}, got \'{type(
|
||||
obj
|
||||
).__name__}\''
|
||||
)
|
||||
|
||||
def non_empty_str(value: Union[str, None]) -> Union[str, None]:
|
||||
'''
|
||||
@@ -160,7 +190,10 @@ def non_empty_str(value: Union[str, None]) -> Union[str, None]:
|
||||
|
||||
return value
|
||||
|
||||
def get_relative_path_segments(path: pathlib.Path, root: pathlib.Path) -> list[str]:
|
||||
def get_relative_path_segments(
|
||||
path: pathlib.Path,
|
||||
root: pathlib.Path
|
||||
) -> list[str]:
|
||||
'''
|
||||
Returns the path segments relative to ``root``.
|
||||
|
||||
|
||||
Reference in new issue
Block a user