generated from jCloud/repository-template
Compare commits
21
Commits
10328e6608
...
v0.2.2-rc0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a85cd1b433
|
||
|
|
06f91a18e9
|
||
|
|
bc542ed781
|
||
|
|
aa44f9c3a1
|
||
|
|
0f4c344676
|
||
|
|
ae01f223e3
|
||
|
|
4781e21f5d
|
||
|
|
0d86785dba
|
||
|
|
5402dd960e
|
||
|
|
d8249d3eb1
|
||
|
|
6c593a286c
|
||
|
|
4b659d7d2d | ||
|
|
1ccb610310
|
||
|
|
a25c66d77b
|
||
|
|
82e10c5493
|
||
|
|
03fa81f0df
|
||
|
|
efa2dbf724
|
||
|
|
0f8f9d3cfa
|
||
|
|
3e77ebb7d0
|
||
|
|
310861dacc
|
||
|
|
4365de27a8
|
No files matched your search
+12
-1
@@ -1,11 +1,22 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## [Unreleased]
|
## [0.2.2] - 2026-10-14
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Import error in Python <3.13 which prevented the tool from running and made it unusuable in Python <3.13
|
||||||
|
|
||||||
|
## [0.2.1] - 2026-10-06
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Python namespace name conflict when package and module have the same name
|
- Python namespace name conflict when package and module have the same name
|
||||||
- Internal namespace name error which occured when generating Python documentation with `.` as the project directory
|
- Internal namespace name error which occured when generating Python documentation with `.` as the project directory
|
||||||
|
- Ignore Python namespaces with invalid names during documentation generation
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Stricter Python namespace name validation
|
||||||
|
|
||||||
## [0.2.0] - 2026-09-28
|
## [0.2.0] - 2026-09-28
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,45 @@
|
|||||||
# Module `jcloud_docsgen.core.python.namespaces`
|
# Module `jcloud_docsgen.core.python.namespaces`
|
||||||
|
|
||||||
|
## Function `validate_namespace_name`
|
||||||
|
|
||||||
|
Checks whether a namespace name is valid. Namespace names are valid
|
||||||
|
if they contain no dots and are valid Python identifiers.
|
||||||
|
|
||||||
|
### Function signature
|
||||||
|
|
||||||
|
```python
|
||||||
|
validate_namespace_name(name: str) -> bool
|
||||||
|
```
|
||||||
|
|
||||||
|
### Returns
|
||||||
|
|
||||||
|
Whether the namespace name is valid.
|
||||||
|
|
||||||
|
Return type: `bool`
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
| Parameter | Type | Kind | Default value | Description |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| `name` | `str` | normal | -- | The namespace name to validate. |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Docstring
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
## Class `PythonNamespace`
|
## Class `PythonNamespace`
|
||||||
|
|
||||||
The base class for all Python namespaces such as modules or packages.
|
The base class for all Python namespaces such as modules or packages.
|
||||||
@@ -57,6 +97,8 @@ The base class for all Python namespaces such as modules or packages.
|
|||||||
:param name: The name of the namespace.
|
:param name: The name of the namespace.
|
||||||
:type name: str
|
:type name: str
|
||||||
|
|
||||||
|
:raises InvalidNamespaceError: If the namespace name is invalid.
|
||||||
|
|
||||||
## Class `PythonPackageNamespace`
|
## Class `PythonPackageNamespace`
|
||||||
|
|
||||||
A subclass of ``PythonNamespace`` for Python package namespaces.
|
A subclass of ``PythonNamespace`` for Python package namespaces.
|
||||||
@@ -381,6 +423,8 @@ A subclass of ``PythonNamespace`` for Python package namespaces.
|
|||||||
:param sub_namespaces: The sub-namespaces.
|
:param sub_namespaces: The sub-namespaces.
|
||||||
:type sub_namespaces: list[PythonNamespace]
|
:type sub_namespaces: list[PythonNamespace]
|
||||||
|
|
||||||
|
:raises InvalidNamespaceError: If the namespace name is invalid.
|
||||||
|
|
||||||
## Class `PythonModuleNamespace`
|
## Class `PythonModuleNamespace`
|
||||||
|
|
||||||
A subclass of ``PythonNamespace`` for Python module namespaces.
|
A subclass of ``PythonNamespace`` for Python module namespaces.
|
||||||
|
|||||||
Generated
+4
-4
@@ -1,4 +1,4 @@
|
|||||||
# This file is automatically @generated by Poetry 2.4.3 and should not be changed by hand.
|
# This file is automatically @generated by Poetry 2.5.1 and should not be changed by hand.
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorama"
|
name = "colorama"
|
||||||
@@ -235,14 +235,14 @@ version = "4.16.0"
|
|||||||
description = "Backported and Experimental Type Hints for Python 3.9+"
|
description = "Backported and Experimental Type Hints for Python 3.9+"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.9"
|
python-versions = ">=3.9"
|
||||||
groups = ["dev"]
|
groups = ["main", "dev"]
|
||||||
markers = "python_version == \"3.10\""
|
|
||||||
files = [
|
files = [
|
||||||
{file = "typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8"},
|
{file = "typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8"},
|
||||||
{file = "typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5"},
|
{file = "typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5"},
|
||||||
]
|
]
|
||||||
|
markers = {dev = "python_version == \"3.10\""}
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.1"
|
lock-version = "2.1"
|
||||||
python-versions = ">=3.10"
|
python-versions = ">=3.10"
|
||||||
content-hash = "24c9a2d464f6c737eeae0a66f792fa23824c3960b7cc72a22fff1408f21ec812"
|
content-hash = "0fb3b53540e7a7fe173bf29a2031bd59f863a8dea94a29d51933de2375c3bfa2"
|
||||||
+2
-2
@@ -4,9 +4,9 @@ build-backend = "poetry.core.masonry.api"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "jcloud-docsgen"
|
name = "jcloud-docsgen"
|
||||||
version = "0.2.0"
|
version = "0.2.2"
|
||||||
description = "A tool that generates Markdown documentation for software project source code"
|
description = "A tool that generates Markdown documentation for software project source code"
|
||||||
dependencies = ["docstring-parser"]
|
dependencies = ["docstring-parser", "typing-extensions (>=4.16.0,<5.0.0)"]
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,11 @@ from .definitions import (
|
|||||||
PythonFunctionDefinition,
|
PythonFunctionDefinition,
|
||||||
)
|
)
|
||||||
from .docstrings import PythonDocstring
|
from .docstrings import PythonDocstring
|
||||||
from .namespaces import PythonModuleNamespace, PythonPackageNamespace
|
from .namespaces import (
|
||||||
|
PythonModuleNamespace,
|
||||||
|
PythonPackageNamespace,
|
||||||
|
validate_namespace_name,
|
||||||
|
)
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'PythonDefinitionDocumentationIncludeSections',
|
'PythonDefinitionDocumentationIncludeSections',
|
||||||
@@ -926,9 +930,12 @@ class PythonModuleDocumentationGenerator:
|
|||||||
),
|
),
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> None:
|
) -> None:
|
||||||
if module_path.name.count('.') > 1:
|
if not (
|
||||||
|
module_path.suffix == '.py'
|
||||||
|
and validate_namespace_name(module_path.stem)
|
||||||
|
):
|
||||||
raise InvalidNamespaceError(
|
raise InvalidNamespaceError(
|
||||||
'namespace identifier cannot contain more than one dot',
|
'invalid module file name',
|
||||||
namespace_identifier=module_path.name,
|
namespace_identifier=module_path.name,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1107,12 +1114,18 @@ class PythonDocumentationGenerator:
|
|||||||
)
|
)
|
||||||
|
|
||||||
for entry in directory.iterdir():
|
for entry in directory.iterdir():
|
||||||
if entry.is_dir() and (
|
try:
|
||||||
entry.parent / (f'{entry.stem}.py')
|
if entry.is_dir() and (
|
||||||
).resolve() not in [e.resolve() for e in entry.parent.iterdir()]:
|
entry.parent / (f'{entry.stem}.py')
|
||||||
namespace.add(self._namespace(entry))
|
).resolve() not in [
|
||||||
elif entry.suffix == '.py':
|
e.resolve() for e in entry.parent.iterdir()
|
||||||
namespace.add(PythonModuleNamespace(entry.stem))
|
]:
|
||||||
|
namespace.add(self._namespace(entry))
|
||||||
|
elif entry.suffix == '.py':
|
||||||
|
namespace.add(PythonModuleNamespace(entry.stem))
|
||||||
|
except InvalidNamespaceError:
|
||||||
|
# the name of the directory or module is invalid; ignore.
|
||||||
|
pass
|
||||||
|
|
||||||
return namespace
|
return namespace
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import keyword
|
||||||
from typing import TypeAlias, Union
|
from typing import TypeAlias, Union
|
||||||
|
|
||||||
from ...exceptions import (
|
from ...exceptions import (
|
||||||
@@ -24,27 +25,47 @@ from ...exceptions import (
|
|||||||
from ...utils import assert_that_is_instance
|
from ...utils import assert_that_is_instance
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
'validate_namespace_name',
|
||||||
'PythonNamespace',
|
'PythonNamespace',
|
||||||
'PythonPackageNamespace',
|
'PythonPackageNamespace',
|
||||||
'PythonModuleNamespace',
|
'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:
|
class PythonNamespace:
|
||||||
"""
|
"""
|
||||||
The base class for all Python namespaces such as modules or packages.
|
The base class for all Python namespaces such as modules or packages.
|
||||||
|
|
||||||
:param name: The name of the namespace.
|
:param name: The name of the namespace.
|
||||||
:type name: str
|
:type name: str
|
||||||
|
|
||||||
|
:raises InvalidNamespaceError: If the namespace name is invalid.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, name: str) -> None:
|
def __init__(self, name: str) -> None:
|
||||||
assert_that_is_instance(name, str)
|
assert_that_is_instance(name, str)
|
||||||
|
|
||||||
if not name.strip():
|
if not validate_namespace_name(name):
|
||||||
raise InvalidNamespaceError(
|
raise InvalidNamespaceError(
|
||||||
'invalid namespace',
|
'invalid namespace', namespace_identifier=name
|
||||||
namespace_identifier=name,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self.name = name
|
self.name = name
|
||||||
@@ -70,6 +91,8 @@ class PythonPackageNamespace(PythonNamespace):
|
|||||||
:type name: str
|
:type name: str
|
||||||
:param sub_namespaces: The sub-namespaces.
|
:param sub_namespaces: The sub-namespaces.
|
||||||
:type sub_namespaces: list[PythonNamespace]
|
:type sub_namespaces: list[PythonNamespace]
|
||||||
|
|
||||||
|
:raises InvalidNamespaceError: If the namespace name is invalid.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
|||||||
@@ -14,6 +14,20 @@
|
|||||||
|
|
||||||
import errno
|
import errno
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'NamespaceError',
|
||||||
|
'InvalidNamespaceError',
|
||||||
|
'NamespaceNotFoundError',
|
||||||
|
'NamespaceExistsError',
|
||||||
|
'PythonIdentifierError',
|
||||||
|
'InvalidPythonIdentifierError',
|
||||||
|
'PythonAnnotationError',
|
||||||
|
'InvalidPythonAnnotationError',
|
||||||
|
'PythonDefinitionError',
|
||||||
|
'PythonArgumentStructureError',
|
||||||
|
'DirectoryNotEmptyError',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class NamespaceError(ValueError):
|
class NamespaceError(ValueError):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -27,6 +27,16 @@ except ImportError:
|
|||||||
from typing_extensions import deprecated
|
from typing_extensions import deprecated
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'ExistingDirectory',
|
||||||
|
'ExistingFile',
|
||||||
|
'human_readable_list',
|
||||||
|
'assert_that_is_instance',
|
||||||
|
'non_empty_str',
|
||||||
|
'get_relative_path_segments',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
@deprecated('Use pathlib.Path instead.')
|
@deprecated('Use pathlib.Path instead.')
|
||||||
class ExistingDirectory(pathlib.Path):
|
class ExistingDirectory(pathlib.Path):
|
||||||
"""
|
"""
|
||||||
|
|||||||
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.
+9
@@ -0,0 +1,9 @@
|
|||||||
|
# Module `pkg.a.b`
|
||||||
|
|
||||||
|
## Function `fn`
|
||||||
|
|
||||||
|
### Function signature
|
||||||
|
|
||||||
|
```python
|
||||||
|
fn()
|
||||||
|
```
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
def fn(): ...
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
def fn(): ...
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
def fn(): ...
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
def fn(): ...
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
def fn(): ...
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
def fn(): ...
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
def fn(): ...
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
def fn(): ...
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
def fn(): ...
|
||||||
Whitespace-only changes.
Whitespace-only changes.
+1
@@ -0,0 +1 @@
|
|||||||
|
def fn(): ...
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
def fn(): ...
|
||||||
@@ -25,176 +25,134 @@ from src.jcloud_docsgen.exceptions import InvalidNamespaceError
|
|||||||
[
|
[
|
||||||
(
|
(
|
||||||
pathlib.Path(
|
pathlib.Path(
|
||||||
(
|
('tests/unit/core/python/_core/invalid_module_names/a.b.c'),
|
||||||
'tests/unit/core/python/_core/fil'
|
|
||||||
'es_with_more_than_one_dot/a.b.c'
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
InvalidNamespaceError,
|
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(
|
pathlib.Path(
|
||||||
(
|
(
|
||||||
'tests/unit/core/python/_core/file'
|
'tests/unit/core/python/_core/i'
|
||||||
's_with_more_than_one_dot/a.b.c.d'
|
'nvalid_module_names/a.b.c.d.e'
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
InvalidNamespaceError,
|
InvalidNamespaceError,
|
||||||
'namespace identifier cannot contain more than one dot: a.b.c.d',
|
'invalid module file name: a.b.c.d.e',
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
pathlib.Path(
|
pathlib.Path(
|
||||||
(
|
(
|
||||||
'tests/unit/core/python/_core/files'
|
'tests/unit/core/python/_core/in'
|
||||||
'_with_more_than_one_dot/a.b.c.d.e'
|
'valid_module_names/a.b.c.d.e.f'
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
InvalidNamespaceError,
|
InvalidNamespaceError,
|
||||||
(
|
'invalid module file name: a.b.c.d.e.f',
|
||||||
'namespace identifier cannot cont'
|
|
||||||
'ain more than one dot: a.b.c.d.e'
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
pathlib.Path(
|
pathlib.Path(
|
||||||
(
|
(
|
||||||
'tests/unit/core/python/_core/files_'
|
'tests/unit/core/python/_core/inv'
|
||||||
'with_more_than_one_dot/a.b.c.d.e.f'
|
'alid_module_names/a.b.c.d.e.f.g'
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
InvalidNamespaceError,
|
InvalidNamespaceError,
|
||||||
(
|
'invalid module file name: a.b.c.d.e.f.g',
|
||||||
'namespace identifier cannot conta'
|
|
||||||
'in more than one dot: a.b.c.d.e.f'
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
pathlib.Path(
|
pathlib.Path(
|
||||||
(
|
(
|
||||||
'tests/unit/core/python/_core/files_w'
|
'tests/unit/core/python/_core/inva'
|
||||||
'ith_more_than_one_dot/a.b.c.d.e.f.g'
|
'lid_module_names/a.b.c.d.e.f.g.h'
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
InvalidNamespaceError,
|
InvalidNamespaceError,
|
||||||
(
|
'invalid module file name: a.b.c.d.e.f.g.h',
|
||||||
'namespace identifier cannot contai'
|
|
||||||
'n more than one dot: a.b.c.d.e.f.g'
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
pathlib.Path(
|
pathlib.Path(
|
||||||
(
|
(
|
||||||
'tests/unit/core/python/_core/files_wi'
|
'tests/unit/core/python/_core/inval'
|
||||||
'th_more_than_one_dot/a.b.c.d.e.f.g.h'
|
'id_module_names/a.b.c.d.e.f.g.h.py'
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
InvalidNamespaceError,
|
InvalidNamespaceError,
|
||||||
(
|
'invalid module file name: a.b.c.d.e.f.g.h.py',
|
||||||
'namespace identifier cannot contain'
|
|
||||||
' more than one dot: a.b.c.d.e.f.g.h'
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
pathlib.Path(
|
pathlib.Path(
|
||||||
(
|
(
|
||||||
'tests/unit/core/python/_core/files_wit'
|
'tests/unit/core/python/_core/inva'
|
||||||
'h_more_than_one_dot/a.b.c.d.e.f.g.h.py'
|
'lid_module_names/a.b.c.d.e.f.g.py'
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
InvalidNamespaceError,
|
InvalidNamespaceError,
|
||||||
(
|
'invalid module file name: a.b.c.d.e.f.g.py',
|
||||||
'namespace identifier cannot contain m'
|
|
||||||
'ore than one dot: a.b.c.d.e.f.g.h.py'
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
pathlib.Path(
|
pathlib.Path(
|
||||||
(
|
(
|
||||||
'tests/unit/core/python/_core/files_wi'
|
'tests/unit/core/python/_core/in'
|
||||||
'th_more_than_one_dot/a.b.c.d.e.f.g.py'
|
'lid_module_names/a.b.c.d.e.f.py'
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
InvalidNamespaceError,
|
InvalidNamespaceError,
|
||||||
(
|
'invalid module file name: a.b.c.d.e.f.py',
|
||||||
'namespace identifier cannot contain '
|
|
||||||
'more than one dot: a.b.c.d.e.f.g.py'
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
pathlib.Path(
|
pathlib.Path(
|
||||||
(
|
(
|
||||||
'tests/unit/core/python/_core/files_w'
|
'tests/unit/core/python/_core/in'
|
||||||
'ith_more_than_one_dot/a.b.c.d.e.f.py'
|
'valid_module_names/a.b.c.d.e.py'
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
InvalidNamespaceError,
|
InvalidNamespaceError,
|
||||||
(
|
'invalid module file name: a.b.c.d.e.py',
|
||||||
'namespace identifier cannot contain'
|
|
||||||
' more than one dot: a.b.c.d.e.f.py'
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
pathlib.Path(
|
pathlib.Path(
|
||||||
(
|
(
|
||||||
'tests/unit/core/python/_core/files_'
|
'tests/unit/core/python/_core/i'
|
||||||
'with_more_than_one_dot/a.b.c.d.e.py'
|
'nvalid_module_names/a.b.c.d.py'
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
InvalidNamespaceError,
|
InvalidNamespaceError,
|
||||||
(
|
'invalid module file name: a.b.c.d.py',
|
||||||
'namespace identifier cannot contai'
|
|
||||||
'n more than one dot: a.b.c.d.e.py'
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
pathlib.Path(
|
pathlib.Path(
|
||||||
(
|
('tests/unit/core/python/_core/invalid_module_names/a.b.c.py'),
|
||||||
'tests/unit/core/python/_core/files'
|
|
||||||
'_with_more_than_one_dot/a.b.c.d.py'
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
InvalidNamespaceError,
|
InvalidNamespaceError,
|
||||||
(
|
'invalid module file name: a.b.c.py',
|
||||||
'namespace identifier cannot conta'
|
|
||||||
'in more than one dot: a.b.c.d.py'
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
pathlib.Path(
|
pathlib.Path(
|
||||||
(
|
('tests/unit/core/python/_core/invalid_module_names/a.b.py'),
|
||||||
'tests/unit/core/python/_core/file'
|
|
||||||
's_with_more_than_one_dot/a.b.c.py'
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
InvalidNamespaceError,
|
InvalidNamespaceError,
|
||||||
(
|
'invalid module file name: a.b.py',
|
||||||
'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',
|
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
pathlib.Path(
|
pathlib.Path(
|
||||||
@@ -205,7 +163,7 @@ from src.jcloud_docsgen.exceptions import InvalidNamespaceError
|
|||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
InvalidNamespaceError,
|
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',
|
'namespace,expected_name',
|
||||||
[
|
[
|
||||||
(PythonModuleNamespace('a'), 'a'),
|
(PythonModuleNamespace('a'), 'a'),
|
||||||
(PythonModuleNamespace('1'), '1'),
|
|
||||||
(PythonModuleNamespace(StrSubclass('a')), StrSubclass('a')),
|
(PythonModuleNamespace(StrSubclass('a')), StrSubclass('a')),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -41,11 +40,7 @@ def test_PythonModuleNamespace_name_attribute(namespace, expected_name):
|
|||||||
[
|
[
|
||||||
(PythonModuleNamespace('a'), PythonModuleNamespace('a'), True),
|
(PythonModuleNamespace('a'), PythonModuleNamespace('a'), True),
|
||||||
(PythonModuleNamespace('b'), PythonModuleNamespace('b'), True),
|
(PythonModuleNamespace('b'), PythonModuleNamespace('b'), True),
|
||||||
(PythonModuleNamespace('1'), PythonModuleNamespace('1'), True),
|
|
||||||
(PythonModuleNamespace('42'), PythonModuleNamespace('42'), True),
|
|
||||||
(PythonModuleNamespace('a'), PythonModuleNamespace('b'), False),
|
(PythonModuleNamespace('a'), PythonModuleNamespace('b'), False),
|
||||||
(PythonModuleNamespace('0'), PythonModuleNamespace('-0'), False),
|
|
||||||
(PythonModuleNamespace('1'), PythonModuleNamespace('a'), False),
|
|
||||||
(PythonModuleNamespace('a'), 'a', False),
|
(PythonModuleNamespace('a'), 'a', False),
|
||||||
(PythonModuleNamespace('a'), 'b', False),
|
(PythonModuleNamespace('a'), 'b', False),
|
||||||
(PythonModuleNamespace('a'), PythonPackageNamespace('a', []), False),
|
(PythonModuleNamespace('a'), PythonPackageNamespace('a', []), False),
|
||||||
@@ -61,7 +56,6 @@ def test_PythonModuleNamespace___eq__(namespace1, namespace2, expected):
|
|||||||
'namespace,expected',
|
'namespace,expected',
|
||||||
[
|
[
|
||||||
(PythonModuleNamespace('a'), "PythonModuleNamespace('a')"),
|
(PythonModuleNamespace('a'), "PythonModuleNamespace('a')"),
|
||||||
(PythonModuleNamespace('1'), "PythonModuleNamespace('1')"),
|
|
||||||
(
|
(
|
||||||
PythonModuleNamespace(StrSubclass('a')),
|
PythonModuleNamespace(StrSubclass('a')),
|
||||||
"PythonModuleNamespace('a')",
|
"PythonModuleNamespace('a')",
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ class StrSubclass(str): ...
|
|||||||
'namespace,expected_name',
|
'namespace,expected_name',
|
||||||
[
|
[
|
||||||
(PythonNamespace('a'), 'a'),
|
(PythonNamespace('a'), 'a'),
|
||||||
(PythonNamespace('1'), '1'),
|
|
||||||
(PythonNamespace(StrSubclass('a')), StrSubclass('a')),
|
(PythonNamespace(StrSubclass('a')), StrSubclass('a')),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -36,7 +35,6 @@ def test_PythonNamespace_name_attribute(namespace, expected_name):
|
|||||||
'namespace,expected',
|
'namespace,expected',
|
||||||
[
|
[
|
||||||
(PythonNamespace('a'), "PythonNamespace('a')"),
|
(PythonNamespace('a'), "PythonNamespace('a')"),
|
||||||
(PythonNamespace('1'), "PythonNamespace('1')"),
|
|
||||||
(PythonNamespace(StrSubclass('a')), "PythonNamespace('a')"),
|
(PythonNamespace(StrSubclass('a')), "PythonNamespace('a')"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -38,13 +38,6 @@ class StrSubclass(str): ...
|
|||||||
),
|
),
|
||||||
'a',
|
'a',
|
||||||
),
|
),
|
||||||
(
|
|
||||||
PythonPackageNamespace(
|
|
||||||
'1',
|
|
||||||
[],
|
|
||||||
),
|
|
||||||
'1',
|
|
||||||
),
|
|
||||||
(
|
(
|
||||||
PythonPackageNamespace(
|
PythonPackageNamespace(
|
||||||
StrSubclass('a'),
|
StrSubclass('a'),
|
||||||
@@ -291,10 +284,6 @@ def test_PythonPackageNamespace___eq__(namespace1, namespace2, expected):
|
|||||||
PythonPackageNamespace('a', []),
|
PythonPackageNamespace('a', []),
|
||||||
"PythonPackageNamespace('a', [])",
|
"PythonPackageNamespace('a', [])",
|
||||||
),
|
),
|
||||||
(
|
|
||||||
PythonPackageNamespace('1', []),
|
|
||||||
"PythonPackageNamespace('1', [])",
|
|
||||||
),
|
|
||||||
(
|
(
|
||||||
PythonPackageNamespace(StrSubclass('a'), []),
|
PythonPackageNamespace(StrSubclass('a'), []),
|
||||||
"PythonPackageNamespace('a', [])",
|
"PythonPackageNamespace('a', [])",
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
# Copyright 2026 jCloud
|
||||||
|
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from src.jcloud_docsgen.core.python.namespaces import validate_namespace_name
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'name,expected',
|
||||||
|
[
|
||||||
|
('a', True),
|
||||||
|
('namespace', True),
|
||||||
|
('match', True),
|
||||||
|
('case', True),
|
||||||
|
('type', True),
|
||||||
|
('_', True),
|
||||||
|
('__', True),
|
||||||
|
('___', True),
|
||||||
|
('_a', True),
|
||||||
|
('_a_', True),
|
||||||
|
('_a.', False),
|
||||||
|
('a.b', False),
|
||||||
|
('a-b', False),
|
||||||
|
('a.', False),
|
||||||
|
('a-', False),
|
||||||
|
('.a', False),
|
||||||
|
('-a', False),
|
||||||
|
('.a.', False),
|
||||||
|
('-a-', False),
|
||||||
|
('.', False),
|
||||||
|
('a-.b', False),
|
||||||
|
('"', False),
|
||||||
|
('""', False),
|
||||||
|
('def', False),
|
||||||
|
('class', False),
|
||||||
|
('import', False),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_validate_namespace_name(name, expected):
|
||||||
|
assert validate_namespace_name(name) == expected
|
||||||
Reference in new issue
Block a user