generated from jCloud/repository-template
feat(python-namespaces)!: add validation for namespace names
Added more strict validation for namespaces names to PythonNamespace than before and updated error messages. All tests depending on this were updated to the new behavior.
This commit is contained in:
19 files changed
+78
-109
No files matched your search
@@ -37,7 +37,11 @@ from .definitions import (
|
||||
PythonFunctionDefinition,
|
||||
)
|
||||
from .docstrings import PythonDocstring
|
||||
from .namespaces import PythonModuleNamespace, PythonPackageNamespace
|
||||
from .namespaces import (
|
||||
PythonModuleNamespace,
|
||||
PythonPackageNamespace,
|
||||
validate_namespace_name,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
'PythonDefinitionDocumentationIncludeSections',
|
||||
@@ -926,9 +930,12 @@ class PythonModuleDocumentationGenerator:
|
||||
),
|
||||
**kwargs,
|
||||
) -> None:
|
||||
if module_path.name.count('.') > 1:
|
||||
if not (
|
||||
module_path.suffix == '.py'
|
||||
and validate_namespace_name(module_path.stem)
|
||||
):
|
||||
raise InvalidNamespaceError(
|
||||
'namespace identifier cannot contain more than one dot',
|
||||
'invalid module file name',
|
||||
namespace_identifier=module_path.name,
|
||||
)
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import keyword
|
||||
from typing import TypeAlias, Union
|
||||
|
||||
from ...exceptions import (
|
||||
@@ -24,27 +25,47 @@ from ...exceptions import (
|
||||
from ...utils import assert_that_is_instance
|
||||
|
||||
__all__ = [
|
||||
'validate_namespace_name',
|
||||
'PythonNamespace',
|
||||
'PythonPackageNamespace',
|
||||
'PythonModuleNamespace',
|
||||
]
|
||||
|
||||
|
||||
def validate_namespace_name(name: str) -> bool:
|
||||
"""
|
||||
Checks whether a namespace name is valid. Namespace names are valid
|
||||
if they contain no dots and are valid Python identifiers.
|
||||
|
||||
:param name: The namespace name to validate.
|
||||
:type name: str
|
||||
|
||||
:returns: Whether the namespace name is valid.
|
||||
:rtype: bool
|
||||
"""
|
||||
|
||||
if not isinstance(name, str):
|
||||
return False
|
||||
|
||||
return name.isidentifier() and not keyword.iskeyword(name)
|
||||
|
||||
|
||||
class PythonNamespace:
|
||||
"""
|
||||
The base class for all Python namespaces such as modules or packages.
|
||||
|
||||
:param name: The name of the namespace.
|
||||
:type name: str
|
||||
|
||||
:raises InvalidNamespaceError: If the namespace name is invalid.
|
||||
"""
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
assert_that_is_instance(name, str)
|
||||
|
||||
if not name.strip():
|
||||
if not validate_namespace_name(name):
|
||||
raise InvalidNamespaceError(
|
||||
'invalid namespace',
|
||||
namespace_identifier=name,
|
||||
'invalid namespace', namespace_identifier=name
|
||||
)
|
||||
|
||||
self.name = name
|
||||
@@ -70,6 +91,8 @@ class PythonPackageNamespace(PythonNamespace):
|
||||
:type name: str
|
||||
:param sub_namespaces: The sub-namespaces.
|
||||
:type sub_namespaces: list[PythonNamespace]
|
||||
|
||||
:raises InvalidNamespaceError: If the namespace name is invalid.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -25,176 +25,134 @@ from src.jcloud_docsgen.exceptions import InvalidNamespaceError
|
||||
[
|
||||
(
|
||||
pathlib.Path(
|
||||
(
|
||||
'tests/unit/core/python/_core/fil'
|
||||
'es_with_more_than_one_dot/a.b.c'
|
||||
),
|
||||
('tests/unit/core/python/_core/invalid_module_names/a.b.c'),
|
||||
),
|
||||
None,
|
||||
InvalidNamespaceError,
|
||||
'namespace identifier cannot contain more than one dot: a.b.c',
|
||||
'invalid module file name: a.b.c',
|
||||
),
|
||||
(
|
||||
pathlib.Path(
|
||||
('tests/unit/core/python/_core/invalid_module_names/a.b.c.d'),
|
||||
),
|
||||
None,
|
||||
InvalidNamespaceError,
|
||||
'invalid module file name: a.b.c.d',
|
||||
),
|
||||
(
|
||||
pathlib.Path(
|
||||
(
|
||||
'tests/unit/core/python/_core/file'
|
||||
's_with_more_than_one_dot/a.b.c.d'
|
||||
'tests/unit/core/python/_core/i'
|
||||
'nvalid_module_names/a.b.c.d.e'
|
||||
),
|
||||
),
|
||||
None,
|
||||
InvalidNamespaceError,
|
||||
'namespace identifier cannot contain more than one dot: a.b.c.d',
|
||||
'invalid module file name: a.b.c.d.e',
|
||||
),
|
||||
(
|
||||
pathlib.Path(
|
||||
(
|
||||
'tests/unit/core/python/_core/files'
|
||||
'_with_more_than_one_dot/a.b.c.d.e'
|
||||
'tests/unit/core/python/_core/in'
|
||||
'valid_module_names/a.b.c.d.e.f'
|
||||
),
|
||||
),
|
||||
None,
|
||||
InvalidNamespaceError,
|
||||
(
|
||||
'namespace identifier cannot cont'
|
||||
'ain more than one dot: a.b.c.d.e'
|
||||
),
|
||||
'invalid module file name: a.b.c.d.e.f',
|
||||
),
|
||||
(
|
||||
pathlib.Path(
|
||||
(
|
||||
'tests/unit/core/python/_core/files_'
|
||||
'with_more_than_one_dot/a.b.c.d.e.f'
|
||||
'tests/unit/core/python/_core/inv'
|
||||
'alid_module_names/a.b.c.d.e.f.g'
|
||||
),
|
||||
),
|
||||
None,
|
||||
InvalidNamespaceError,
|
||||
(
|
||||
'namespace identifier cannot conta'
|
||||
'in more than one dot: a.b.c.d.e.f'
|
||||
),
|
||||
'invalid module file name: a.b.c.d.e.f.g',
|
||||
),
|
||||
(
|
||||
pathlib.Path(
|
||||
(
|
||||
'tests/unit/core/python/_core/files_w'
|
||||
'ith_more_than_one_dot/a.b.c.d.e.f.g'
|
||||
'tests/unit/core/python/_core/inva'
|
||||
'lid_module_names/a.b.c.d.e.f.g.h'
|
||||
),
|
||||
),
|
||||
None,
|
||||
InvalidNamespaceError,
|
||||
(
|
||||
'namespace identifier cannot contai'
|
||||
'n more than one dot: a.b.c.d.e.f.g'
|
||||
),
|
||||
'invalid module file name: a.b.c.d.e.f.g.h',
|
||||
),
|
||||
(
|
||||
pathlib.Path(
|
||||
(
|
||||
'tests/unit/core/python/_core/files_wi'
|
||||
'th_more_than_one_dot/a.b.c.d.e.f.g.h'
|
||||
'tests/unit/core/python/_core/inval'
|
||||
'id_module_names/a.b.c.d.e.f.g.h.py'
|
||||
),
|
||||
),
|
||||
None,
|
||||
InvalidNamespaceError,
|
||||
(
|
||||
'namespace identifier cannot contain'
|
||||
' more than one dot: a.b.c.d.e.f.g.h'
|
||||
),
|
||||
'invalid module file name: a.b.c.d.e.f.g.h.py',
|
||||
),
|
||||
(
|
||||
pathlib.Path(
|
||||
(
|
||||
'tests/unit/core/python/_core/files_wit'
|
||||
'h_more_than_one_dot/a.b.c.d.e.f.g.h.py'
|
||||
'tests/unit/core/python/_core/inva'
|
||||
'lid_module_names/a.b.c.d.e.f.g.py'
|
||||
),
|
||||
),
|
||||
None,
|
||||
InvalidNamespaceError,
|
||||
(
|
||||
'namespace identifier cannot contain m'
|
||||
'ore than one dot: a.b.c.d.e.f.g.h.py'
|
||||
),
|
||||
'invalid module file name: a.b.c.d.e.f.g.py',
|
||||
),
|
||||
(
|
||||
pathlib.Path(
|
||||
(
|
||||
'tests/unit/core/python/_core/files_wi'
|
||||
'th_more_than_one_dot/a.b.c.d.e.f.g.py'
|
||||
'tests/unit/core/python/_core/in'
|
||||
'lid_module_names/a.b.c.d.e.f.py'
|
||||
),
|
||||
),
|
||||
None,
|
||||
InvalidNamespaceError,
|
||||
(
|
||||
'namespace identifier cannot contain '
|
||||
'more than one dot: a.b.c.d.e.f.g.py'
|
||||
),
|
||||
'invalid module file name: a.b.c.d.e.f.py',
|
||||
),
|
||||
(
|
||||
pathlib.Path(
|
||||
(
|
||||
'tests/unit/core/python/_core/files_w'
|
||||
'ith_more_than_one_dot/a.b.c.d.e.f.py'
|
||||
'tests/unit/core/python/_core/in'
|
||||
'valid_module_names/a.b.c.d.e.py'
|
||||
),
|
||||
),
|
||||
None,
|
||||
InvalidNamespaceError,
|
||||
(
|
||||
'namespace identifier cannot contain'
|
||||
' more than one dot: a.b.c.d.e.f.py'
|
||||
),
|
||||
'invalid module file name: a.b.c.d.e.py',
|
||||
),
|
||||
(
|
||||
pathlib.Path(
|
||||
(
|
||||
'tests/unit/core/python/_core/files_'
|
||||
'with_more_than_one_dot/a.b.c.d.e.py'
|
||||
'tests/unit/core/python/_core/i'
|
||||
'nvalid_module_names/a.b.c.d.py'
|
||||
),
|
||||
),
|
||||
None,
|
||||
InvalidNamespaceError,
|
||||
(
|
||||
'namespace identifier cannot contai'
|
||||
'n more than one dot: a.b.c.d.e.py'
|
||||
),
|
||||
'invalid module file name: a.b.c.d.py',
|
||||
),
|
||||
(
|
||||
pathlib.Path(
|
||||
(
|
||||
'tests/unit/core/python/_core/files'
|
||||
'_with_more_than_one_dot/a.b.c.d.py'
|
||||
),
|
||||
('tests/unit/core/python/_core/invalid_module_names/a.b.c.py'),
|
||||
),
|
||||
None,
|
||||
InvalidNamespaceError,
|
||||
(
|
||||
'namespace identifier cannot conta'
|
||||
'in more than one dot: a.b.c.d.py'
|
||||
),
|
||||
'invalid module file name: a.b.c.py',
|
||||
),
|
||||
(
|
||||
pathlib.Path(
|
||||
(
|
||||
'tests/unit/core/python/_core/file'
|
||||
's_with_more_than_one_dot/a.b.c.py'
|
||||
),
|
||||
('tests/unit/core/python/_core/invalid_module_names/a.b.py'),
|
||||
),
|
||||
None,
|
||||
InvalidNamespaceError,
|
||||
(
|
||||
'namespace identifier cannot cont'
|
||||
'ain more than one dot: a.b.c.py'
|
||||
),
|
||||
),
|
||||
(
|
||||
pathlib.Path(
|
||||
(
|
||||
'tests/unit/core/python/_core/fil'
|
||||
'es_with_more_than_one_dot/a.b.py'
|
||||
),
|
||||
),
|
||||
None,
|
||||
InvalidNamespaceError,
|
||||
'namespace identifier cannot contain more than one dot: a.b.py',
|
||||
'invalid module file name: a.b.py',
|
||||
),
|
||||
(
|
||||
pathlib.Path(
|
||||
@@ -205,7 +163,7 @@ from src.jcloud_docsgen.exceptions import InvalidNamespaceError
|
||||
),
|
||||
None,
|
||||
InvalidNamespaceError,
|
||||
'namespace identifier cannot contain more than one dot: a.b.py',
|
||||
'invalid module file name: a.b.py',
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -28,7 +28,6 @@ class StrSubclass(str): ...
|
||||
'namespace,expected_name',
|
||||
[
|
||||
(PythonModuleNamespace('a'), 'a'),
|
||||
(PythonModuleNamespace('1'), '1'),
|
||||
(PythonModuleNamespace(StrSubclass('a')), StrSubclass('a')),
|
||||
],
|
||||
)
|
||||
@@ -41,11 +40,7 @@ def test_PythonModuleNamespace_name_attribute(namespace, expected_name):
|
||||
[
|
||||
(PythonModuleNamespace('a'), PythonModuleNamespace('a'), True),
|
||||
(PythonModuleNamespace('b'), PythonModuleNamespace('b'), True),
|
||||
(PythonModuleNamespace('1'), PythonModuleNamespace('1'), True),
|
||||
(PythonModuleNamespace('42'), PythonModuleNamespace('42'), True),
|
||||
(PythonModuleNamespace('a'), PythonModuleNamespace('b'), False),
|
||||
(PythonModuleNamespace('0'), PythonModuleNamespace('-0'), False),
|
||||
(PythonModuleNamespace('1'), PythonModuleNamespace('a'), False),
|
||||
(PythonModuleNamespace('a'), 'a', False),
|
||||
(PythonModuleNamespace('a'), 'b', False),
|
||||
(PythonModuleNamespace('a'), PythonPackageNamespace('a', []), False),
|
||||
@@ -61,7 +56,6 @@ def test_PythonModuleNamespace___eq__(namespace1, namespace2, expected):
|
||||
'namespace,expected',
|
||||
[
|
||||
(PythonModuleNamespace('a'), "PythonModuleNamespace('a')"),
|
||||
(PythonModuleNamespace('1'), "PythonModuleNamespace('1')"),
|
||||
(
|
||||
PythonModuleNamespace(StrSubclass('a')),
|
||||
"PythonModuleNamespace('a')",
|
||||
|
||||
@@ -24,7 +24,6 @@ class StrSubclass(str): ...
|
||||
'namespace,expected_name',
|
||||
[
|
||||
(PythonNamespace('a'), 'a'),
|
||||
(PythonNamespace('1'), '1'),
|
||||
(PythonNamespace(StrSubclass('a')), StrSubclass('a')),
|
||||
],
|
||||
)
|
||||
@@ -36,7 +35,6 @@ def test_PythonNamespace_name_attribute(namespace, expected_name):
|
||||
'namespace,expected',
|
||||
[
|
||||
(PythonNamespace('a'), "PythonNamespace('a')"),
|
||||
(PythonNamespace('1'), "PythonNamespace('1')"),
|
||||
(PythonNamespace(StrSubclass('a')), "PythonNamespace('a')"),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -38,13 +38,6 @@ class StrSubclass(str): ...
|
||||
),
|
||||
'a',
|
||||
),
|
||||
(
|
||||
PythonPackageNamespace(
|
||||
'1',
|
||||
[],
|
||||
),
|
||||
'1',
|
||||
),
|
||||
(
|
||||
PythonPackageNamespace(
|
||||
StrSubclass('a'),
|
||||
@@ -291,10 +284,6 @@ def test_PythonPackageNamespace___eq__(namespace1, namespace2, expected):
|
||||
PythonPackageNamespace('a', []),
|
||||
"PythonPackageNamespace('a', [])",
|
||||
),
|
||||
(
|
||||
PythonPackageNamespace('1', []),
|
||||
"PythonPackageNamespace('1', [])",
|
||||
),
|
||||
(
|
||||
PythonPackageNamespace(StrSubclass('a'), []),
|
||||
"PythonPackageNamespace('a', [])",
|
||||
|
||||
Reference in new issue
Block a user