generated from jCloud/repository-template
Compare commits
76
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62cadcc7ae
|
||
|
|
ecce3a9b69
|
||
|
|
0fbfe84657
|
||
|
|
d0ea392f62
|
||
|
|
717a8c446e
|
||
|
|
ec156a538e
|
||
|
|
e2264696e8
|
||
|
|
6cf3de156d
|
||
|
|
b6d2fa7db8
|
||
|
|
63cef6f641
|
||
|
|
06802c96f6
|
||
|
|
17c5e4938f
|
||
|
|
cc786a6c69
|
||
|
|
274ed45167
|
||
|
|
62206db574
|
||
|
|
89451c34e3
|
||
|
|
f6dbefaf6c
|
||
|
|
1a230abf02
|
||
|
|
14d6a8984a
|
||
|
|
56f650d0ad
|
||
|
|
25a92d710e
|
||
|
|
a55d4d4f79
|
||
|
|
24673a45a5
|
||
|
|
0e81d0b9ca
|
||
|
|
b5f67caa69
|
||
|
|
de3eac3bb1
|
||
|
|
aa4a139878
|
||
|
|
d9887f34c9
|
||
|
|
178e6b0bd8
|
||
|
|
f680110110
|
||
|
|
475775eb7e
|
||
|
|
ffcc7404de
|
||
|
|
23e450e9df
|
||
|
|
caa8e04047
|
||
|
|
8930efc7e6
|
||
|
|
1ce3d8f9d1
|
||
|
|
56588e6c78
|
||
|
|
bd7780f112
|
||
|
|
5e84156e01
|
||
|
|
089cf5f2ff
|
||
|
|
8644232a00
|
||
|
|
2cb99d4ca9
|
||
|
|
8f5dc33369
|
||
|
|
e2e6a59d13
|
||
|
|
84fe67230f
|
||
|
|
348be4f07f
|
||
|
|
db0d36f956
|
||
|
|
29d1c5bced
|
||
|
|
3ab9884be0
|
||
|
|
60a097f0cc
|
||
|
|
a8513a78e2
|
||
|
|
34457f0b9f
|
||
|
|
bce073746e
|
||
|
|
350f8f9941
|
||
|
|
2d6de2028f
|
||
|
|
436dacf806
|
||
|
|
3cd374c354
|
||
|
|
78e3e020be
|
||
|
|
36cedb390b
|
||
|
|
d54c0fb208
|
||
|
|
5d8dbd659d
|
||
|
|
1789352287
|
||
|
|
3daff2ba13
|
||
|
|
20fe7c5605
|
||
|
|
f5b2c77427
|
||
|
|
75a13527a9
|
||
|
|
ac8bd2374f
|
||
|
|
c47aa0738a
|
||
|
|
260f41b808
|
||
|
|
c4212320a2
|
||
|
|
324ffcd4eb
|
||
|
|
aa702ca9f9
|
||
|
|
ef5605ced1
|
||
|
|
eac5fb0ffc
|
||
|
|
5c036e60a1
|
||
|
|
9b49de336b
|
No files matched your search
@@ -0,0 +1,58 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
name: Generate API reference
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branch:
|
||||||
|
- main
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
generate:
|
||||||
|
runs-on: python
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install jcloud-docsgen
|
||||||
|
run: |
|
||||||
|
pip install \
|
||||||
|
--index-url https://gitea.jcloud-services.ddns.net/api/packages/jCloud/pypi/simple/ \
|
||||||
|
--extra-index-url https://pypi.org/simple \
|
||||||
|
jcloud-docsgen
|
||||||
|
|
||||||
|
- name: Generate documentation
|
||||||
|
run: |
|
||||||
|
rm -rf docs/reference
|
||||||
|
jcloud-docsgen python -T -o docs/reference .
|
||||||
|
|
||||||
|
- name: Commit and push
|
||||||
|
run: |
|
||||||
|
git config user.name "${{ vars.BOT_NAME }}"
|
||||||
|
git config user.email "${{ vars.BOT_EMAIL }}"
|
||||||
|
|
||||||
|
git add docs/reference
|
||||||
|
|
||||||
|
if git diff --chached --quit; then
|
||||||
|
echo "No changes"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
git commit -m "chore: update API reference"
|
||||||
|
git push
|
||||||
@@ -25,7 +25,7 @@ permissions:
|
|||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: Build package
|
name: Build package
|
||||||
runs-on: python-node
|
runs-on: python
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -45,6 +45,7 @@ jobs:
|
|||||||
prepare_upload_release_asset:
|
prepare_upload_release_asset:
|
||||||
name: Prepare release asset upload
|
name: Prepare release asset upload
|
||||||
runs-on: debian
|
runs-on: debian
|
||||||
|
needs: build
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
files: ${{ steps.files.outputs.files }}
|
files: ${{ steps.files.outputs.files }}
|
||||||
@@ -82,6 +83,12 @@ jobs:
|
|||||||
file: ${{ fromJSON(needs.prepare_upload_release_asset.outputs.files) }}
|
file: ${{ fromJSON(needs.prepare_upload_release_asset.outputs.files) }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
- name: Download artifact
|
||||||
|
uses: christopherhx/gitea-download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: build-output
|
||||||
|
path: dist/
|
||||||
|
|
||||||
- uses: ${{ gitea.server_url }}/jCloud/actions/upload-release-asset@60d1ae076c2e1802e4bc9461e26c42c557652811
|
- uses: ${{ gitea.server_url }}/jCloud/actions/upload-release-asset@60d1ae076c2e1802e4bc9461e26c42c557652811
|
||||||
with:
|
with:
|
||||||
file: ${{ matrix.file }}
|
file: ${{ matrix.file }}
|
||||||
@@ -92,7 +99,7 @@ jobs:
|
|||||||
publish:
|
publish:
|
||||||
if: ${{ !github.event.release.prerelease && !github.event.release.draft }}
|
if: ${{ !github.event.release.prerelease && !github.event.release.draft }}
|
||||||
name: Publish package to package registry
|
name: Publish package to package registry
|
||||||
runs-on: debian
|
runs-on: python
|
||||||
needs: build
|
needs: build
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
+176
-4
@@ -1,5 +1,177 @@
|
|||||||
dist/
|
# Byte-compiled / optimized / DLL files
|
||||||
src/*.egg-info/
|
|
||||||
.vscode/
|
|
||||||
.pytest_cache/
|
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
cover/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
.pybuilder/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
|
# .python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# UV
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
#uv.lock
|
||||||
|
|
||||||
|
# poetry
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||||
|
#poetry.lock
|
||||||
|
|
||||||
|
# pdm
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||||
|
#pdm.lock
|
||||||
|
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||||
|
# in version control.
|
||||||
|
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
||||||
|
.pdm.toml
|
||||||
|
.pdm-python
|
||||||
|
.pdm-build/
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
# Cython debug symbols
|
||||||
|
cython_debug/
|
||||||
|
|
||||||
|
# PyCharm
|
||||||
|
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||||
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
|
#.idea/
|
||||||
|
|
||||||
|
# Ruff stuff:
|
||||||
|
.ruff_cache/
|
||||||
|
|
||||||
|
# PyPI configuration file
|
||||||
|
.pypirc
|
||||||
|
|
||||||
|
# VS Code
|
||||||
|
.vscode/
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
# ------------------------------------------------ SUBJECT AREA
|
||||||
|
# ---------------------------------------------------------------------- DETAIL AREA
|
||||||
|
|
||||||
|
# Please enter a subject that does not exceed the limit of 50
|
||||||
|
# characters.
|
||||||
|
# If you enter a detailed description, no line should
|
||||||
|
# exceed the limit of 72 characters. Break the line as soon as you
|
||||||
|
# reach this limit.
|
||||||
@@ -7,11 +7,11 @@ Currently supported programming languages:
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
You can install it using pip:
|
You can install the package `jcloud-docsgen` from the [Gitea Package Registry](https://gitea.jcloud-services.ddns.net/jCloud/-/packages/pypi/jcloud-docsgen/).
|
||||||
|
|
||||||
```bash
|
## Setup
|
||||||
pip install jcloud-docsgen --index-url https://repo.jcloud-services.ddns.net/simple/ --extra-index-url https://pypi.org/simple/
|
|
||||||
```
|
Please execute `scripts/setup.sh` when cloning the repository to configure Git.
|
||||||
|
|
||||||
## Reference
|
## Reference
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,24 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- CLI for `jcloud-docsgen` that can be called without `python3 -m ...`
|
||||||
|
- CI pipeline to generate API reference on every push or merge on `main`
|
||||||
|
- Python generator output directory creation
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Replaced the installation instructions, which used the old registry, with a reference to the Gitea Package Registry in README
|
||||||
|
- Made Python function signatures (argument default values) compliant with PEP 8
|
||||||
|
- Removed implicit project directory structure assumptions
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
- utility class for existing directories
|
||||||
|
- utility class for existing files
|
||||||
|
|
||||||
## [0.1.0] - 2026-09-01
|
## [0.1.0] - 2026-09-01
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
Generated
+248
@@ -0,0 +1,248 @@
|
|||||||
|
# This file is automatically @generated by Poetry 2.4.3 and should not be changed by hand.
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorama"
|
||||||
|
version = "0.4.6"
|
||||||
|
description = "Cross-platform colored terminal text."
|
||||||
|
optional = false
|
||||||
|
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||||
|
groups = ["dev"]
|
||||||
|
markers = "sys_platform == \"win32\""
|
||||||
|
files = [
|
||||||
|
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
||||||
|
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "docstring-parser"
|
||||||
|
version = "0.18.0"
|
||||||
|
description = "Parse Python docstrings in reST, Google and Numpydoc format"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
groups = ["main"]
|
||||||
|
files = [
|
||||||
|
{file = "docstring_parser-0.18.0-py3-none-any.whl", hash = "sha256:b3fcbed555c47d8479be0796ef7e19c2670d428d72e96da63f3a40122860374b"},
|
||||||
|
{file = "docstring_parser-0.18.0.tar.gz", hash = "sha256:292510982205c12b1248696f44959db3cdd1740237a968ea1e2e7a900eeb2015"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["pre-commit (>=2.16.0) ; python_version >= \"3.9\"", "pydoctor (>=25.4.0)", "pytest"]
|
||||||
|
docs = ["pydoctor (>=25.4.0)"]
|
||||||
|
test = ["pytest"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "exceptiongroup"
|
||||||
|
version = "1.3.1"
|
||||||
|
description = "Backport of PEP 654 (exception groups)"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
groups = ["dev"]
|
||||||
|
markers = "python_version == \"3.10\""
|
||||||
|
files = [
|
||||||
|
{file = "exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598"},
|
||||||
|
{file = "exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""}
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
test = ["pytest (>=6)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iniconfig"
|
||||||
|
version = "2.3.0"
|
||||||
|
description = "brain-dead simple config-ini parsing"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.10"
|
||||||
|
groups = ["dev"]
|
||||||
|
files = [
|
||||||
|
{file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"},
|
||||||
|
{file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "packaging"
|
||||||
|
version = "26.3"
|
||||||
|
description = "Core utilities for Python packages"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.9"
|
||||||
|
groups = ["dev"]
|
||||||
|
files = [
|
||||||
|
{file = "packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c"},
|
||||||
|
{file = "packaging-26.3.tar.gz", hash = "sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pluggy"
|
||||||
|
version = "1.6.0"
|
||||||
|
description = "plugin and hook calling mechanisms for python"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.9"
|
||||||
|
groups = ["dev"]
|
||||||
|
files = [
|
||||||
|
{file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"},
|
||||||
|
{file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["pre-commit", "tox"]
|
||||||
|
testing = ["coverage", "pytest", "pytest-benchmark"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pygments"
|
||||||
|
version = "2.21.0"
|
||||||
|
description = "Pygments is a syntax highlighting package written in Python."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.9"
|
||||||
|
groups = ["dev"]
|
||||||
|
files = [
|
||||||
|
{file = "pygments-2.21.0-py3-none-any.whl", hash = "sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9"},
|
||||||
|
{file = "pygments-2.21.0.tar.gz", hash = "sha256:610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
windows-terminal = ["colorama (>=0.4.6)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pytest"
|
||||||
|
version = "9.1.1"
|
||||||
|
description = "pytest: simple powerful testing with Python"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.10"
|
||||||
|
groups = ["dev"]
|
||||||
|
files = [
|
||||||
|
{file = "pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c"},
|
||||||
|
{file = "pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""}
|
||||||
|
exceptiongroup = {version = ">=1", markers = "python_version < \"3.11\""}
|
||||||
|
iniconfig = ">=1.0.1"
|
||||||
|
packaging = ">=22"
|
||||||
|
pluggy = ">=1.5,<2"
|
||||||
|
pygments = ">=2.7.2"
|
||||||
|
tomli = {version = ">=1", markers = "python_version < \"3.11\""}
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pytest-expectdir"
|
||||||
|
version = "1.2.0"
|
||||||
|
description = "A pytest plugin to provide initial/expected directories, and check a test transforms the initial directory to the expected one"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
groups = ["dev"]
|
||||||
|
files = [
|
||||||
|
{file = "pytest-expectdir-1.2.0.tar.gz", hash = "sha256:145b7f86d4e8ae7c7cace3007f32d68afbdd4d18c392b3d5792794f8e9d51fae"},
|
||||||
|
{file = "pytest_expectdir-1.2.0-py3-none-any.whl", hash = "sha256:8fa19e7c0b69d6bfd0e81c6e33c9a8283eb14a7bab8408067e430a827a03f993"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
pytest = ">=5.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ruff"
|
||||||
|
version = "0.16.8"
|
||||||
|
description = "An extremely fast Python linter and code formatter, written in Rust."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
groups = ["dev"]
|
||||||
|
files = [
|
||||||
|
{file = "ruff-0.16.8-py3-none-linux_armv6l.whl", hash = "sha256:6ffbd6d87383c1edf5f6fa890f10200950240d7c1a16052a19a09d3a2307dd38"},
|
||||||
|
{file = "ruff-0.16.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:42ed6b878ed61e3acca92f2730a17acff39286944ea82398544696366a6f925e"},
|
||||||
|
{file = "ruff-0.16.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7ea781c7f2afba8c6a505ea0fb3f994020249e0c450635f5381286fea6b46170"},
|
||||||
|
{file = "ruff-0.16.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8efeae3bbe414a5efefda11a792dfb51ef90ac48d50c4830de2f644caf3e8659"},
|
||||||
|
{file = "ruff-0.16.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a79b795469fef7fc6e908b218eed2eb17332afd85031db6480dc864560e69b2"},
|
||||||
|
{file = "ruff-0.16.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fdc5563cdc50555e6fba39322850860e9267c1b3d12c26a74729d8604c3c812"},
|
||||||
|
{file = "ruff-0.16.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34508983c70665578dab88f5223d8e6228307e1135398ca8bfc8b7e9501e282b"},
|
||||||
|
{file = "ruff-0.16.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:644bb578569e0ffc575741232bd385dacdd6fbe123f1a729e7a225f54aa3957f"},
|
||||||
|
{file = "ruff-0.16.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15e7d226246961db9235098333caa13063906d3851136b84c2900b82f5daa1df"},
|
||||||
|
{file = "ruff-0.16.8-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a2bf6bc3e9ebdd4449abc6f06cf64b98051a2c61cf94d2fe9596518c881f1a1e"},
|
||||||
|
{file = "ruff-0.16.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6ca111ba0849539165e9e59d2b442542f3c1e8060ebbdea82494f1ffbccb1e1f"},
|
||||||
|
{file = "ruff-0.16.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:359a1e5b495448ee1e91018064382ebc86f90e8aac2fed222c7d0e4e8df85fd2"},
|
||||||
|
{file = "ruff-0.16.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:59e8f5681349474110b24d62e93cfda6593f5fa3473446ca3705200cac1a08b9"},
|
||||||
|
{file = "ruff-0.16.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:efa3e7a16d1baaa79957888dfdf8be9ef2e44db81cb032af06d76632ab59e773"},
|
||||||
|
{file = "ruff-0.16.8-py3-none-win32.whl", hash = "sha256:55793ba85c69921e89be061426d91a78652d6e50317c962240922747a4eb713f"},
|
||||||
|
{file = "ruff-0.16.8-py3-none-win_amd64.whl", hash = "sha256:a6b85621fd3c81e31fc5f5add09c9c078b430db3595ca632efafdec9e64ebfaa"},
|
||||||
|
{file = "ruff-0.16.8-py3-none-win_arm64.whl", hash = "sha256:d075e820af612102ce217f07cc93e69f9490b10ec13ea85fa87bd03d996cef8a"},
|
||||||
|
{file = "ruff-0.16.8.tar.gz", hash = "sha256:9247bf92b5f04d825c8639a4fe423ec2e4222acd9222e58412b0dab7e442798b"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tomli"
|
||||||
|
version = "2.4.1"
|
||||||
|
description = "A lil' TOML parser"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
groups = ["dev"]
|
||||||
|
markers = "python_version == \"3.10\""
|
||||||
|
files = [
|
||||||
|
{file = "tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30"},
|
||||||
|
{file = "tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a"},
|
||||||
|
{file = "tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076"},
|
||||||
|
{file = "tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9"},
|
||||||
|
{file = "tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c"},
|
||||||
|
{file = "tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc"},
|
||||||
|
{file = "tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049"},
|
||||||
|
{file = "tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e"},
|
||||||
|
{file = "tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece"},
|
||||||
|
{file = "tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a"},
|
||||||
|
{file = "tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085"},
|
||||||
|
{file = "tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9"},
|
||||||
|
{file = "tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5"},
|
||||||
|
{file = "tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585"},
|
||||||
|
{file = "tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1"},
|
||||||
|
{file = "tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917"},
|
||||||
|
{file = "tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9"},
|
||||||
|
{file = "tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257"},
|
||||||
|
{file = "tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54"},
|
||||||
|
{file = "tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a"},
|
||||||
|
{file = "tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897"},
|
||||||
|
{file = "tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f"},
|
||||||
|
{file = "tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d"},
|
||||||
|
{file = "tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5"},
|
||||||
|
{file = "tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd"},
|
||||||
|
{file = "tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36"},
|
||||||
|
{file = "tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd"},
|
||||||
|
{file = "tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf"},
|
||||||
|
{file = "tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac"},
|
||||||
|
{file = "tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662"},
|
||||||
|
{file = "tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853"},
|
||||||
|
{file = "tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15"},
|
||||||
|
{file = "tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba"},
|
||||||
|
{file = "tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6"},
|
||||||
|
{file = "tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7"},
|
||||||
|
{file = "tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232"},
|
||||||
|
{file = "tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4"},
|
||||||
|
{file = "tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c"},
|
||||||
|
{file = "tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d"},
|
||||||
|
{file = "tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41"},
|
||||||
|
{file = "tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c"},
|
||||||
|
{file = "tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f"},
|
||||||
|
{file = "tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8"},
|
||||||
|
{file = "tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26"},
|
||||||
|
{file = "tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396"},
|
||||||
|
{file = "tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe"},
|
||||||
|
{file = "tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typing-extensions"
|
||||||
|
version = "4.16.0"
|
||||||
|
description = "Backported and Experimental Type Hints for Python 3.9+"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.9"
|
||||||
|
groups = ["dev"]
|
||||||
|
markers = "python_version == \"3.10\""
|
||||||
|
files = [
|
||||||
|
{file = "typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8"},
|
||||||
|
{file = "typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
lock-version = "2.1"
|
||||||
|
python-versions = ">=3.10"
|
||||||
|
content-hash = "24c9a2d464f6c737eeae0a66f792fa23824c3960b7cc72a22fff1408f21ec812"
|
||||||
+37
-6
@@ -1,16 +1,47 @@
|
|||||||
[build-system]
|
[build-system]
|
||||||
requires = ["setuptools", "wheel"]
|
requires = ["poetry-core>=2.0.0"]
|
||||||
build-backend = "setuptools.build_meta"
|
build-backend = "poetry.core.masonry.api"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "jcloud-docsgen"
|
name = "jcloud-docsgen"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
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"]
|
||||||
|
requires-python = ">=3.10"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
|
||||||
[tool.setuptools]
|
[project.scripts]
|
||||||
package-dir = {"" = "src"}
|
jcloud-docsgen = "jcloud_docsgen.cli:main"
|
||||||
|
|
||||||
[tool.setuptools.packages.find]
|
[tool.poetry]
|
||||||
where = ["src"]
|
packages = [
|
||||||
|
{ include = "jcloud_docsgen", from = "src"}
|
||||||
|
]
|
||||||
|
|
||||||
|
[[tool.poetry.source]]
|
||||||
|
name = "jcloud"
|
||||||
|
url = "https://gitea.jcloud-services.ddns.net/api/packages/jCloud/pypi/simple/"
|
||||||
|
priority = "supplemental"
|
||||||
|
|
||||||
|
[dependency-groups]
|
||||||
|
dev = [
|
||||||
|
"pytest (>=9.1.1,<10.0.0)",
|
||||||
|
"pytest-expectdir (>=1.2.0,<2.0.0)",
|
||||||
|
"ruff (>=0.16.8,<0.17.0)"
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.ruff]
|
||||||
|
line-length = 79
|
||||||
|
target-version = "py311"
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
|
select = [
|
||||||
|
"E",
|
||||||
|
"F",
|
||||||
|
"W",
|
||||||
|
"I",
|
||||||
|
"UP"
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
quote-style = "single"
|
||||||
Executable
+15
@@ -0,0 +1,15 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
git config --local commit.template .gitmessage
|
||||||
@@ -18,5 +18,5 @@ from .core import __all__ as _core__all__
|
|||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'cli',
|
'cli',
|
||||||
*_core__all__
|
*_core__all__,
|
||||||
]
|
]
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# 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 sys
|
||||||
|
|
||||||
|
from .cli.cli import main
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main())
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
'''
|
|
||||||
The command line interface
|
|
||||||
'''
|
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
'main'
|
|
||||||
]
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import pathlib
|
|
||||||
from .utils import ExistingDirectory
|
|
||||||
|
|
||||||
def existing_directory(path: str, *args, **kwargs) -> pathlib.Path:
|
|
||||||
try:
|
|
||||||
return ExistingDirectory(path, *args, **kwargs)
|
|
||||||
except (FileNotFoundError, NotADirectoryError) as e:
|
|
||||||
raise argparse.ArgumentTypeError(f'{e.filename}{": " + e.args[1] if len(e.args) > 1 else ""}')
|
|
||||||
|
|
||||||
def main() -> int:
|
|
||||||
argument_parser = argparse.ArgumentParser()
|
|
||||||
argument_parser.add_argument('project_directory', type = existing_directory, default = pathlib.Path('.'), help = 'The directory of the project')
|
|
||||||
args = argument_parser.parse_args()
|
|
||||||
return 0
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
from . import cli, languages
|
||||||
|
from .cli import main
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'cli',
|
||||||
|
'languages',
|
||||||
|
'main',
|
||||||
|
]
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
"""
|
||||||
|
The command line interface
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import pathlib
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from .languages.python import VALID_SECTIONS as VALID_PYTHON_SECTIONS
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'existing_directory',
|
||||||
|
'error',
|
||||||
|
'create_argument_parser',
|
||||||
|
'main',
|
||||||
|
]
|
||||||
|
|
||||||
|
_LANG_PYTHON = 'python'
|
||||||
|
_PROGRAM_NAME = 'jcloud-docsgen'
|
||||||
|
|
||||||
|
|
||||||
|
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')
|
||||||
|
if not path.is_dir():
|
||||||
|
raise argparse.ArgumentTypeError(f'{_path}: not a directory')
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
def error(message: str, exit_code: int = 1):
|
||||||
|
"""
|
||||||
|
Shows an error message and returns the exit code.
|
||||||
|
|
||||||
|
:param message: The error message to show.
|
||||||
|
:type message: str
|
||||||
|
:param exit_code: The exit code.
|
||||||
|
:type exit_code: int
|
||||||
|
"""
|
||||||
|
|
||||||
|
print(f'{_PROGRAM_NAME}: error: {message}', file=sys.stderr)
|
||||||
|
return exit_code
|
||||||
|
|
||||||
|
|
||||||
|
def create_argument_parser() -> argparse.ArgumentParser:
|
||||||
|
"""
|
||||||
|
Prepares a parser to parse the command-line arguments using
|
||||||
|
argparse.
|
||||||
|
|
||||||
|
:return: The parser.
|
||||||
|
:rtype: argparse.ArgumentParser
|
||||||
|
"""
|
||||||
|
|
||||||
|
common_parser = argparse.ArgumentParser(add_help=False)
|
||||||
|
common_parser.add_argument(
|
||||||
|
'project_directory',
|
||||||
|
type=existing_directory,
|
||||||
|
nargs='?',
|
||||||
|
default=pathlib.Path('.'),
|
||||||
|
help='The directory of the project',
|
||||||
|
)
|
||||||
|
common_parser.add_argument(
|
||||||
|
'-o',
|
||||||
|
'--output-dir',
|
||||||
|
type=pathlib.Path,
|
||||||
|
default='docs/reference',
|
||||||
|
help='the output directory the documentation will be written to',
|
||||||
|
)
|
||||||
|
|
||||||
|
argument_parser = argparse.ArgumentParser()
|
||||||
|
|
||||||
|
subparsers = argument_parser.add_subparsers(
|
||||||
|
dest='language',
|
||||||
|
required=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
python_parser = subparsers.add_parser(
|
||||||
|
_LANG_PYTHON,
|
||||||
|
parents=[common_parser],
|
||||||
|
help='generate documentation for Python project',
|
||||||
|
)
|
||||||
|
python_parser.add_argument(
|
||||||
|
'-s',
|
||||||
|
'--sections',
|
||||||
|
nargs='+',
|
||||||
|
choices=VALID_PYTHON_SECTIONS,
|
||||||
|
help='the sections to be included in the documentation',
|
||||||
|
)
|
||||||
|
python_parser.add_argument(
|
||||||
|
'-S',
|
||||||
|
'--sections-exclude',
|
||||||
|
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.'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
python_parser.add_argument(
|
||||||
|
'-H',
|
||||||
|
'--allow-html',
|
||||||
|
action='store_true',
|
||||||
|
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.'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
return argument_parser
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv=None) -> int:
|
||||||
|
argument_parser = create_argument_parser()
|
||||||
|
args = argument_parser.parse_args(argv)
|
||||||
|
|
||||||
|
try:
|
||||||
|
if args.language == _LANG_PYTHON:
|
||||||
|
from .languages.python import generate
|
||||||
|
|
||||||
|
generate(
|
||||||
|
args.project_directory,
|
||||||
|
args.output_dir,
|
||||||
|
include_sections=args.sections,
|
||||||
|
exclude_sections=args.sections_exclude,
|
||||||
|
allow_html=args.allow_html,
|
||||||
|
allow_tables=args.allow_tables,
|
||||||
|
)
|
||||||
|
except FileNotFoundError as exc:
|
||||||
|
return error(f'{exc.filename}: no such file or directory')
|
||||||
|
except NotADirectoryError as exc:
|
||||||
|
return error(f'{exc.filename}: not a directory')
|
||||||
|
except IsADirectoryError as exc:
|
||||||
|
return error(f'{exc.filename}: is a directory')
|
||||||
|
except FileExistsError as exc:
|
||||||
|
return error(f'{exc.filename}: file already exists')
|
||||||
|
except PermissionError as exc:
|
||||||
|
return error(f'{exc.filename}: permission denied')
|
||||||
|
except OSError as exc:
|
||||||
|
return error(f'{exc.filename}: {exc.args[1]}')
|
||||||
|
except UnicodeError:
|
||||||
|
return error('invalid text encoding')
|
||||||
|
except SyntaxError:
|
||||||
|
# TODO: add a custom exception class to clearify that a project
|
||||||
|
# parsing syntax error is meant.
|
||||||
|
return error('syntax error in project source code')
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
return 130
|
||||||
|
except BrokenPipeError:
|
||||||
|
return 141
|
||||||
|
|
||||||
|
return 0
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
from . import python
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'python',
|
||||||
|
]
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
# 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 pathlib
|
||||||
|
|
||||||
|
from ...core.python import (
|
||||||
|
PythonDefinitionDocumentationIncludeSections,
|
||||||
|
PythonDocumentationGenerator,
|
||||||
|
)
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'VALID_SECTIONS',
|
||||||
|
'parse_sections_list',
|
||||||
|
'generate',
|
||||||
|
]
|
||||||
|
|
||||||
|
VALID_SECTIONS = list(
|
||||||
|
PythonDefinitionDocumentationIncludeSections()._args.keys()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_sections_list(
|
||||||
|
include_sections: list[str] | None = 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.
|
||||||
|
These lists both consist of the sections as strings which contain
|
||||||
|
the section name.
|
||||||
|
|
||||||
|
:param include_sections: The list of sections to be included.
|
||||||
|
:type include_sections: list[str] | None
|
||||||
|
:param exclude_sections: The list of sections to be excluded.
|
||||||
|
:type exclude_sections: list[str]
|
||||||
|
|
||||||
|
:return: The Python definition documentation sections object.
|
||||||
|
:rtype: PythonDefinitionDocumentationIncludeSections
|
||||||
|
"""
|
||||||
|
|
||||||
|
if include_sections is None:
|
||||||
|
include_sections = VALID_SECTIONS[:]
|
||||||
|
|
||||||
|
for section in exclude_sections:
|
||||||
|
while section in include_sections:
|
||||||
|
del include_sections[include_sections.index(section)]
|
||||||
|
|
||||||
|
return PythonDefinitionDocumentationIncludeSections(
|
||||||
|
signature='signature' in include_sections,
|
||||||
|
returns='returns' in include_sections,
|
||||||
|
params='params' in include_sections,
|
||||||
|
exceptions='exceptions' in include_sections,
|
||||||
|
examples='examples' in include_sections,
|
||||||
|
docstring='docstring' in include_sections,
|
||||||
|
bases='bases' in include_sections,
|
||||||
|
decorators='decorators' in include_sections,
|
||||||
|
class_body='class_body' in include_sections,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _generate(
|
||||||
|
project_directory: pathlib.Path,
|
||||||
|
output_directory: pathlib.Path,
|
||||||
|
*,
|
||||||
|
include_sections: PythonDefinitionDocumentationIncludeSections = (
|
||||||
|
PythonDefinitionDocumentationIncludeSections()
|
||||||
|
),
|
||||||
|
allow_html: bool = False,
|
||||||
|
allow_tables: bool = False,
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Generates the documentation for a Python project.
|
||||||
|
|
||||||
|
:param project_directory: The project directory.
|
||||||
|
:type project_directory: pathlib.Path
|
||||||
|
:param output_directory: The output directory.
|
||||||
|
:type output_directory: pathlib.Path
|
||||||
|
:param include_sections: The sections to be included in the
|
||||||
|
documentation.
|
||||||
|
:type include_sections: PythonDefinitionDocumentationIncludeSections
|
||||||
|
:param allow_html: Indicates whether HTML is allowed to appear in
|
||||||
|
the generated documentation.
|
||||||
|
:type allow_html: bool
|
||||||
|
:param allow_tables: Indicates whether Markdown tables are allowed.
|
||||||
|
Warning: Markdown tables are not CommonMark.
|
||||||
|
"""
|
||||||
|
|
||||||
|
docs_generator = PythonDocumentationGenerator(
|
||||||
|
project_directory,
|
||||||
|
output_directory,
|
||||||
|
include_sections=include_sections,
|
||||||
|
allow_html=allow_html,
|
||||||
|
allow_tables=allow_tables,
|
||||||
|
)
|
||||||
|
docs_generator.generate_documentation()
|
||||||
|
|
||||||
|
|
||||||
|
def generate(
|
||||||
|
project_directory: pathlib.Path,
|
||||||
|
output_directory: pathlib.Path,
|
||||||
|
*,
|
||||||
|
include_sections: list[str] | None = None,
|
||||||
|
exclude_sections: list[str] = [],
|
||||||
|
allow_html: bool = False,
|
||||||
|
allow_tables: bool = False,
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Generates the documentation for a Python project.
|
||||||
|
|
||||||
|
:param project_directory: The project directory.
|
||||||
|
:type project_directory: pathlib.Path
|
||||||
|
:param output_directory: The output directory.
|
||||||
|
:type output_directory: pathlib.Path
|
||||||
|
:param include_sections: The sections to be included in the
|
||||||
|
documentation.
|
||||||
|
:type include_sections: list[str] | None
|
||||||
|
:param exclude_sections: The sections to be excluded in the
|
||||||
|
documentation.
|
||||||
|
:type exclude_sections: list[str]
|
||||||
|
:param allow_html: Indicates whether HTML is allowed to appear in
|
||||||
|
the generated documentation.
|
||||||
|
:type allow_html: bool
|
||||||
|
:param allow_tables: Indicates whether Markdown tables are allowed.
|
||||||
|
Warning: Markdown tables are not CommonMark.
|
||||||
|
"""
|
||||||
|
|
||||||
|
sections = parse_sections_list(include_sections, exclude_sections)
|
||||||
|
|
||||||
|
_generate(
|
||||||
|
project_directory,
|
||||||
|
output_directory,
|
||||||
|
include_sections=sections,
|
||||||
|
allow_html=allow_html,
|
||||||
|
allow_tables=allow_tables,
|
||||||
|
)
|
||||||
@@ -15,5 +15,5 @@
|
|||||||
from . import python
|
from . import python
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'python'
|
'python',
|
||||||
]
|
]
|
||||||
@@ -12,11 +12,11 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
from . import namespaces
|
||||||
from ._core import *
|
from ._core import *
|
||||||
from ._core import __all__ as _core__all__
|
from ._core import __all__ as _core__all__
|
||||||
from . import namespaces
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
*_core__all__,
|
*_core__all__,
|
||||||
'namespaces'
|
'namespaces',
|
||||||
]
|
]
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -13,20 +13,26 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from enum import Enum
|
|
||||||
from typing import Union
|
|
||||||
import ast
|
import ast
|
||||||
from ...utils import assert_that_is_instance
|
|
||||||
from ...exceptions import InvalidPythonIdentifierError, InvalidPythonAnnotationError, PythonArgumentStructureError
|
|
||||||
import keyword
|
import keyword
|
||||||
import types
|
import types
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
from ...exceptions import (
|
||||||
|
InvalidPythonAnnotationError,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
PythonArgumentStructureError,
|
||||||
|
)
|
||||||
|
from ...utils import assert_that_is_instance
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'PythonArgumentKind',
|
'PythonArgumentKind',
|
||||||
'PythonFunctionArgument',
|
'PythonFunctionArgument',
|
||||||
'PythonASTArgumentsListParser'
|
'PythonASTArgumentsListParser',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class PythonArgumentKind(Enum):
|
class PythonArgumentKind(Enum):
|
||||||
NORMAL = 0
|
NORMAL = 0
|
||||||
POSITIONAL_ONLY = 1
|
POSITIONAL_ONLY = 1
|
||||||
@@ -34,8 +40,9 @@ class PythonArgumentKind(Enum):
|
|||||||
VARARG = 3
|
VARARG = 3
|
||||||
KWARGS = 4
|
KWARGS = 4
|
||||||
|
|
||||||
|
|
||||||
class PythonFunctionArgument:
|
class PythonFunctionArgument:
|
||||||
'''
|
"""
|
||||||
Represents an argument of a Python function.
|
Represents an argument of a Python function.
|
||||||
|
|
||||||
:param name: The name of the argument.
|
:param name: The name of the argument.
|
||||||
@@ -43,12 +50,18 @@ class PythonFunctionArgument:
|
|||||||
:param kind: The kind of the argument.
|
:param kind: The kind of the argument.
|
||||||
:type kind: ArgumentKind
|
:type kind: ArgumentKind
|
||||||
:param default: The default value of the argument.
|
:param default: The default value of the argument.
|
||||||
:type default: Union[str, None]
|
:type default: str | None
|
||||||
:param annotation: The type annotation of the argument.
|
:param annotation: The type annotation of the argument.
|
||||||
:type annotation: Union[str, None]
|
:type annotation: 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: str | None,
|
||||||
|
annotation: str | None,
|
||||||
|
) -> None:
|
||||||
assert_that_is_instance(name, str)
|
assert_that_is_instance(name, str)
|
||||||
assert_that_is_instance(kind, PythonArgumentKind)
|
assert_that_is_instance(kind, PythonArgumentKind)
|
||||||
assert_that_is_instance(default, (str, types.NoneType))
|
assert_that_is_instance(default, (str, types.NoneType))
|
||||||
@@ -56,42 +69,65 @@ class PythonFunctionArgument:
|
|||||||
|
|
||||||
# check whether name is a valid identifier
|
# check whether name is a valid identifier
|
||||||
if not name or not name.isidentifier() or keyword.iskeyword(name):
|
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
|
# check whether the annotation is a valid annotation
|
||||||
# Currently, it is only checked whether the parameter is not
|
# Currently, it is only checked whether the parameter is not
|
||||||
# empty.
|
# empty.
|
||||||
if annotation is not None and not annotation:
|
if annotation is not None and not annotation:
|
||||||
raise InvalidPythonAnnotationError('invalid annotation', annotation = annotation)
|
raise InvalidPythonAnnotationError(
|
||||||
|
'invalid annotation',
|
||||||
|
annotation=annotation,
|
||||||
|
)
|
||||||
|
|
||||||
self.name = name
|
self.name = name
|
||||||
self.kind = kind
|
self.kind = kind
|
||||||
self.default = default
|
self.default = default
|
||||||
self.annotation = annotation
|
self.annotation = annotation
|
||||||
|
|
||||||
if self.kind in (PythonArgumentKind.VARARG, PythonArgumentKind.KWARGS) and self.default is not None:
|
if (
|
||||||
raise PythonArgumentStructureError('* or ** arguments cannot have default values', definition = self.signature_repr())
|
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:
|
def __eq__(self, value: PythonFunctionArgument) -> bool:
|
||||||
if not isinstance(value, PythonFunctionArgument):
|
if not isinstance(value, PythonFunctionArgument):
|
||||||
return False
|
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:
|
def __repr__(self) -> str:
|
||||||
return type(self).__name__ + repr((
|
return type(self).__name__ + repr(
|
||||||
|
(
|
||||||
self.name,
|
self.name,
|
||||||
self.kind,
|
self.kind,
|
||||||
self.default,
|
self.default,
|
||||||
self.annotation
|
self.annotation,
|
||||||
))
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def signature_repr(self) -> str:
|
def signature_repr(self) -> str:
|
||||||
'''
|
"""
|
||||||
Returns the function signature representation of the argument.
|
Returns the function signature representation of the argument.
|
||||||
|
|
||||||
:return: The string representation of the argument.
|
:return: The string representation of the argument.
|
||||||
:rtype: str
|
:rtype: str
|
||||||
'''
|
"""
|
||||||
|
|
||||||
if self.kind == PythonArgumentKind.KWARGS:
|
if self.kind == PythonArgumentKind.KWARGS:
|
||||||
str_repr = '**'
|
str_repr = '**'
|
||||||
@@ -106,68 +142,154 @@ class PythonFunctionArgument:
|
|||||||
str_repr += ': ' + self.annotation
|
str_repr += ': ' + self.annotation
|
||||||
|
|
||||||
if self.default is not None:
|
if self.default is not None:
|
||||||
|
if self.annotation is None:
|
||||||
|
str_repr += '=' + self.default
|
||||||
|
else:
|
||||||
str_repr += ' = ' + self.default
|
str_repr += ' = ' + self.default
|
||||||
|
|
||||||
return str_repr
|
return str_repr
|
||||||
|
|
||||||
|
|
||||||
class PythonASTArgumentsListParser:
|
class PythonASTArgumentsListParser:
|
||||||
'''
|
"""
|
||||||
A parser for making ``PythonFunctionArgument`` objects from an
|
A parser for making ``PythonFunctionArgument`` objects from an
|
||||||
``ast.arguments`` arguments list.
|
``ast.arguments`` arguments list.
|
||||||
|
|
||||||
:param ast_arguments_list: The ``ast.arguments`` arguments list.
|
:param ast_arguments_list: The ``ast.arguments`` arguments list.
|
||||||
:type ast_arguments_list: ast.arguments
|
:type ast_arguments_list: ast.arguments
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def __init__(self, ast_arguments_list: ast.arguments) -> None:
|
def __init__(self, ast_arguments_list: ast.arguments) -> None:
|
||||||
self.ast_arguments_list = ast_arguments_list
|
self.ast_arguments_list = ast_arguments_list
|
||||||
|
|
||||||
def to_argument_list(self) -> list[PythonFunctionArgument]:
|
def to_argument_list(self) -> list[PythonFunctionArgument]:
|
||||||
'''
|
"""
|
||||||
Converts the AST arguments list to a list of Python function
|
Converts the AST arguments list to a list of Python function
|
||||||
argument objects.
|
argument objects.
|
||||||
|
|
||||||
:return: The list of Python function argument objects.
|
:return: The list of Python function argument objects.
|
||||||
:rtype: list[PythonFunctionArgument]
|
:rtype: list[PythonFunctionArgument]
|
||||||
'''
|
"""
|
||||||
|
|
||||||
defaults = [None for _ in range(len(
|
defaults = (
|
||||||
self.ast_arguments_list.posonlyargs +
|
[
|
||||||
self.ast_arguments_list.args +
|
None
|
||||||
self.ast_arguments_list.kwonlyargs
|
for _ in range(
|
||||||
) - len(self.ast_arguments_list.defaults) - len(self.ast_arguments_list.kw_defaults))] + \
|
len(
|
||||||
[ast.unparse(d) for d in self.ast_arguments_list.defaults] + \
|
self.ast_arguments_list.posonlyargs
|
||||||
[ast.unparse(d) if d is not None else None for d in self.ast_arguments_list.kw_defaults]
|
+ 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
|
i = 0
|
||||||
arguments = []
|
arguments = []
|
||||||
for arg in self.ast_arguments_list.posonlyargs:
|
for arg in self.ast_arguments_list.posonlyargs:
|
||||||
if arg.annotation is None:
|
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:
|
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
|
i += 1
|
||||||
for arg in self.ast_arguments_list.args:
|
for arg in self.ast_arguments_list.args:
|
||||||
if arg.annotation is None:
|
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:
|
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
|
i += 1
|
||||||
if self.ast_arguments_list.vararg is not None:
|
if self.ast_arguments_list.vararg is not None:
|
||||||
if self.ast_arguments_list.vararg.annotation is 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:
|
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:
|
for arg in self.ast_arguments_list.kwonlyargs:
|
||||||
if arg.annotation is None:
|
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:
|
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
|
i += 1
|
||||||
if self.ast_arguments_list.kwarg is not None:
|
if self.ast_arguments_list.kwarg is not None:
|
||||||
if self.ast_arguments_list.kwarg.annotation is 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:
|
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
|
return arguments
|
||||||
@@ -13,55 +13,66 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from typing import Union
|
|
||||||
import ast
|
import ast
|
||||||
from .arguments import PythonFunctionArgument, PythonASTArgumentsListParser
|
|
||||||
from .docstrings import PythonDocstring
|
|
||||||
import keyword
|
import keyword
|
||||||
|
import types
|
||||||
|
|
||||||
from ...exceptions import InvalidPythonIdentifierError
|
from ...exceptions import InvalidPythonIdentifierError
|
||||||
from ...utils import assert_that_is_instance
|
from ...utils import assert_that_is_instance
|
||||||
import types
|
from .arguments import PythonASTArgumentsListParser, PythonFunctionArgument
|
||||||
|
from .docstrings import PythonDocstring
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'PythonDefinition',
|
'PythonDefinition',
|
||||||
'PythonFunctionDefinition',
|
'PythonFunctionDefinition',
|
||||||
'PythonAsyncFunctionDefinition',
|
'PythonAsyncFunctionDefinition',
|
||||||
'PythonClassDefinition'
|
'PythonClassDefinition',
|
||||||
]
|
]
|
||||||
|
|
||||||
def _python_docstring(doc: Union[str, None]) -> Union[PythonDocstring, None]:
|
|
||||||
'''
|
def _python_docstring(doc: str | None) -> PythonDocstring | None:
|
||||||
|
"""
|
||||||
Returns the PythonDocstring object if the docstring is a string and
|
Returns the PythonDocstring object if the docstring is a string and
|
||||||
not ``None``.
|
not ``None``.
|
||||||
|
|
||||||
:param doc: The docstring.
|
:param doc: The docstring.
|
||||||
:type doc: Union[str, None]
|
:type doc: str | None
|
||||||
|
|
||||||
:return: The PythonDocstring object or ``None``.
|
:return: The PythonDocstring object or ``None``.
|
||||||
:rtype: Union[PythonDocstring, None]
|
:rtype: PythonDocstring | None
|
||||||
'''
|
"""
|
||||||
|
|
||||||
return PythonDocstring(doc) if doc is not None else None
|
return PythonDocstring(doc) if doc is not None else None
|
||||||
|
|
||||||
|
|
||||||
class PythonDefinition:
|
class PythonDefinition:
|
||||||
'''
|
"""
|
||||||
A base class for Python definition (a class, function or asynchronous
|
A base class for Python definition (a class, function or asynchronous
|
||||||
function definition) classes.
|
function definition) classes.
|
||||||
|
|
||||||
:param name: The name of the definition.
|
:param name: The name of the definition.
|
||||||
:type name: str
|
:type name: str
|
||||||
:param doc: The docstring.
|
:param doc: The docstring.
|
||||||
:type doc: Union[PythonDocstring, None]
|
:type doc: PythonDocstring | None
|
||||||
:param decorators: The definition decorators.
|
:param decorators: The definition decorators.
|
||||||
:type decorators: list[str]
|
:type decorators: list[str]
|
||||||
|
|
||||||
:raises InvalidPythonIdentifierError: If the name is not a valid
|
:raises InvalidPythonIdentifierError: If the name is not a valid
|
||||||
Python identifier.
|
Python identifier.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def __init__(self, name: str, doc: Union[PythonDocstring, None], decorators: list[str]) -> None:
|
def __init__(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
doc: PythonDocstring | None,
|
||||||
|
decorators: list[str],
|
||||||
|
) -> None:
|
||||||
if keyword.iskeyword(name) or not name.isidentifier() or not name:
|
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))
|
assert_that_is_instance(doc, (PythonDocstring, types.NoneType))
|
||||||
|
|
||||||
@@ -73,7 +84,7 @@ class PythonDefinition:
|
|||||||
return (
|
return (
|
||||||
self.name,
|
self.name,
|
||||||
self.doc,
|
self.doc,
|
||||||
self.decorators
|
self.decorators,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
@@ -81,17 +92,17 @@ class PythonDefinition:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_node(cls, node: ast.stmt) -> PythonDefinition:
|
def from_node(cls, node: ast.stmt) -> PythonDefinition:
|
||||||
'''
|
"""
|
||||||
From an AST node.
|
From an AST node.
|
||||||
|
|
||||||
:param node: The AST node.
|
:param node: The AST node.
|
||||||
:type node: ast.stmt
|
:type node: ast.stmt
|
||||||
'''
|
"""
|
||||||
|
|
||||||
return cls(
|
return cls(
|
||||||
node.name,
|
node.name,
|
||||||
_python_docstring(ast.get_docstring(node)),
|
_python_docstring(ast.get_docstring(node)),
|
||||||
[ast.unparse(d) for d in node.decorator_list]
|
[ast.unparse(d) for d in node.decorator_list],
|
||||||
)
|
)
|
||||||
|
|
||||||
def __eq__(self, value: object) -> bool:
|
def __eq__(self, value: object) -> bool:
|
||||||
@@ -99,8 +110,9 @@ class PythonDefinition:
|
|||||||
return False
|
return False
|
||||||
return self._arg_list() == value._arg_list()
|
return self._arg_list() == value._arg_list()
|
||||||
|
|
||||||
|
|
||||||
class PythonFunctionDefinition(PythonDefinition):
|
class PythonFunctionDefinition(PythonDefinition):
|
||||||
'''
|
"""
|
||||||
A PythonDefinition subclass representing a Python function
|
A PythonDefinition subclass representing a Python function
|
||||||
definition.
|
definition.
|
||||||
|
|
||||||
@@ -109,17 +121,24 @@ class PythonFunctionDefinition(PythonDefinition):
|
|||||||
:param args: The arguments.
|
:param args: The arguments.
|
||||||
:type args: list[PythonFunctionArgument]
|
:type args: list[PythonFunctionArgument]
|
||||||
:param returns: The return type of the function or class.
|
:param returns: The return type of the function or class.
|
||||||
:type returns: Union[str, None]
|
:type returns: str | None
|
||||||
:param doc: The docstring.
|
:param doc: The docstring.
|
||||||
:type doc: Union[PythonDocstring, None]
|
:type doc: PythonDocstring | None
|
||||||
:param decorators: The definition decorators.
|
:param decorators: The definition decorators.
|
||||||
:type decorators: list[str]
|
:type decorators: list[str]
|
||||||
|
|
||||||
:raises InvalidPythonIdentifierError: If the name is not a valid
|
:raises InvalidPythonIdentifierError: If the name is not a valid
|
||||||
Python identifier.
|
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: str | None,
|
||||||
|
doc: PythonDocstring | None,
|
||||||
|
decorators: list[str],
|
||||||
|
) -> None:
|
||||||
super().__init__(name, doc, decorators)
|
super().__init__(name, doc, decorators)
|
||||||
self.args = args
|
self.args = args
|
||||||
self.returns = returns
|
self.returns = returns
|
||||||
@@ -130,28 +149,29 @@ class PythonFunctionDefinition(PythonDefinition):
|
|||||||
self.args,
|
self.args,
|
||||||
self.returns,
|
self.returns,
|
||||||
self.doc,
|
self.doc,
|
||||||
self.decorators
|
self.decorators,
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_node(cls, node: ast.stmt) -> PythonFunctionDefinition:
|
def from_node(cls, node: ast.stmt) -> PythonFunctionDefinition:
|
||||||
'''
|
"""
|
||||||
From an AST node.
|
From an AST node.
|
||||||
|
|
||||||
:param node: The AST node.
|
:param node: The AST node.
|
||||||
:type node: ast.stmt
|
:type node: ast.stmt
|
||||||
'''
|
"""
|
||||||
|
|
||||||
return cls(
|
return cls(
|
||||||
node.name,
|
node.name,
|
||||||
PythonASTArgumentsListParser(node.args).to_argument_list(),
|
PythonASTArgumentsListParser(node.args).to_argument_list(),
|
||||||
ast.unparse(node.returns) if node.returns is not None else None,
|
ast.unparse(node.returns) if node.returns is not None else None,
|
||||||
_python_docstring(ast.get_docstring(node)),
|
_python_docstring(ast.get_docstring(node)),
|
||||||
[ast.unparse(d) for d in node.decorator_list]
|
[ast.unparse(d) for d in node.decorator_list],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class PythonAsyncFunctionDefinition(PythonFunctionDefinition):
|
class PythonAsyncFunctionDefinition(PythonFunctionDefinition):
|
||||||
'''
|
"""
|
||||||
A PythonDefinition subclass representing an asynchronous Python function
|
A PythonDefinition subclass representing an asynchronous Python function
|
||||||
definition.
|
definition.
|
||||||
|
|
||||||
@@ -160,18 +180,19 @@ class PythonAsyncFunctionDefinition(PythonFunctionDefinition):
|
|||||||
:param args: The arguments.
|
:param args: The arguments.
|
||||||
:type args: list[PythonFunctionArgument]
|
:type args: list[PythonFunctionArgument]
|
||||||
:param returns: The return type of the function or class.
|
:param returns: The return type of the function or class.
|
||||||
:type returns: Union[str, None]
|
:type returns: str | None
|
||||||
:param doc: The docstring.
|
:param doc: The docstring.
|
||||||
:type doc: Union[PythonDocstring, None]
|
:type doc: PythonDocstring | None
|
||||||
:param decorators: The definition decorators.
|
:param decorators: The definition decorators.
|
||||||
:type decorators: list[str]
|
:type decorators: list[str]
|
||||||
|
|
||||||
:raises InvalidPythonIdentifierError: If the name is not a valid
|
:raises InvalidPythonIdentifierError: If the name is not a valid
|
||||||
Python identifier.
|
Python identifier.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
|
|
||||||
class PythonClassDefinition(PythonDefinition):
|
class PythonClassDefinition(PythonDefinition):
|
||||||
'''
|
"""
|
||||||
A PythonDefinition subclass representing a Python class definition.
|
A PythonDefinition subclass representing a Python class definition.
|
||||||
|
|
||||||
:param name: The name of the definition.
|
:param name: The name of the definition.
|
||||||
@@ -179,7 +200,7 @@ class PythonClassDefinition(PythonDefinition):
|
|||||||
:param bases: The base classes.
|
:param bases: The base classes.
|
||||||
:type bases: list[str]
|
:type bases: list[str]
|
||||||
:param doc: The docstring.
|
:param doc: The docstring.
|
||||||
:type doc: Union[PythonDocstring, None]
|
:type doc: PythonDocstring | None
|
||||||
:param decorators: The definition decorators.
|
:param decorators: The definition decorators.
|
||||||
:type decorators: list[str]
|
:type decorators: list[str]
|
||||||
:param body:
|
:param body:
|
||||||
@@ -187,9 +208,16 @@ class PythonClassDefinition(PythonDefinition):
|
|||||||
|
|
||||||
:raises InvalidPythonIdentifierError: If the name is not a valid
|
:raises InvalidPythonIdentifierError: If the name is not a valid
|
||||||
Python identifier.
|
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: PythonDocstring | None,
|
||||||
|
decorators: list[str],
|
||||||
|
body: list[PythonDefinition],
|
||||||
|
) -> None:
|
||||||
super().__init__(name, doc, decorators)
|
super().__init__(name, doc, decorators)
|
||||||
self.bases = bases
|
self.bases = bases
|
||||||
self.body = body
|
self.body = body
|
||||||
@@ -200,17 +228,17 @@ class PythonClassDefinition(PythonDefinition):
|
|||||||
self.bases,
|
self.bases,
|
||||||
self.doc,
|
self.doc,
|
||||||
self.decorators,
|
self.decorators,
|
||||||
self.body
|
self.body,
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_node(cls, node: ast.stmt) -> PythonClassDefinition:
|
def from_node(cls, node: ast.stmt) -> PythonClassDefinition:
|
||||||
'''
|
"""
|
||||||
From an AST node.
|
From an AST node.
|
||||||
|
|
||||||
:param node: The AST node.
|
:param node: The AST node.
|
||||||
:type node: ast.stmt
|
:type node: ast.stmt
|
||||||
'''
|
"""
|
||||||
|
|
||||||
return cls(
|
return cls(
|
||||||
node.name,
|
node.name,
|
||||||
@@ -220,13 +248,12 @@ class PythonClassDefinition(PythonDefinition):
|
|||||||
[
|
[
|
||||||
PythonFunctionDefinition.from_node(expr)
|
PythonFunctionDefinition.from_node(expr)
|
||||||
if isinstance(expr, ast.FunctionDef)
|
if isinstance(expr, ast.FunctionDef)
|
||||||
|
|
||||||
else PythonAsyncFunctionDefinition.from_node(expr)
|
else PythonAsyncFunctionDefinition.from_node(expr)
|
||||||
if isinstance(expr, ast.AsyncFunctionDef)
|
if isinstance(expr, ast.AsyncFunctionDef)
|
||||||
|
|
||||||
else PythonClassDefinition.from_node(expr)
|
else PythonClassDefinition.from_node(expr)
|
||||||
|
|
||||||
for expr in node.body
|
for expr in node.body
|
||||||
if isinstance(expr, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef))
|
if isinstance(
|
||||||
]
|
expr, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)
|
||||||
|
)
|
||||||
|
],
|
||||||
)
|
)
|
||||||
@@ -12,20 +12,18 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from enum import Enum
|
|
||||||
import docstring_parser
|
import docstring_parser
|
||||||
|
|
||||||
__all__ = [
|
__all__ = ['PythonDocstring']
|
||||||
'PythonDocstring'
|
|
||||||
]
|
|
||||||
|
|
||||||
class PythonDocstring:
|
class PythonDocstring:
|
||||||
'''
|
"""
|
||||||
Represents a Python docstring.
|
Represents a Python docstring.
|
||||||
|
|
||||||
:param docstring: The docstring as a string.
|
:param docstring: The docstring as a string.
|
||||||
:type docstring: str
|
:type docstring: str
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def __init__(self, docstring: str) -> None:
|
def __init__(self, docstring: str) -> None:
|
||||||
self.docstring = docstring
|
self.docstring = docstring
|
||||||
@@ -39,11 +37,11 @@ class PythonDocstring:
|
|||||||
return self.docstring == value.docstring
|
return self.docstring == value.docstring
|
||||||
|
|
||||||
def parse(self) -> docstring_parser.Docstring:
|
def parse(self) -> docstring_parser.Docstring:
|
||||||
'''
|
"""
|
||||||
Parses the docstring.
|
Parses the docstring.
|
||||||
|
|
||||||
:return: The parsed docstring.
|
:return: The parsed docstring.
|
||||||
:rtype: docstring_parser.Docstring
|
:rtype: docstring_parser.Docstring
|
||||||
'''
|
"""
|
||||||
|
|
||||||
return docstring_parser.parse(self.docstring)
|
return docstring_parser.parse(self.docstring)
|
||||||
@@ -13,55 +13,78 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from ...exceptions import InvalidNamespaceError, NamespaceNotFoundError, NamespaceExistsError
|
|
||||||
|
from typing import TypeAlias, Union
|
||||||
|
|
||||||
|
from ...exceptions import (
|
||||||
|
InvalidNamespaceError,
|
||||||
|
NamespaceExistsError,
|
||||||
|
NamespaceNotFoundError,
|
||||||
|
)
|
||||||
from ...utils import assert_that_is_instance
|
from ...utils import assert_that_is_instance
|
||||||
from typing import Union, TypeAlias, Dict, List
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'PythonNamespace',
|
'PythonNamespace',
|
||||||
'PythonPackageNamespace',
|
'PythonPackageNamespace',
|
||||||
'PythonModuleNamespace'
|
'PythonModuleNamespace',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
'''
|
"""
|
||||||
|
|
||||||
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 name.strip():
|
||||||
raise InvalidNamespaceError('invalid namespace', namespace_identifier = name)
|
raise InvalidNamespaceError(
|
||||||
|
'invalid namespace',
|
||||||
|
namespace_identifier=name,
|
||||||
|
)
|
||||||
|
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f'{type(self).__name__}({self.name!r})'
|
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):
|
class PythonPackageNamespace(PythonNamespace):
|
||||||
'''
|
"""
|
||||||
A subclass of ``PythonNamespace`` for Python package namespaces.
|
A subclass of ``PythonNamespace`` for Python package namespaces.
|
||||||
|
|
||||||
:param name: The name of the namespace.
|
:param name: The name of the namespace.
|
||||||
: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]
|
||||||
'''
|
"""
|
||||||
|
|
||||||
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)
|
assert_that_is_instance(sub_namespaces, list)
|
||||||
|
|
||||||
super().__init__(name)
|
super().__init__(name)
|
||||||
|
|
||||||
self._sub_namespaces = sub_namespaces
|
self._sub_namespaces = sub_namespaces
|
||||||
|
|
||||||
def namespace(self, sub_namespaces: List[str]) -> PythonNamespace:
|
def namespace(self, sub_namespaces: list[str]) -> PythonNamespace:
|
||||||
'''
|
"""
|
||||||
Returns the namespace object with a specific identifier, such as
|
Returns the namespace object with a specific identifier, such as
|
||||||
``['package', 'subpackage', 'module']``.
|
``['package', 'subpackage', 'module']``.
|
||||||
|
|
||||||
@@ -74,7 +97,7 @@ class PythonPackageNamespace(PythonNamespace):
|
|||||||
|
|
||||||
:return: The namespace.
|
:return: The namespace.
|
||||||
:rtype: PythonNamespace
|
:rtype: PythonNamespace
|
||||||
'''
|
"""
|
||||||
|
|
||||||
if not sub_namespaces:
|
if not sub_namespaces:
|
||||||
raise InvalidNamespaceError('invalid namespace')
|
raise InvalidNamespaceError('invalid namespace')
|
||||||
@@ -94,8 +117,11 @@ class PythonPackageNamespace(PythonNamespace):
|
|||||||
else:
|
else:
|
||||||
return sub_namespace
|
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
|
Returns the names of all sub-namespaces of the specified package
|
||||||
namespace and keeps the package structure.
|
namespace and keeps the package structure.
|
||||||
|
|
||||||
@@ -104,21 +130,25 @@ class PythonPackageNamespace(PythonNamespace):
|
|||||||
|
|
||||||
:return: The names if all sub-namespaces.
|
:return: The names if all sub-namespaces.
|
||||||
:rtype: PythonPackageNamespaceDictType
|
:rtype: PythonPackageNamespaceDictType
|
||||||
'''
|
"""
|
||||||
|
|
||||||
return {
|
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
|
for sn in package._sub_namespaces
|
||||||
}
|
}
|
||||||
|
|
||||||
def sub_namespace_names(self) -> PythonPackageNamespaceDictType:
|
def sub_namespace_names(self) -> PythonPackageNamespaceDictType:
|
||||||
'''
|
"""
|
||||||
Returns the names of all sub-namespaces and keeps the package
|
Returns the names of all sub-namespaces and keeps the package
|
||||||
structure.
|
structure.
|
||||||
|
|
||||||
:return: The names if all sub-namespaces.
|
:return: The names if all sub-namespaces.
|
||||||
:rtype: PythonPackageNamespaceDictType
|
:rtype: PythonPackageNamespaceDictType
|
||||||
'''
|
"""
|
||||||
|
|
||||||
return self._sub_namespaces_names(self)
|
return self._sub_namespaces_names(self)
|
||||||
|
|
||||||
@@ -135,7 +165,7 @@ class PythonPackageNamespace(PythonNamespace):
|
|||||||
return type(self).__name__ + repr((self.name, self._sub_namespaces))
|
return type(self).__name__ + repr((self.name, self._sub_namespaces))
|
||||||
|
|
||||||
def __getitem__(self, name: str) -> PythonNamespace:
|
def __getitem__(self, name: str) -> PythonNamespace:
|
||||||
'''
|
"""
|
||||||
Returns a namespace with the specified name.
|
Returns a namespace with the specified name.
|
||||||
|
|
||||||
:param name: The name of the namespace
|
:param name: The name of the namespace
|
||||||
@@ -145,16 +175,19 @@ class PythonPackageNamespace(PythonNamespace):
|
|||||||
|
|
||||||
:return: The namespace
|
:return: The namespace
|
||||||
:rtype: PythonNamespace
|
:rtype: PythonNamespace
|
||||||
'''
|
"""
|
||||||
|
|
||||||
for sub in self._sub_namespaces:
|
for sub in self._sub_namespaces:
|
||||||
if sub.name == name:
|
if sub.name == name:
|
||||||
return sub
|
return sub
|
||||||
|
|
||||||
raise NamespaceNotFoundError('no such namespace', namespace_identifier = name)
|
raise NamespaceNotFoundError(
|
||||||
|
'no such namespace',
|
||||||
|
namespace_identifier=name,
|
||||||
|
)
|
||||||
|
|
||||||
def add(self, namespace: PythonNamespace) -> None:
|
def add(self, namespace: PythonNamespace) -> None:
|
||||||
'''
|
"""
|
||||||
Adds a namespace.
|
Adds a namespace.
|
||||||
|
|
||||||
:param namespace: The namespace to add.
|
:param namespace: The namespace to add.
|
||||||
@@ -163,24 +196,28 @@ class PythonPackageNamespace(PythonNamespace):
|
|||||||
:raises NamespaceExistsError: If a namespace with the name of the
|
:raises NamespaceExistsError: If a namespace with the name of the
|
||||||
namespace that is attempted to add
|
namespace that is attempted to add
|
||||||
already exists.
|
already exists.
|
||||||
'''
|
"""
|
||||||
try:
|
try:
|
||||||
self.__getitem__(namespace.name)
|
self.__getitem__(namespace.name)
|
||||||
raise NamespaceExistsError('namespace already exists', namespace_identifier = namespace.name)
|
raise NamespaceExistsError(
|
||||||
|
'namespace already exists',
|
||||||
|
namespace_identifier=namespace.name,
|
||||||
|
)
|
||||||
except NamespaceNotFoundError:
|
except NamespaceNotFoundError:
|
||||||
self._sub_namespaces.append(namespace)
|
self._sub_namespaces.append(namespace)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def sub_namespaces(self) -> List[PythonNamespace]:
|
def sub_namespaces(self) -> list[PythonNamespace]:
|
||||||
return self._sub_namespaces
|
return self._sub_namespaces
|
||||||
|
|
||||||
|
|
||||||
class PythonModuleNamespace(PythonNamespace):
|
class PythonModuleNamespace(PythonNamespace):
|
||||||
'''
|
"""
|
||||||
A subclass of ``PythonNamespace`` for Python module namespaces.
|
A subclass of ``PythonNamespace`` for Python module namespaces.
|
||||||
|
|
||||||
:param name: The name of the namespace.
|
:param name: The name of the namespace.
|
||||||
:type name: str
|
:type name: str
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def __init__(self, name: str) -> None:
|
def __init__(self, name: str) -> None:
|
||||||
super().__init__(name)
|
super().__init__(name)
|
||||||
|
|||||||
@@ -12,10 +12,12 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
class NamespaceError(ValueError):
|
class NamespaceError(ValueError):
|
||||||
'''
|
"""
|
||||||
Base class for namespace errors.
|
Base class for namespace errors.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def __init__(self, *args: object, namespace_identifier: str = '') -> None:
|
def __init__(self, *args: object, namespace_identifier: str = '') -> None:
|
||||||
super().__init__(*args)
|
super().__init__(*args)
|
||||||
self.namespace_identifier = namespace_identifier
|
self.namespace_identifier = namespace_identifier
|
||||||
@@ -24,16 +26,25 @@ class NamespaceError(ValueError):
|
|||||||
if not self.args:
|
if not self.args:
|
||||||
return ''
|
return ''
|
||||||
else:
|
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 InvalidNamespaceError(NamespaceError): ...
|
||||||
|
|
||||||
|
|
||||||
class NamespaceNotFoundError(NamespaceError): ...
|
class NamespaceNotFoundError(NamespaceError): ...
|
||||||
|
|
||||||
|
|
||||||
class NamespaceExistsError(NamespaceError): ...
|
class NamespaceExistsError(NamespaceError): ...
|
||||||
|
|
||||||
|
|
||||||
class PythonIdentifierError(ValueError):
|
class PythonIdentifierError(ValueError):
|
||||||
'''
|
"""
|
||||||
Base class for Python identifier errors.
|
Base class for Python identifier errors.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def __init__(self, *args: object, identifier: str = '') -> None:
|
def __init__(self, *args: object, identifier: str = '') -> None:
|
||||||
super().__init__(*args)
|
super().__init__(*args)
|
||||||
self.identifier = identifier
|
self.identifier = identifier
|
||||||
@@ -42,14 +53,19 @@ class PythonIdentifierError(ValueError):
|
|||||||
if not self.args:
|
if not self.args:
|
||||||
return ''
|
return ''
|
||||||
else:
|
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): ...
|
class InvalidPythonIdentifierError(PythonIdentifierError): ...
|
||||||
|
|
||||||
|
|
||||||
class PythonAnnotationError(ValueError):
|
class PythonAnnotationError(ValueError):
|
||||||
'''
|
"""
|
||||||
Base class for Python annotation errors.
|
Base class for Python annotation errors.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def __init__(self, *args: object, annotation: str = '') -> None:
|
def __init__(self, *args: object, annotation: str = '') -> None:
|
||||||
super().__init__(*args)
|
super().__init__(*args)
|
||||||
self.annotation = annotation
|
self.annotation = annotation
|
||||||
@@ -58,14 +74,19 @@ class PythonAnnotationError(ValueError):
|
|||||||
if not self.args:
|
if not self.args:
|
||||||
return ''
|
return ''
|
||||||
else:
|
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): ...
|
class InvalidPythonAnnotationError(PythonAnnotationError): ...
|
||||||
|
|
||||||
|
|
||||||
class PythonDefinitionError(ValueError):
|
class PythonDefinitionError(ValueError):
|
||||||
'''
|
"""
|
||||||
Base class for Python definition errors.
|
Base class for Python definition errors.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def __init__(self, *args: object, definition: str = '') -> None:
|
def __init__(self, *args: object, definition: str = '') -> None:
|
||||||
super().__init__(*args)
|
super().__init__(*args)
|
||||||
self.definition = definition
|
self.definition = definition
|
||||||
@@ -74,6 +95,9 @@ class PythonDefinitionError(ValueError):
|
|||||||
if not self.args:
|
if not self.args:
|
||||||
return ''
|
return ''
|
||||||
else:
|
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): ...
|
class PythonArgumentStructureError(PythonDefinitionError): ...
|
||||||
+94
-38
@@ -12,48 +12,68 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
'''
|
"""
|
||||||
The utilities for jcloud_docsgen
|
The utilities for jcloud_docsgen
|
||||||
'''
|
"""
|
||||||
|
|
||||||
import pathlib
|
|
||||||
import os
|
|
||||||
import errno
|
import errno
|
||||||
from typing import Union
|
import os
|
||||||
|
import pathlib
|
||||||
import types
|
import types
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
try:
|
||||||
|
from warnings import deprecated
|
||||||
|
except ImportError:
|
||||||
|
from typing_extensions import deprecated
|
||||||
|
|
||||||
|
|
||||||
|
@deprecated('Use pathlib.Path instead.')
|
||||||
class ExistingDirectory(pathlib.Path):
|
class ExistingDirectory(pathlib.Path):
|
||||||
'''
|
"""
|
||||||
pathlib.Path subclass that is a directory.
|
pathlib.Path subclass that is a directory.
|
||||||
|
|
||||||
ExistingDirectory represents a filesystem path but it also checks
|
ExistingDirectory represents a filesystem path but it also checks
|
||||||
whether the path exists and is not a file but a directory. It
|
whether the path exists and is not a file but a directory. It
|
||||||
inherits from pathlib.Path.
|
inherits from pathlib.Path.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def __init__(self, path, *args, **kwargs) -> None:
|
def __init__(self, path, *args, **kwargs) -> None:
|
||||||
if not os.path.exists(path):
|
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):
|
if not os.path.isdir(path):
|
||||||
raise NotADirectoryError(errno.ENOTDIR, 'not a directory', path)
|
raise NotADirectoryError(errno.ENOTDIR, 'not a directory', path)
|
||||||
super().__init__(*(path, *args), **kwargs)
|
super().__init__(*(path, *args), **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@deprecated('Use pathlib.Path instead.')
|
||||||
class ExistingFile(pathlib.Path):
|
class ExistingFile(pathlib.Path):
|
||||||
'''
|
"""
|
||||||
pathlib.Path subclass that is a file.
|
pathlib.Path subclass that is a file.
|
||||||
|
|
||||||
ExistingFile represents a filesystem path but it also checks whether
|
ExistingFile represents a filesystem path but it also checks whether
|
||||||
the path exists and is not a directory but a file. It inherits from
|
the path exists and is not a directory but a file. It inherits from
|
||||||
pathlib.Path.
|
pathlib.Path.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def __init__(self, path, *args, **kwargs) -> None:
|
def __init__(self, path, *args, **kwargs) -> None:
|
||||||
if not os.path.exists(path):
|
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):
|
if not os.path.isfile(path):
|
||||||
raise IsADirectoryError(errno.EISDIR, 'is a directory', path)
|
raise IsADirectoryError(errno.EISDIR, 'is a directory', path)
|
||||||
super().__init__(*(path, *args), **kwargs)
|
super().__init__(*(path, *args), **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def _quote(string: str, quotation_mark: str) -> str:
|
def _quote(string: str, quotation_mark: str) -> str:
|
||||||
'''
|
"""
|
||||||
Quotes a string.
|
Quotes a string.
|
||||||
|
|
||||||
:param string: The string to quote
|
:param string: The string to quote
|
||||||
@@ -63,12 +83,17 @@ def _quote(string: str, quotation_mark: str) -> str:
|
|||||||
|
|
||||||
:return: The quoted string
|
:return: The quoted string
|
||||||
:rtype: str
|
:rtype: str
|
||||||
'''
|
"""
|
||||||
|
|
||||||
return quotation_mark + string + quotation_mark
|
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.
|
Generates a human-readable list from a list.
|
||||||
|
|
||||||
:param ls: The list.
|
:param ls: The list.
|
||||||
@@ -82,7 +107,7 @@ def human_readable_list(ls: list, final_separator: str = 'and', quotation_mark:
|
|||||||
|
|
||||||
:return: The human-readable list.
|
:return: The human-readable list.
|
||||||
:rtype: str
|
:rtype: str
|
||||||
'''
|
"""
|
||||||
|
|
||||||
# empty list
|
# empty list
|
||||||
if not ls:
|
if not ls:
|
||||||
@@ -92,15 +117,26 @@ def human_readable_list(ls: list, final_separator: str = 'and', quotation_mark:
|
|||||||
if len(ls) == 1:
|
if len(ls) == 1:
|
||||||
return _quote(str(ls[0]), quotation_mark)
|
return _quote(str(ls[0]), quotation_mark)
|
||||||
|
|
||||||
return ', '.join(
|
return (
|
||||||
|
', '.join(
|
||||||
[
|
[
|
||||||
_quote(str(obj), quotation_mark) # quote the string representation of the object
|
_quote(
|
||||||
for obj in ls[:-1] # do not include the last element of the list
|
str(obj), quotation_mark
|
||||||
]
|
) # quote the string representation of the object
|
||||||
) + ' ' + final_separator + ' ' + _quote(str(ls[-1]), quotation_mark)
|
for obj in ls[
|
||||||
|
:-1
|
||||||
|
] # do not include the last element of the list
|
||||||
|
],
|
||||||
|
)
|
||||||
|
+ ' '
|
||||||
|
+ final_separator
|
||||||
|
+ ' '
|
||||||
|
+ _quote(str(ls[-1]), quotation_mark)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _list_type_names(types: list[type]) -> list[str]:
|
def _list_type_names(types: list[type]) -> list[str]:
|
||||||
'''
|
"""
|
||||||
Converts a list of types into a list of their names (``__name__``
|
Converts a list of types into a list of their names (``__name__``
|
||||||
attribute)
|
attribute)
|
||||||
|
|
||||||
@@ -109,13 +145,20 @@ def _list_type_names(types: list[type]) -> list[str]:
|
|||||||
|
|
||||||
:return: The list of the names of the types
|
:return: The list of the names of the types
|
||||||
:rtype: list[str]
|
:rtype: list[str]
|
||||||
'''
|
"""
|
||||||
|
|
||||||
return [tp.__name__ for tp in types]
|
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: type | types.UnionType | tuple[type, ...],
|
||||||
|
) -> None:
|
||||||
if not isinstance(class_or_tuple, Union[type, types.UnionType, tuple]):
|
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 not isinstance(obj, class_or_tuple):
|
||||||
if isinstance(class_or_tuple, (tuple, types.UnionType)):
|
if isinstance(class_or_tuple, (tuple, types.UnionType)):
|
||||||
if isinstance(class_or_tuple, types.UnionType):
|
if isinstance(class_or_tuple, types.UnionType):
|
||||||
@@ -124,13 +167,22 @@ def assert_that_is_instance(obj: object, class_or_tuple: Union[type, types.Union
|
|||||||
exception_message_expected = 'either '
|
exception_message_expected = 'either '
|
||||||
else:
|
else:
|
||||||
exception_message_expected = ''
|
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:
|
else:
|
||||||
exception_message_expected = '\'' + class_or_tuple.__name__ + '\''
|
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]:
|
|
||||||
'''
|
def non_empty_str(value: str | None) -> str | None:
|
||||||
|
"""
|
||||||
Returns the value or ``None``.
|
Returns the value or ``None``.
|
||||||
|
|
||||||
Returns the value if it is not empty and not `Ǹone``; otherwise,
|
Returns the value if it is not empty and not `Ǹone``; otherwise,
|
||||||
@@ -139,11 +191,11 @@ def non_empty_str(value: Union[str, None]) -> Union[str, None]:
|
|||||||
of spaces, it is also considered empty.
|
of spaces, it is also considered empty.
|
||||||
|
|
||||||
:param value: The value.
|
:param value: The value.
|
||||||
:type value: Union[str, None]
|
:type value: str | None
|
||||||
|
|
||||||
:return: The value or ``None``.
|
:return: The value or ``None``.
|
||||||
:rtype: Union[str, None]
|
:rtype: str | None
|
||||||
'''
|
"""
|
||||||
|
|
||||||
if value is None:
|
if value is None:
|
||||||
return None
|
return None
|
||||||
@@ -153,8 +205,12 @@ def non_empty_str(value: Union[str, None]) -> Union[str, None]:
|
|||||||
|
|
||||||
return value
|
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``.
|
Returns the path segments relative to ``root``.
|
||||||
|
|
||||||
:param path: The path.
|
:param path: The path.
|
||||||
@@ -164,12 +220,12 @@ def get_relative_path_segments(path: pathlib.Path, root: pathlib.Path) -> list[s
|
|||||||
|
|
||||||
:return: The path segments relative to ``root``.
|
:return: The path segments relative to ``root``.
|
||||||
:rtype: list[str]
|
:rtype: list[str]
|
||||||
'''
|
"""
|
||||||
|
|
||||||
return list(
|
return list(
|
||||||
path.resolve()
|
path.resolve()
|
||||||
.relative_to(
|
.relative_to(
|
||||||
root.resolve()
|
root.resolve(),
|
||||||
)
|
)
|
||||||
.parts
|
.parts,
|
||||||
)
|
)
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# 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 subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def test_cli():
|
||||||
|
result = subprocess.run(
|
||||||
|
[
|
||||||
|
sys.executable,
|
||||||
|
'-m',
|
||||||
|
'jcloud_docsgen',
|
||||||
|
'--help',
|
||||||
|
],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
stdout = result.stdout.lower()
|
||||||
|
assert (
|
||||||
|
'usage:' in stdout
|
||||||
|
and 'positional arguments' in stdout
|
||||||
|
and 'options' in stdout
|
||||||
|
and '--help' in stdout
|
||||||
|
)
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Module `pkg.module`
|
||||||
|
|
||||||
|
## Function `f`
|
||||||
|
|
||||||
|
Does something.
|
||||||
|
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
| Parameter | Type | Kind | Default value | Description |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| `a` | `int` | normal | `42` | A parameter. |
|
||||||
|
|
||||||
|
<details><summary><h3 style="display:inline">Docstring</h3></summary>Does something.
|
||||||
|
|
||||||
|
:param a: A parameter.
|
||||||
|
:type a: int
|
||||||
|
|
||||||
|
:return: A string.
|
||||||
|
:rtype: str</details>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
def f(a: int = 42) -> str:
|
||||||
|
"""
|
||||||
|
Does something.
|
||||||
|
|
||||||
|
:param a: A parameter.
|
||||||
|
:type a: int
|
||||||
|
|
||||||
|
:return: A string.
|
||||||
|
:rtype: str
|
||||||
|
"""
|
||||||
|
...
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# 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 jcloud_docsgen.cli.cli import create_argument_parser
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'lang',
|
||||||
|
[
|
||||||
|
'javascript',
|
||||||
|
'Python',
|
||||||
|
'PYTHON',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_language_error(lang):
|
||||||
|
parser = create_argument_parser()
|
||||||
|
|
||||||
|
with pytest.raises(SystemExit):
|
||||||
|
parser.parse_args([lang])
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'lang',
|
||||||
|
[
|
||||||
|
'python',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_language_success(lang):
|
||||||
|
parser = create_argument_parser()
|
||||||
|
parser.parse_args([lang])
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
# 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 pathlib
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from jcloud_docsgen.cli.cli import create_argument_parser
|
||||||
|
from jcloud_docsgen.cli.cli import main as cli_main
|
||||||
|
from jcloud_docsgen.cli.languages.python import parse_sections_list
|
||||||
|
from jcloud_docsgen.core.python import (
|
||||||
|
PythonDefinitionDocumentationIncludeSections,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'include,exclude,expected',
|
||||||
|
[
|
||||||
|
(
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
PythonDefinitionDocumentationIncludeSections(
|
||||||
|
signature=False,
|
||||||
|
returns=False,
|
||||||
|
params=False,
|
||||||
|
exceptions=False,
|
||||||
|
examples=False,
|
||||||
|
docstring=False,
|
||||||
|
bases=False,
|
||||||
|
decorators=False,
|
||||||
|
class_body=False,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[],
|
||||||
|
['signature'],
|
||||||
|
PythonDefinitionDocumentationIncludeSections(
|
||||||
|
signature=False,
|
||||||
|
returns=False,
|
||||||
|
params=False,
|
||||||
|
exceptions=False,
|
||||||
|
examples=False,
|
||||||
|
docstring=False,
|
||||||
|
bases=False,
|
||||||
|
decorators=False,
|
||||||
|
class_body=False,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
['signature'],
|
||||||
|
['signature'],
|
||||||
|
PythonDefinitionDocumentationIncludeSections(
|
||||||
|
signature=False,
|
||||||
|
returns=False,
|
||||||
|
params=False,
|
||||||
|
exceptions=False,
|
||||||
|
examples=False,
|
||||||
|
docstring=False,
|
||||||
|
bases=False,
|
||||||
|
decorators=False,
|
||||||
|
class_body=False,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
['signature'],
|
||||||
|
[],
|
||||||
|
PythonDefinitionDocumentationIncludeSections(
|
||||||
|
signature=True,
|
||||||
|
returns=False,
|
||||||
|
params=False,
|
||||||
|
exceptions=False,
|
||||||
|
examples=False,
|
||||||
|
docstring=False,
|
||||||
|
bases=False,
|
||||||
|
decorators=False,
|
||||||
|
class_body=False,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
PythonDefinitionDocumentationIncludeSections(),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
['signature', 'exceptions', 'bases', 'class_body'],
|
||||||
|
['signature', 'bases'],
|
||||||
|
PythonDefinitionDocumentationIncludeSections(
|
||||||
|
signature=False,
|
||||||
|
returns=False,
|
||||||
|
params=False,
|
||||||
|
exceptions=True,
|
||||||
|
examples=False,
|
||||||
|
docstring=False,
|
||||||
|
bases=False,
|
||||||
|
decorators=False,
|
||||||
|
class_body=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
None,
|
||||||
|
['params', 'docstring'],
|
||||||
|
PythonDefinitionDocumentationIncludeSections(
|
||||||
|
signature=True,
|
||||||
|
returns=True,
|
||||||
|
params=False,
|
||||||
|
exceptions=True,
|
||||||
|
examples=True,
|
||||||
|
docstring=False,
|
||||||
|
bases=True,
|
||||||
|
decorators=True,
|
||||||
|
class_body=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_parse_sections_list(include, exclude, expected):
|
||||||
|
assert parse_sections_list(include, exclude) == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_sections_error():
|
||||||
|
parser = create_argument_parser()
|
||||||
|
|
||||||
|
with pytest.raises(SystemExit):
|
||||||
|
parser.parse_args(
|
||||||
|
[
|
||||||
|
'python',
|
||||||
|
'-s',
|
||||||
|
'param', # correct: `params`
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(SystemExit):
|
||||||
|
parser.parse_args(
|
||||||
|
[
|
||||||
|
'python',
|
||||||
|
'-s',
|
||||||
|
'params',
|
||||||
|
'docstrng', # correct: `docstring`
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_sections_success():
|
||||||
|
parser = create_argument_parser()
|
||||||
|
|
||||||
|
parser.parse_args(
|
||||||
|
[
|
||||||
|
'python',
|
||||||
|
'-s',
|
||||||
|
'params',
|
||||||
|
]
|
||||||
|
)
|
||||||
|
parser.parse_args(
|
||||||
|
[
|
||||||
|
'python',
|
||||||
|
'-s',
|
||||||
|
'params',
|
||||||
|
'docstring',
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_docs_generation(expectdir):
|
||||||
|
with expectdir('python_project') as output_dir:
|
||||||
|
output_dir: pathlib.Path
|
||||||
|
input_dir = pathlib.Path(__file__).parent / 'python_project/project'
|
||||||
|
cli_main(
|
||||||
|
[
|
||||||
|
'python',
|
||||||
|
'-s',
|
||||||
|
'params',
|
||||||
|
'docstring',
|
||||||
|
'-HTo',
|
||||||
|
str(output_dir),
|
||||||
|
str(input_dir),
|
||||||
|
]
|
||||||
|
)
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -12,51 +12,135 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from src.jcloud_docsgen.core.python import PythonDocumentationGenerator
|
|
||||||
from src.jcloud_docsgen.core.python.namespaces import PythonModuleNamespace, PythonPackageNamespace
|
|
||||||
from src.jcloud_docsgen.utils import ExistingDirectory
|
|
||||||
import pytest
|
|
||||||
import pathlib
|
import pathlib
|
||||||
|
|
||||||
@pytest.mark.parametrize('project_directory,docs_directory,expected_exception,expected_exception_msg', [
|
import pytest
|
||||||
(1, 1, TypeError, 'expected \'ExistingDirectory\', got \'int\''),
|
|
||||||
(1, None, TypeError, 'expected \'ExistingDirectory\', got \'int\''),
|
|
||||||
(42, None, TypeError, 'expected \'ExistingDirectory\', got \'int\''),
|
|
||||||
(ExistingDirectory('tests'), 1, TypeError, 'expected \'ExistingDirectory\', got \'int\''),
|
|
||||||
(ExistingDirectory('tests/'), 1, TypeError, 'expected \'ExistingDirectory\', got \'int\''),
|
|
||||||
(1, ExistingDirectory('tests/'), TypeError, 'expected \'ExistingDirectory\', got \'int\''),
|
|
||||||
(1, ExistingDirectory('tests'), TypeError, 'expected \'ExistingDirectory\', got \'int\''),
|
|
||||||
(None, ExistingDirectory('tests'), TypeError, 'expected \'ExistingDirectory\', got \'NoneType\''),
|
|
||||||
])
|
|
||||||
def test_PythonDocumentationGenerator_exceptions(project_directory, docs_directory, expected_exception, expected_exception_msg):
|
|
||||||
with pytest.raises(expected_exception) as exc_info:
|
|
||||||
PythonDocumentationGenerator(project_directory, docs_directory)
|
|
||||||
assert str(exc_info.value) == expected_exception_msg
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('python_documentation_generator,expected', [
|
import tempfile
|
||||||
(PythonDocumentationGenerator(ExistingDirectory('tests/unit/core/python/_core/test_project_dirs/pdir_1'), ExistingDirectory('tests/unit/core/python/_core/test_project_dirs/pdir_1/docs')), []),
|
|
||||||
(PythonDocumentationGenerator(ExistingDirectory('tests/unit/core/python/_core/test_project_dirs/pdir_2'), ExistingDirectory('tests/unit/core/python/_core/test_project_dirs/pdir_2/docs')), [PythonPackageNamespace('pkg', [PythonModuleNamespace('module')])]),
|
|
||||||
(PythonDocumentationGenerator(ExistingDirectory('tests/unit/core/python/_core/test_project_dirs/pdir_3'), ExistingDirectory('tests/unit/core/python/_core/test_project_dirs/pdir_3/docs')), [PythonPackageNamespace('pkg', [PythonModuleNamespace('module'), PythonPackageNamespace('pkg', [PythonModuleNamespace('module2')])])]),
|
|
||||||
])
|
|
||||||
def test_PythonDocumentationGenerator_collect_modules(python_documentation_generator: PythonDocumentationGenerator, expected):
|
|
||||||
assert python_documentation_generator.namespace() == expected
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('dir', [
|
from src.jcloud_docsgen.core.python import PythonDocumentationGenerator
|
||||||
d.name
|
from src.jcloud_docsgen.core.python.namespaces import (
|
||||||
for d in pathlib.Path('tests/unit/core/python/_core/test_PythonDocumentationGenerator/test_generate_documentation/').iterdir()
|
PythonModuleNamespace,
|
||||||
])
|
PythonPackageNamespace,
|
||||||
def test_generate_documentation(dir, expectdir):
|
|
||||||
with expectdir('test_PythonDocumentationGenerator/test_generate_documentation/' + dir) as d:
|
|
||||||
PythonDocumentationGenerator(
|
|
||||||
ExistingDirectory(
|
|
||||||
str(
|
|
||||||
pathlib.Path('tests/unit/core/python/_core/test_PythonDocumentationGenerator/test_generate_documentation/') /
|
|
||||||
dir /
|
|
||||||
'project'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'python_documentation_generator,expected',
|
||||||
|
[
|
||||||
|
(
|
||||||
|
PythonDocumentationGenerator(
|
||||||
|
pathlib.Path(
|
||||||
|
'tests/unit/core/python/_core/test_project_dirs/pdir_1'
|
||||||
),
|
),
|
||||||
ExistingDirectory(str(d)),
|
pathlib.Path(
|
||||||
|
'tests/unit/core/python/_core/test_project_dirs/pdir_1/docs'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonDocumentationGenerator(
|
||||||
|
pathlib.Path(
|
||||||
|
'tests/unit/core/python/_core/test_project_dirs/pdir_2/src'
|
||||||
|
),
|
||||||
|
pathlib.Path(
|
||||||
|
'tests/unit/core/python/_core/test_project_dirs/pdir_2/docs'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
PythonPackageNamespace(
|
||||||
|
'pkg',
|
||||||
|
[PythonModuleNamespace('module')],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonDocumentationGenerator(
|
||||||
|
pathlib.Path(
|
||||||
|
'tests/unit/core/python/_core/test_project_dirs/pdir_3/src'
|
||||||
|
),
|
||||||
|
pathlib.Path(
|
||||||
|
'tests/unit/core/python/_core/test_project_dirs/pdir_3/docs'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
PythonPackageNamespace(
|
||||||
|
'pkg',
|
||||||
|
[
|
||||||
|
PythonModuleNamespace('module'),
|
||||||
|
PythonPackageNamespace(
|
||||||
|
'pkg',
|
||||||
|
[
|
||||||
|
PythonModuleNamespace('module2'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_PythonDocumentationGenerator_collect_modules(
|
||||||
|
python_documentation_generator: PythonDocumentationGenerator,
|
||||||
|
expected,
|
||||||
|
):
|
||||||
|
assert python_documentation_generator.namespace().sub_namespaces == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'dir',
|
||||||
|
[
|
||||||
|
d.name
|
||||||
|
for d in pathlib.Path(
|
||||||
|
(
|
||||||
|
'tests/unit/core/python/_core/test_PythonDocume'
|
||||||
|
'ntationGenerator/test_generate_documentation/'
|
||||||
|
),
|
||||||
|
).iterdir()
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_generate_documentation(dir, expectdir):
|
||||||
|
with expectdir(
|
||||||
|
'test_PythonDocumentationGenerator/test_generate_documentation/' + dir
|
||||||
|
) as d:
|
||||||
|
PythonDocumentationGenerator(
|
||||||
|
pathlib.Path(
|
||||||
|
str(
|
||||||
|
pathlib.Path(
|
||||||
|
(
|
||||||
|
'tests/unit/core/python/_core/test_PythonDocume'
|
||||||
|
'ntationGenerator/test_generate_documentation/'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
/ dir
|
||||||
|
/ 'project',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
pathlib.Path(str(d)),
|
||||||
allow_tables=True,
|
allow_tables=True,
|
||||||
allow_html = False
|
allow_html=False,
|
||||||
).generate_documentation(
|
).generate_documentation() # simplify the tests
|
||||||
) # simplify the tests
|
|
||||||
|
|
||||||
|
def test_creates_directory():
|
||||||
|
with tempfile.TemporaryDirectory() as output_dir:
|
||||||
|
output_dir = pathlib.Path(output_dir)
|
||||||
|
with tempfile.TemporaryDirectory() as project_dir:
|
||||||
|
project_dir = pathlib.Path(project_dir)
|
||||||
|
|
||||||
|
# The directory of the package
|
||||||
|
package_dir = project_dir / 'pkg'
|
||||||
|
assert not package_dir.exists()
|
||||||
|
package_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# The actual output directory directory
|
||||||
|
docs_dir = output_dir / 'docs' / 'reference'
|
||||||
|
# It should not exist
|
||||||
|
assert not docs_dir.exists()
|
||||||
|
|
||||||
|
docs_generator = PythonDocumentationGenerator(
|
||||||
|
project_dir, docs_dir
|
||||||
|
)
|
||||||
|
docs_generator.generate_documentation()
|
||||||
|
assert docs_dir.exists()
|
||||||
File renamed without changes.
+30
@@ -7,3 +7,33 @@
|
|||||||
```python
|
```python
|
||||||
func()
|
func()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Function `func2`
|
||||||
|
|
||||||
|
### Function signature
|
||||||
|
|
||||||
|
```python
|
||||||
|
func2(a: int, b: int = 42, c=42, d=42)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
| Parameter | Type | Kind | Default value | Description |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| `a` | `int` | normal | -- | -- |
|
||||||
|
| `b` | `int` | normal | `42` | -- |
|
||||||
|
| `c` | `int` | normal | `42` | -- |
|
||||||
|
| `d` | -- | normal | `42` | -- |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Docstring
|
||||||
|
|
||||||
|
:param c:
|
||||||
|
:type c: int
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
def func(): ...
|
||||||
|
|
||||||
|
|
||||||
|
def func2(a: int, b: int = 42, c=42, d=42):
|
||||||
|
"""
|
||||||
|
:param c:
|
||||||
|
:type c: int
|
||||||
|
"""
|
||||||
-1
@@ -1 +0,0 @@
|
|||||||
def func(): ...
|
|
||||||
+2
@@ -1,8 +1,10 @@
|
|||||||
class UserNotFoundError(Exception):
|
class UserNotFoundError(Exception):
|
||||||
"""User does not exist."""
|
"""User does not exist."""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class InvalidEmailError(Exception):
|
class InvalidEmailError(Exception):
|
||||||
"""Email address is invalid."""
|
"""Email address is invalid."""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
+1
@@ -7,6 +7,7 @@ class User:
|
|||||||
"""
|
"""
|
||||||
Represents a user.
|
Represents a user.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
id: str
|
id: str
|
||||||
name: str
|
name: str
|
||||||
email: str
|
email: str
|
||||||
+5
-6
@@ -12,18 +12,17 @@ class UserService:
|
|||||||
def __init__(self, storage: InMemoryUserStorage):
|
def __init__(self, storage: InMemoryUserStorage):
|
||||||
self.storage = storage
|
self.storage = storage
|
||||||
|
|
||||||
def create_user(self, user_id: str, name: str, email: str, age: int | None = None) -> User:
|
def create_user(
|
||||||
|
self, user_id: str, name: str, email: str, age: int | None = None
|
||||||
|
) -> User:
|
||||||
"""
|
"""
|
||||||
Creates and stores a new user.
|
Creates and stores a new user.
|
||||||
"""
|
"""
|
||||||
if not is_valid_email(email):
|
if not is_valid_email(email):
|
||||||
raise InvalidEmailError(f"Invalid email: {email}")
|
raise InvalidEmailError(f'Invalid email: {email}')
|
||||||
|
|
||||||
user = User(
|
user = User(
|
||||||
id=user_id,
|
id=user_id, name=normalize_name(name), email=email, age=age
|
||||||
name=normalize_name(name),
|
|
||||||
email=email,
|
|
||||||
age=age
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self.storage.add(user)
|
self.storage.add(user)
|
||||||
File renamed without changes.
+2
-2
@@ -5,7 +5,7 @@ def is_valid_email(email: str) -> bool:
|
|||||||
"""
|
"""
|
||||||
Checks whether an email address is valid.
|
Checks whether an email address is valid.
|
||||||
"""
|
"""
|
||||||
pattern = r"^[\w\.-]+@[\w\.-]+\.\w+$"
|
pattern = r'^[\w\.-]+@[\w\.-]+\.\w+$'
|
||||||
return re.match(pattern, email) is not None
|
return re.match(pattern, email) is not None
|
||||||
|
|
||||||
|
|
||||||
@@ -13,4 +13,4 @@ def normalize_name(name: str) -> str:
|
|||||||
"""
|
"""
|
||||||
Removes extra spaces and formats the name.
|
Removes extra spaces and formats the name.
|
||||||
"""
|
"""
|
||||||
return " ".join(name.strip().split()).title()
|
return ' '.join(name.strip().split()).title()
|
||||||
@@ -12,49 +12,265 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
from src.jcloud_docsgen.core.python import PythonModuleDocumentationGenerator
|
from src.jcloud_docsgen.core.python import PythonModuleDocumentationGenerator
|
||||||
from src.jcloud_docsgen.exceptions import InvalidNamespaceError
|
from src.jcloud_docsgen.exceptions import InvalidNamespaceError
|
||||||
import pytest
|
|
||||||
from src.jcloud_docsgen.utils import ExistingFile, ExistingDirectory
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('module_path,src_directory,expected_exception,expected_exception_msg', [
|
|
||||||
(1, 1, TypeError, 'expected \'ExistingFile\', got \'int\''),
|
|
||||||
(1, None, TypeError, 'expected \'ExistingFile\', got \'int\''),
|
|
||||||
(42, None, TypeError, 'expected \'ExistingFile\', got \'int\''),
|
|
||||||
(ExistingFile('tests/unit/utils/test_file'), 1, TypeError, 'expected either \'ExistingDirectory\' or \'NoneType\', got \'int\''),
|
|
||||||
(ExistingDirectory('tests/'), 1, TypeError, 'expected \'ExistingFile\', got \'ExistingDirectory\''),
|
|
||||||
(ExistingDirectory('tests'), 1, TypeError, 'expected \'ExistingFile\', got \'ExistingDirectory\''),
|
|
||||||
(1, ExistingDirectory('tests/'), TypeError, 'expected \'ExistingFile\', got \'int\''),
|
|
||||||
(1, ExistingDirectory('tests'), TypeError, 'expected \'ExistingFile\', got \'int\''),
|
|
||||||
(None, ExistingDirectory('tests'), TypeError, 'expected \'ExistingFile\', got \'NoneType\''),
|
|
||||||
(None, None, TypeError, 'expected \'ExistingFile\', got \'NoneType\''),
|
|
||||||
(1, None, TypeError, 'expected \'ExistingFile\', got \'int\''),
|
|
||||||
|
|
||||||
(ExistingFile('tests/unit/core/python/_core/files_with_more_than_one_dot/a.b.c'), None, InvalidNamespaceError, 'namespace identifier cannot contain more than one dot: a.b.c'),
|
@pytest.mark.parametrize(
|
||||||
(ExistingFile('tests/unit/core/python/_core/files_with_more_than_one_dot/a.b.c.d'), None, InvalidNamespaceError, 'namespace identifier cannot contain more than one dot: a.b.c.d'),
|
'module_path,src_directory,expected_exception,expected_exception_msg',
|
||||||
(ExistingFile('tests/unit/core/python/_core/files_with_more_than_one_dot/a.b.c.d.e'), None, InvalidNamespaceError, 'namespace identifier cannot contain more than one dot: a.b.c.d.e'),
|
[
|
||||||
(ExistingFile('tests/unit/core/python/_core/files_with_more_than_one_dot/a.b.c.d.e.f'), None, InvalidNamespaceError, 'namespace identifier cannot contain more than one dot: a.b.c.d.e.f'),
|
(
|
||||||
(ExistingFile('tests/unit/core/python/_core/files_with_more_than_one_dot/a.b.c.d.e.f.g'), None, InvalidNamespaceError, 'namespace identifier cannot contain more than one dot: a.b.c.d.e.f.g'),
|
pathlib.Path(
|
||||||
(ExistingFile('tests/unit/core/python/_core/files_with_more_than_one_dot/a.b.c.d.e.f.g.h'), None, InvalidNamespaceError, 'namespace identifier cannot contain more than one dot: a.b.c.d.e.f.g.h'),
|
(
|
||||||
(ExistingFile('tests/unit/core/python/_core/files_with_more_than_one_dot/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.py'),
|
'tests/unit/core/python/_core/fil'
|
||||||
(ExistingFile('tests/unit/core/python/_core/files_with_more_than_one_dot/a.b.c.d.e.f.g.py'), None, InvalidNamespaceError, 'namespace identifier cannot contain more than one dot: a.b.c.d.e.f.g.py'),
|
'es_with_more_than_one_dot/a.b.c'
|
||||||
(ExistingFile('tests/unit/core/python/_core/files_with_more_than_one_dot/a.b.c.d.e.f.py'), None, InvalidNamespaceError, 'namespace identifier cannot contain more than one dot: a.b.c.d.e.f.py'),
|
),
|
||||||
(ExistingFile('tests/unit/core/python/_core/files_with_more_than_one_dot/a.b.c.d.e.py'), None, InvalidNamespaceError, 'namespace identifier cannot contain more than one dot: a.b.c.d.e.py'),
|
),
|
||||||
(ExistingFile('tests/unit/core/python/_core/files_with_more_than_one_dot/a.b.c.d.py'), None, InvalidNamespaceError, 'namespace identifier cannot contain more than one dot: a.b.c.d.py'),
|
None,
|
||||||
(ExistingFile('tests/unit/core/python/_core/files_with_more_than_one_dot/a.b.c.py'), None, InvalidNamespaceError, 'namespace identifier cannot contain more than one dot: a.b.c.py'),
|
InvalidNamespaceError,
|
||||||
(ExistingFile('tests/unit/core/python/_core/files_with_more_than_one_dot/a.b.py'), None, InvalidNamespaceError, 'namespace identifier cannot contain more than one dot: a.b.py'),
|
'namespace identifier cannot contain more than one dot: a.b.c',
|
||||||
(ExistingFile('tests/unit/core/python/_core/directory.with.more.than.one.dot/a.b.py'), None, InvalidNamespaceError, 'namespace identifier cannot contain more than one dot: a.b.py'),
|
),
|
||||||
])
|
(
|
||||||
def test_PythonModuleDocumentationGenerator_exceptions(module_path, src_directory, expected_exception, expected_exception_msg):
|
pathlib.Path(
|
||||||
|
(
|
||||||
|
'tests/unit/core/python/_core/file'
|
||||||
|
's_with_more_than_one_dot/a.b.c.d'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
InvalidNamespaceError,
|
||||||
|
'namespace identifier cannot contain more than one dot: a.b.c.d',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
pathlib.Path(
|
||||||
|
(
|
||||||
|
'tests/unit/core/python/_core/files'
|
||||||
|
'_with_more_than_one_dot/a.b.c.d.e'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
InvalidNamespaceError,
|
||||||
|
(
|
||||||
|
'namespace identifier cannot cont'
|
||||||
|
'ain more than one dot: a.b.c.d.e'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
pathlib.Path(
|
||||||
|
(
|
||||||
|
'tests/unit/core/python/_core/files_'
|
||||||
|
'with_more_than_one_dot/a.b.c.d.e.f'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
InvalidNamespaceError,
|
||||||
|
(
|
||||||
|
'namespace identifier cannot conta'
|
||||||
|
'in more than one dot: a.b.c.d.e.f'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
pathlib.Path(
|
||||||
|
(
|
||||||
|
'tests/unit/core/python/_core/files_w'
|
||||||
|
'ith_more_than_one_dot/a.b.c.d.e.f.g'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
InvalidNamespaceError,
|
||||||
|
(
|
||||||
|
'namespace identifier cannot contai'
|
||||||
|
'n more than one dot: a.b.c.d.e.f.g'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
pathlib.Path(
|
||||||
|
(
|
||||||
|
'tests/unit/core/python/_core/files_wi'
|
||||||
|
'th_more_than_one_dot/a.b.c.d.e.f.g.h'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
InvalidNamespaceError,
|
||||||
|
(
|
||||||
|
'namespace identifier cannot contain'
|
||||||
|
' more than one dot: a.b.c.d.e.f.g.h'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
pathlib.Path(
|
||||||
|
(
|
||||||
|
'tests/unit/core/python/_core/files_wit'
|
||||||
|
'h_more_than_one_dot/a.b.c.d.e.f.g.h.py'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
InvalidNamespaceError,
|
||||||
|
(
|
||||||
|
'namespace identifier cannot contain m'
|
||||||
|
'ore than one dot: a.b.c.d.e.f.g.h.py'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
pathlib.Path(
|
||||||
|
(
|
||||||
|
'tests/unit/core/python/_core/files_wi'
|
||||||
|
'th_more_than_one_dot/a.b.c.d.e.f.g.py'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
InvalidNamespaceError,
|
||||||
|
(
|
||||||
|
'namespace identifier cannot contain '
|
||||||
|
'more than one dot: a.b.c.d.e.f.g.py'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
pathlib.Path(
|
||||||
|
(
|
||||||
|
'tests/unit/core/python/_core/files_w'
|
||||||
|
'ith_more_than_one_dot/a.b.c.d.e.f.py'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
InvalidNamespaceError,
|
||||||
|
(
|
||||||
|
'namespace identifier cannot contain'
|
||||||
|
' more than one dot: a.b.c.d.e.f.py'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
pathlib.Path(
|
||||||
|
(
|
||||||
|
'tests/unit/core/python/_core/files_'
|
||||||
|
'with_more_than_one_dot/a.b.c.d.e.py'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
InvalidNamespaceError,
|
||||||
|
(
|
||||||
|
'namespace identifier cannot contai'
|
||||||
|
'n more than one dot: a.b.c.d.e.py'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
pathlib.Path(
|
||||||
|
(
|
||||||
|
'tests/unit/core/python/_core/files'
|
||||||
|
'_with_more_than_one_dot/a.b.c.d.py'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
InvalidNamespaceError,
|
||||||
|
(
|
||||||
|
'namespace identifier cannot conta'
|
||||||
|
'in more than one dot: a.b.c.d.py'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
pathlib.Path(
|
||||||
|
(
|
||||||
|
'tests/unit/core/python/_core/file'
|
||||||
|
's_with_more_than_one_dot/a.b.c.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',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
pathlib.Path(
|
||||||
|
(
|
||||||
|
'tests/unit/core/python/_core/direc'
|
||||||
|
'tory.with.more.than.one.dot/a.b.py'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
InvalidNamespaceError,
|
||||||
|
'namespace identifier cannot contain more than one dot: a.b.py',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_PythonModuleDocumentationGenerator_exceptions(
|
||||||
|
module_path,
|
||||||
|
src_directory,
|
||||||
|
expected_exception,
|
||||||
|
expected_exception_msg,
|
||||||
|
):
|
||||||
with pytest.raises(expected_exception) as exc_info:
|
with pytest.raises(expected_exception) as exc_info:
|
||||||
PythonModuleDocumentationGenerator(module_path, src_directory)
|
PythonModuleDocumentationGenerator(module_path, src_directory)
|
||||||
assert str(exc_info.value) == expected_exception_msg
|
assert str(exc_info.value) == expected_exception_msg
|
||||||
|
|
||||||
@pytest.mark.parametrize('module_documentation_generator,expected', [
|
|
||||||
(PythonModuleDocumentationGenerator(ExistingFile('tests/unit/core/python/_core/test_project_dirs/pdir_2/src/pkg/module.py'), ExistingDirectory('tests/unit/core/python/_core/test_project_dirs/pdir_2/src/'), allow_tables = True, allow_html = False), '''# Module `pkg.module`
|
@pytest.mark.parametrize(
|
||||||
|
'module_documentation_generator,expected',
|
||||||
|
[
|
||||||
|
(
|
||||||
|
PythonModuleDocumentationGenerator(
|
||||||
|
pathlib.Path(
|
||||||
|
(
|
||||||
|
'tests/unit/core/python/_core/test_pr'
|
||||||
|
'oject_dirs/pdir_2/src/pkg/module.py'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
pathlib.Path(
|
||||||
|
'tests/unit/core/python/_core/test_project_dirs/pdir_2/src/'
|
||||||
|
),
|
||||||
|
allow_tables=True,
|
||||||
|
allow_html=False,
|
||||||
|
),
|
||||||
|
"""# Module `pkg.module`
|
||||||
|
|
||||||
A test module.
|
A test module.
|
||||||
|
|
||||||
|
## Function `fn`
|
||||||
|
|
||||||
|
### Function signature
|
||||||
|
|
||||||
|
```python
|
||||||
|
fn(a: int, b: int = 42, c=42, d=42)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
| Parameter | Type | Kind | Default value | Description |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| `a` | `int` | normal | -- | -- |
|
||||||
|
| `b` | `int` | normal | `42` | -- |
|
||||||
|
| `c` | `int` | normal | `42` | -- |
|
||||||
|
| `d` | -- | normal | `42` | -- |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Docstring
|
||||||
|
|
||||||
|
:param c:
|
||||||
|
:type c: int
|
||||||
|
|
||||||
## Function `add`
|
## Function `add`
|
||||||
|
|
||||||
Adds two numbers.
|
Adds two numbers.
|
||||||
@@ -218,12 +434,54 @@ Barks.
|
|||||||
|
|
||||||
### Docstring
|
### Docstring
|
||||||
|
|
||||||
A dog.'''),
|
A dog.""",
|
||||||
|
),
|
||||||
(PythonModuleDocumentationGenerator(ExistingFile('tests/unit/core/python/_core/test_project_dirs/pdir_2/src/pkg/module.py'), None, allow_tables = True, allow_html = False), '''# Module `module`
|
(
|
||||||
|
PythonModuleDocumentationGenerator(
|
||||||
|
pathlib.Path(
|
||||||
|
(
|
||||||
|
'tests/unit/core/python/_core/test_pr'
|
||||||
|
'oject_dirs/pdir_2/src/pkg/module.py'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
allow_tables=True,
|
||||||
|
allow_html=False,
|
||||||
|
),
|
||||||
|
"""# Module `module`
|
||||||
|
|
||||||
A test module.
|
A test module.
|
||||||
|
|
||||||
|
## Function `fn`
|
||||||
|
|
||||||
|
### Function signature
|
||||||
|
|
||||||
|
```python
|
||||||
|
fn(a: int, b: int = 42, c=42, d=42)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
| Parameter | Type | Kind | Default value | Description |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| `a` | `int` | normal | -- | -- |
|
||||||
|
| `b` | `int` | normal | `42` | -- |
|
||||||
|
| `c` | `int` | normal | `42` | -- |
|
||||||
|
| `d` | -- | normal | `42` | -- |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Docstring
|
||||||
|
|
||||||
|
:param c:
|
||||||
|
:type c: int
|
||||||
|
|
||||||
## Function `add`
|
## Function `add`
|
||||||
|
|
||||||
Adds two numbers.
|
Adds two numbers.
|
||||||
@@ -387,12 +645,54 @@ Barks.
|
|||||||
|
|
||||||
### Docstring
|
### Docstring
|
||||||
|
|
||||||
A dog.'''),
|
A dog.""",
|
||||||
|
),
|
||||||
(PythonModuleDocumentationGenerator(ExistingFile('tests/unit/core/python/_core/test_project_dirs/pdir_2/src/pkg/module.py'), None, allow_tables = True, allow_html = True), '''# Module `module`
|
(
|
||||||
|
PythonModuleDocumentationGenerator(
|
||||||
|
pathlib.Path(
|
||||||
|
(
|
||||||
|
'tests/unit/core/python/_core/test_pr'
|
||||||
|
'oject_dirs/pdir_2/src/pkg/module.py'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
allow_tables=True,
|
||||||
|
allow_html=True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"""# Module `module`
|
||||||
|
|
||||||
A test module.
|
A test module.
|
||||||
|
|
||||||
|
## Function `fn`
|
||||||
|
|
||||||
|
### Function signature
|
||||||
|
|
||||||
|
```python
|
||||||
|
fn(a: int, b: int = 42, c=42, d=42)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
| Parameter | Type | Kind | Default value | Description |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| `a` | `int` | normal | -- | -- |
|
||||||
|
| `b` | `int` | normal | `42` | -- |
|
||||||
|
| `c` | `int` | normal | `42` | -- |
|
||||||
|
| `d` | -- | normal | `42` | -- |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<details><summary><h3 style="display:inline">Docstring</h3></summary>"""
|
||||||
|
""":param c:
|
||||||
|
:type c: int</details>
|
||||||
|
|
||||||
## Function `add`
|
## Function `add`
|
||||||
|
|
||||||
Adds two numbers.
|
Adds two numbers.
|
||||||
@@ -423,7 +723,8 @@ Return type: `int | float`
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<details><summary><h3 style="display:inline">Docstring</h3></summary>Adds two numbers.
|
<details><summary><h3 style="display:inline">Docstring</h3></summary>Adds """
|
||||||
|
"""two numbers.
|
||||||
|
|
||||||
:param a: The first number.
|
:param a: The first number.
|
||||||
:type a: int | float
|
:type a: int | float
|
||||||
@@ -490,7 +791,8 @@ Return type: `str`
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<details><summary><h5 style="display:inline">Docstring</h5></summary>Returns a greeting.
|
<details><summary><h5 style="display:inline">Docstring</h5></summary>"""
|
||||||
|
"""Returns a greeting.
|
||||||
|
|
||||||
:return: The greeting.
|
:return: The greeting.
|
||||||
:rtype: str</details>
|
:rtype: str</details>
|
||||||
@@ -499,7 +801,8 @@ Return type: `str`
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<details><summary><h3 style="display:inline">Docstring</h3></summary>A class representing an animal.
|
<details><summary><h3 style="display:inline">Docstring</h3></summary>A """
|
||||||
|
"""class representing an animal.
|
||||||
|
|
||||||
:param name: Its name.
|
:param name: Its name.
|
||||||
:type name: str</details>
|
:type name: str</details>
|
||||||
@@ -540,18 +843,96 @@ Return type: `None`
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<details><summary><h5 style="display:inline">Docstring</h5></summary>Barks.</details>
|
<details><summary><h5 style="display:inline">Docstring</h5></summary>Barks."""
|
||||||
|
"""</details>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<details><summary><h3 style="display:inline">Docstring</h3></summary>A dog.</details>'''),
|
<details><summary><h3 style="display:inline">Docstring</h3></summary>A dog."""
|
||||||
|
'</details>'
|
||||||
(PythonModuleDocumentationGenerator(ExistingFile('tests/unit/core/python/_core/test_project_dirs/pdir_2/src/pkg/module.py'), None, allow_tables = False, allow_html = True), '''# Module `module`
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonModuleDocumentationGenerator(
|
||||||
|
pathlib.Path(
|
||||||
|
(
|
||||||
|
'tests/unit/core/python/_core/test_pr'
|
||||||
|
'oject_dirs/pdir_2/src/pkg/module.py'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
allow_tables=False,
|
||||||
|
allow_html=True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"""# Module `module`
|
||||||
|
|
||||||
A test module.
|
A test module.
|
||||||
|
|
||||||
|
## Function `fn`
|
||||||
|
|
||||||
|
### Function signature
|
||||||
|
|
||||||
|
```python
|
||||||
|
fn(a: int, b: int = 42, c=42, d=42)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
- Parameter: `a`
|
||||||
|
|
||||||
|
Type: `int`
|
||||||
|
|
||||||
|
Kind: normal
|
||||||
|
|
||||||
|
Default value: --
|
||||||
|
|
||||||
|
Description: --
|
||||||
|
|
||||||
|
- Parameter: `b`
|
||||||
|
|
||||||
|
Type: `int`
|
||||||
|
|
||||||
|
Kind: normal
|
||||||
|
|
||||||
|
Default value: `42`
|
||||||
|
|
||||||
|
Description: --
|
||||||
|
|
||||||
|
- Parameter: `c`
|
||||||
|
|
||||||
|
Type: `int`
|
||||||
|
|
||||||
|
Kind: normal
|
||||||
|
|
||||||
|
Default value: `42`
|
||||||
|
|
||||||
|
Description: --
|
||||||
|
|
||||||
|
- Parameter: `d`
|
||||||
|
|
||||||
|
Type: --
|
||||||
|
|
||||||
|
Kind: normal
|
||||||
|
|
||||||
|
Default value: `42`
|
||||||
|
|
||||||
|
Description: --
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<details><summary><h3 style="display:inline">Docstring</h3></summary>"""
|
||||||
|
""":param c:
|
||||||
|
:type c: int</details>
|
||||||
|
|
||||||
## Function `add`
|
## Function `add`
|
||||||
|
|
||||||
Adds two numbers.
|
Adds two numbers.
|
||||||
@@ -597,7 +978,8 @@ Return type: `int | float`
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<details><summary><h3 style="display:inline">Docstring</h3></summary>Adds two numbers.
|
<details><summary><h3 style="display:inline">Docstring</h3></summary>Adds """
|
||||||
|
"""two numbers.
|
||||||
|
|
||||||
:param a: The first number.
|
:param a: The first number.
|
||||||
:type a: int | float
|
:type a: int | float
|
||||||
@@ -685,7 +1067,8 @@ Return type: `str`
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<details><summary><h5 style="display:inline">Docstring</h5></summary>Returns a greeting.
|
<details><summary><h5 style="display:inline">Docstring</h5></summary>"""
|
||||||
|
"""Returns a greeting.
|
||||||
|
|
||||||
:return: The greeting.
|
:return: The greeting.
|
||||||
:rtype: str</details>
|
:rtype: str</details>
|
||||||
@@ -694,7 +1077,8 @@ Return type: `str`
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<details><summary><h3 style="display:inline">Docstring</h3></summary>A class representing an animal.
|
<details><summary><h3 style="display:inline">Docstring</h3></summary>A """
|
||||||
|
"""class representing an animal.
|
||||||
|
|
||||||
:param name: Its name.
|
:param name: Its name.
|
||||||
:type name: str</details>
|
:type name: str</details>
|
||||||
@@ -741,18 +1125,96 @@ Return type: `None`
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<details><summary><h5 style="display:inline">Docstring</h5></summary>Barks.</details>
|
<details><summary><h5 style="display:inline">Docstring</h5></summary>Barks."""
|
||||||
|
"""</details>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<details><summary><h3 style="display:inline">Docstring</h3></summary>A dog.</details>'''),
|
<details><summary><h3 style="display:inline">Docstring</h3></summary>A """
|
||||||
|
'dog.</details>'
|
||||||
(PythonModuleDocumentationGenerator(ExistingFile('tests/unit/core/python/_core/test_project_dirs/pdir_2/src/pkg/module.py'), None, allow_tables = False, allow_html = False), '''# Module `module`
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonModuleDocumentationGenerator(
|
||||||
|
pathlib.Path(
|
||||||
|
(
|
||||||
|
'tests/unit/core/python/_core/test_pr'
|
||||||
|
'oject_dirs/pdir_2/src/pkg/module.py'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
allow_tables=False,
|
||||||
|
allow_html=False,
|
||||||
|
),
|
||||||
|
"""# Module `module`
|
||||||
|
|
||||||
A test module.
|
A test module.
|
||||||
|
|
||||||
|
## Function `fn`
|
||||||
|
|
||||||
|
### Function signature
|
||||||
|
|
||||||
|
```python
|
||||||
|
fn(a: int, b: int = 42, c=42, d=42)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
- Parameter: `a`
|
||||||
|
|
||||||
|
Type: `int`
|
||||||
|
|
||||||
|
Kind: normal
|
||||||
|
|
||||||
|
Default value: --
|
||||||
|
|
||||||
|
Description: --
|
||||||
|
|
||||||
|
- Parameter: `b`
|
||||||
|
|
||||||
|
Type: `int`
|
||||||
|
|
||||||
|
Kind: normal
|
||||||
|
|
||||||
|
Default value: `42`
|
||||||
|
|
||||||
|
Description: --
|
||||||
|
|
||||||
|
- Parameter: `c`
|
||||||
|
|
||||||
|
Type: `int`
|
||||||
|
|
||||||
|
Kind: normal
|
||||||
|
|
||||||
|
Default value: `42`
|
||||||
|
|
||||||
|
Description: --
|
||||||
|
|
||||||
|
- Parameter: `d`
|
||||||
|
|
||||||
|
Type: --
|
||||||
|
|
||||||
|
Kind: normal
|
||||||
|
|
||||||
|
Default value: `42`
|
||||||
|
|
||||||
|
Description: --
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Docstring
|
||||||
|
|
||||||
|
:param c:
|
||||||
|
:type c: int
|
||||||
|
|
||||||
## Function `add`
|
## Function `add`
|
||||||
|
|
||||||
Adds two numbers.
|
Adds two numbers.
|
||||||
@@ -958,7 +1420,12 @@ Barks.
|
|||||||
|
|
||||||
### Docstring
|
### Docstring
|
||||||
|
|
||||||
A dog.'''),
|
A dog.""",
|
||||||
])
|
),
|
||||||
def test_PythonModuleDocumentationGenerator_exceptions(module_documentation_generator, expected):
|
],
|
||||||
|
)
|
||||||
|
def test_PythonModuleDocumentationGenerator_generate_documentation(
|
||||||
|
module_documentation_generator,
|
||||||
|
expected,
|
||||||
|
):
|
||||||
assert module_documentation_generator.generate_documentation() == expected
|
assert module_documentation_generator.generate_documentation() == expected
|
||||||
@@ -12,16 +12,21 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from src.jcloud_docsgen.core.python._core import _argument_kind_human_readable
|
|
||||||
from src.jcloud_docsgen.core.python.arguments import PythonArgumentKind
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@pytest.mark.parametrize('argument_kind,expected', [
|
from src.jcloud_docsgen.core.python._core import _argument_kind_human_readable
|
||||||
|
from src.jcloud_docsgen.core.python.arguments import PythonArgumentKind
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'argument_kind,expected',
|
||||||
|
[
|
||||||
(PythonArgumentKind.NORMAL, 'normal'),
|
(PythonArgumentKind.NORMAL, 'normal'),
|
||||||
(PythonArgumentKind.POSITIONAL_ONLY, 'positional-only'),
|
(PythonArgumentKind.POSITIONAL_ONLY, 'positional-only'),
|
||||||
(PythonArgumentKind.KEYWORD_ONLY, 'keyword-only'),
|
(PythonArgumentKind.KEYWORD_ONLY, 'keyword-only'),
|
||||||
(PythonArgumentKind.VARARG, 'vararg'),
|
(PythonArgumentKind.VARARG, 'vararg'),
|
||||||
(PythonArgumentKind.KWARGS, 'kwargs'),
|
(PythonArgumentKind.KWARGS, 'kwargs'),
|
||||||
])
|
],
|
||||||
|
)
|
||||||
def test__argument_kind_human_readable(argument_kind, expected):
|
def test__argument_kind_human_readable(argument_kind, expected):
|
||||||
assert _argument_kind_human_readable(argument_kind) == expected
|
assert _argument_kind_human_readable(argument_kind) == expected
|
||||||
@@ -12,15 +12,24 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from src.jcloud_docsgen.core.python._core import _collect_definitions
|
|
||||||
from src.jcloud_docsgen.core.python.definitions import PythonClassDefinition, PythonFunctionDefinition
|
|
||||||
from src.jcloud_docsgen.core.python.arguments import PythonFunctionArgument, PythonArgumentKind
|
|
||||||
from src.jcloud_docsgen.core.python.docstrings import PythonDocstring
|
|
||||||
import pytest
|
|
||||||
import ast
|
import ast
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from src.jcloud_docsgen.core.python._core import _collect_definitions
|
||||||
|
from src.jcloud_docsgen.core.python.arguments import (
|
||||||
|
PythonArgumentKind,
|
||||||
|
PythonFunctionArgument,
|
||||||
|
)
|
||||||
|
from src.jcloud_docsgen.core.python.definitions import (
|
||||||
|
PythonClassDefinition,
|
||||||
|
PythonFunctionDefinition,
|
||||||
|
)
|
||||||
|
from src.jcloud_docsgen.core.python.docstrings import PythonDocstring
|
||||||
|
|
||||||
|
|
||||||
def module(source_code: str) -> ast.Module:
|
def module(source_code: str) -> ast.Module:
|
||||||
'''
|
"""
|
||||||
Returns an AST module of the source code.
|
Returns an AST module of the source code.
|
||||||
|
|
||||||
:param source_code: The module source code.
|
:param source_code: The module source code.
|
||||||
@@ -28,18 +37,41 @@ def module(source_code: str) -> ast.Module:
|
|||||||
|
|
||||||
:return: The AST module.
|
:return: The AST module.
|
||||||
:rtype: ast.Module
|
:rtype: ast.Module
|
||||||
'''
|
"""
|
||||||
|
|
||||||
return ast.parse(source_code)
|
return ast.parse(source_code)
|
||||||
|
|
||||||
@pytest.mark.parametrize('module,expected', [
|
|
||||||
(module('def add(a, b):\n\treturn a + b'), [
|
@pytest.mark.parametrize(
|
||||||
PythonFunctionDefinition('add', [
|
'module,expected',
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, None),
|
[
|
||||||
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, None, None),
|
(
|
||||||
], None, None, [])
|
module('def add(a, b):\n\treturn a + b'),
|
||||||
]),
|
[
|
||||||
(module('''def add(a: int | float, b: int | float) -> int | float:
|
PythonFunctionDefinition(
|
||||||
|
'add',
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'b',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
module('''def add(a: int | float, b: int | float) -> int | float:
|
||||||
"""Adds two numbers."""
|
"""Adds two numbers."""
|
||||||
return a + b
|
return a + b
|
||||||
|
|
||||||
@@ -62,78 +94,289 @@ class Something:
|
|||||||
Returns the value.
|
Returns the value.
|
||||||
"""
|
"""
|
||||||
return self._value
|
return self._value
|
||||||
'''), [
|
'''),
|
||||||
PythonFunctionDefinition('add', [
|
[
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, 'int | float'),
|
PythonFunctionDefinition(
|
||||||
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, None, 'int | float'),
|
'add',
|
||||||
], 'int | float', PythonDocstring('Adds two numbers.'), []),
|
[
|
||||||
PythonClassDefinition('Something', [], PythonDocstring('A class.'), [], [
|
PythonFunctionArgument(
|
||||||
PythonFunctionDefinition('__init__', [
|
'a',
|
||||||
PythonFunctionArgument('self', PythonArgumentKind.NORMAL, None, None),
|
PythonArgumentKind.NORMAL,
|
||||||
PythonFunctionArgument('value', PythonArgumentKind.NORMAL, '42', 'typing.Any'),
|
None,
|
||||||
], 'None', None, []),
|
'int | float',
|
||||||
PythonFunctionDefinition('value', [
|
),
|
||||||
PythonFunctionArgument('self', PythonArgumentKind.NORMAL, None, None),
|
PythonFunctionArgument(
|
||||||
], 'typing.Any', PythonDocstring('The value.'), ['property']),
|
'b',
|
||||||
PythonFunctionDefinition('get_value', [
|
PythonArgumentKind.NORMAL,
|
||||||
PythonFunctionArgument('self', PythonArgumentKind.NORMAL, None, None),
|
None,
|
||||||
], 'typing.Any', PythonDocstring('Returns the value.'), []),
|
'int | float',
|
||||||
])
|
),
|
||||||
]),
|
],
|
||||||
(module('''from src.jcloud_docsgen.core.python import PythonDocumentationGenerator
|
'int | float',
|
||||||
from src.jcloud_docsgen.core.python.namespaces import PythonModuleNamespace, PythonPackageNamespace
|
PythonDocstring('Adds two numbers.'),
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
PythonClassDefinition(
|
||||||
|
'Something',
|
||||||
|
[],
|
||||||
|
PythonDocstring('A class.'),
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
PythonFunctionDefinition(
|
||||||
|
'__init__',
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'self',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'value',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
'42',
|
||||||
|
'typing.Any',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'None',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
PythonFunctionDefinition(
|
||||||
|
'value',
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'self',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'typing.Any',
|
||||||
|
PythonDocstring('The value.'),
|
||||||
|
['property'],
|
||||||
|
),
|
||||||
|
PythonFunctionDefinition(
|
||||||
|
'get_value',
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'self',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'typing.Any',
|
||||||
|
PythonDocstring('Returns the value.'),
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
module("""from src.jcloud_docsgen.core.python import (
|
||||||
|
PythonDocumentationGenerator
|
||||||
|
)
|
||||||
|
from src.jcloud_docsgen.core.python.namespaces import (
|
||||||
|
PythonModuleNamespace,
|
||||||
|
PythonPackageNamespace
|
||||||
|
)
|
||||||
import pytest
|
import pytest
|
||||||
from src.jcloud_docsgen.utils import ExistingDirectory
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('project_directory,docs_directory', [
|
@pytest.mark.parametrize('project_directory,docs_directory', [
|
||||||
(1, 1),
|
(1, 1),
|
||||||
(1, None),
|
(1, None),
|
||||||
(42, None),
|
(42, None),
|
||||||
(ExistingDirectory('tests'), 1),
|
(pathlib.Path('tests'), 1),
|
||||||
(ExistingDirectory('tests/'), 1),
|
(pathlib.Path('tests/'), 1),
|
||||||
(1, ExistingDirectory('tests/')),
|
(1, pathlib.Path('tests/')),
|
||||||
(1, ExistingDirectory('tests')),
|
(1, pathlib.Path('tests')),
|
||||||
(None, ExistingDirectory('tests')),
|
(None, pathlib.Path('tests')),
|
||||||
])
|
])
|
||||||
def test_PythonDocumentationGenerator_type_exceptions(project_directory, docs_directory):
|
def test_PythonDocumentationGenerator_type_exceptions(
|
||||||
|
project_directory,
|
||||||
|
docs_directory
|
||||||
|
):
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
PythonDocumentationGenerator(project_directory, docs_directory)
|
PythonDocumentationGenerator(project_directory, docs_directory)
|
||||||
|
|
||||||
@pytest.mark.parametrize('python_documentation_generator,expected', [
|
@pytest.mark.parametrize('python_documentation_generator,expected', [
|
||||||
(PythonDocumentationGenerator(ExistingDirectory('tests/unit/core/python/_core/test_project_dirs/pdir_1'), ExistingDirectory('tests/unit/core/python/_core/test_project_dirs/pdir_1/docs')), []),
|
(PythonDocumentationGenerator(
|
||||||
(PythonDocumentationGenerator(ExistingDirectory('tests/unit/core/python/_core/test_project_dirs/pdir_2'), ExistingDirectory('tests/unit/core/python/_core/test_project_dirs/pdir_2/docs')), [PythonPackageNamespace('pkg', [PythonModuleNamespace('module')])]),
|
pathlib.Path(
|
||||||
(PythonDocumentationGenerator(ExistingDirectory('tests/unit/core/python/_core/test_project_dirs/pdir_3'), ExistingDirectory('tests/unit/core/python/_core/test_project_dirs/pdir_3/docs')), [PythonPackageNamespace('pkg', [PythonModuleNamespace('module'), PythonPackageNamespace('pkg', [PythonModuleNamespace('module2')])])]),
|
'tests/unit/core/python/_core/test_project_dirs/pdir_1'
|
||||||
|
),
|
||||||
|
pathlib.Path(
|
||||||
|
'tests/unit/core/python/_core/test_project_dirs/pdir_1/docs'
|
||||||
|
)
|
||||||
|
), []),
|
||||||
|
(PythonDocumentationGenerator(
|
||||||
|
pathlib.Path(
|
||||||
|
'tests/unit/core/python/_core/test_project_dirs/pdir_2'
|
||||||
|
),
|
||||||
|
pathlib.Path(
|
||||||
|
'tests/unit/core/python/_core/test_project_dirs/pdir_2/docs'
|
||||||
|
)
|
||||||
|
), [PythonPackageNamespace('pkg', [PythonModuleNamespace('module')])]),
|
||||||
|
(PythonDocumentationGenerator(
|
||||||
|
pathlib.Path(
|
||||||
|
'tests/unit/core/python/_core/test_project_dirs/pdir_3'
|
||||||
|
),
|
||||||
|
pathlib.Path(
|
||||||
|
'tests/unit/core/python/_core/test_project_dirs/pdir_3/docs'
|
||||||
|
)
|
||||||
|
), [
|
||||||
|
PythonPackageNamespace(
|
||||||
|
'pkg',
|
||||||
|
[
|
||||||
|
PythonModuleNamespace('module'),
|
||||||
|
PythonPackageNamespace('pkg',
|
||||||
|
[PythonModuleNamespace('module2')]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
])
|
])
|
||||||
def test_PythonDocumentationGenerator_collect_modules(python_documentation_generator: PythonDocumentationGenerator, expected):
|
])
|
||||||
assert python_documentation_generator.namespace() == expected'''), [
|
def test_PythonDocumentationGenerator_collect_modules(
|
||||||
PythonFunctionDefinition('test_PythonDocumentationGenerator_type_exceptions', [
|
python_documentation_generator: PythonDocumentationGenerator,
|
||||||
PythonFunctionArgument('project_directory', PythonArgumentKind.NORMAL, None, None),
|
expected
|
||||||
PythonFunctionArgument('docs_directory', PythonArgumentKind.NORMAL, None, None),
|
):
|
||||||
], None, None, ['''pytest.mark.parametrize('project_directory,docs_directory', [(1, 1), (1, None), (42, None), (ExistingDirectory('tests'), 1), (ExistingDirectory('tests/'), 1), (1, ExistingDirectory('tests/')), (1, ExistingDirectory('tests')), (None, ExistingDirectory('tests'))])''']),
|
assert python_documentation_generator.namespace() == expected"""),
|
||||||
PythonFunctionDefinition('test_PythonDocumentationGenerator_collect_modules', [
|
[
|
||||||
PythonFunctionArgument('python_documentation_generator', PythonArgumentKind.NORMAL, None, 'PythonDocumentationGenerator'),
|
PythonFunctionDefinition(
|
||||||
PythonFunctionArgument('expected', PythonArgumentKind.NORMAL, None, None)
|
'test_PythonDocumentationGenerator_type_exceptions',
|
||||||
], None, None, ['''pytest.mark.parametrize('python_documentation_generator,expected', [(PythonDocumentationGenerator(ExistingDirectory('tests/unit/core/python/_core/test_project_dirs/pdir_1'), ExistingDirectory('tests/unit/core/python/_core/test_project_dirs/pdir_1/docs')), []), (PythonDocumentationGenerator(ExistingDirectory('tests/unit/core/python/_core/test_project_dirs/pdir_2'), ExistingDirectory('tests/unit/core/python/_core/test_project_dirs/pdir_2/docs')), [PythonPackageNamespace('pkg', [PythonModuleNamespace('module')])]), (PythonDocumentationGenerator(ExistingDirectory('tests/unit/core/python/_core/test_project_dirs/pdir_3'), ExistingDirectory('tests/unit/core/python/_core/test_project_dirs/pdir_3/docs')), [PythonPackageNamespace('pkg', [PythonModuleNamespace('module'), PythonPackageNamespace('pkg', [PythonModuleNamespace('module2')])])])])'''])
|
[
|
||||||
]),
|
PythonFunctionArgument(
|
||||||
(module('''class C1:
|
'project_directory',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'docs_directory',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"""pytest.mark.parametrize('project_directo"""
|
||||||
|
"""ry,docs_directory', [(1, 1), (1, None), """
|
||||||
|
"""(42, None), (pathlib.Path('tests'), 1), """
|
||||||
|
"""(pathlib.Path('tests/'), 1), (1, pathlib"""
|
||||||
|
""".Path('tests/')), (1, pathlib.Path('test"""
|
||||||
|
"""s')), (None, pathlib.Path('tests'))])"""
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
PythonFunctionDefinition(
|
||||||
|
'test_PythonDocumentationGenerator_collect_modules',
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'python_documentation_generator',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
'PythonDocumentationGenerator',
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'expected',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"""pytest.mark.parametrize('python_documentation_gener"""
|
||||||
|
"""ator,expected', [(PythonDocumentationGenerator(path"""
|
||||||
|
"""lib.Path('tests/unit/core/python/_core/test_project"""
|
||||||
|
"""_dirs/pdir_1'), pathlib.Path('tests/unit/core/pytho"""
|
||||||
|
"""n/_core/test_project_dirs/pdir_1/docs')), []), (Pyt"""
|
||||||
|
"""honDocumentationGenerator(pathlib.Path('tests/unit/"""
|
||||||
|
"""core/python/_core/test_project_dirs/pdir_2'), pathl"""
|
||||||
|
"""ib.Path('tests/unit/core/python/_core/test_project_"""
|
||||||
|
"""dirs/pdir_2/docs')), [PythonPackageNamespace('pkg',"""
|
||||||
|
""" [PythonModuleNamespace('module')])]), (PythonDocum"""
|
||||||
|
"""entationGenerator(pathlib.Path('tests/unit/core/pyt"""
|
||||||
|
"""hon/_core/test_project_dirs/pdir_3'), pathlib.Path("""
|
||||||
|
"""'tests/unit/core/python/_core/test_project_dirs/pdi"""
|
||||||
|
"""r_3/docs')), [PythonPackageNamespace('pkg', [Python"""
|
||||||
|
"""ModuleNamespace(\'module'), PythonPackageNamespace("""
|
||||||
|
"""\'pkg\', [PythonModuleNamespace(\'module2')])])])])"""
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
module(
|
||||||
|
"""class C1:
|
||||||
class C2:
|
class C2:
|
||||||
class C3:
|
class C3:
|
||||||
def function(self, value: bool, /, arg) -> bool:
|
def function(self, value: bool, /, arg) -> bool:
|
||||||
def should_be_not_in_the_result(arg: int) -> object:
|
def should_be_not_in_the_result(arg: int) -> object:
|
||||||
pass
|
pass
|
||||||
return not value'''), [
|
return not value"""
|
||||||
PythonClassDefinition('C1', [], None, [], [
|
),
|
||||||
PythonClassDefinition('C2', [], None, [], [
|
[
|
||||||
PythonClassDefinition('C3', [], None, [], [
|
PythonClassDefinition(
|
||||||
PythonFunctionDefinition('function', [
|
'C1',
|
||||||
PythonFunctionArgument('self', PythonArgumentKind.POSITIONAL_ONLY, None, None),
|
[],
|
||||||
PythonFunctionArgument('value', PythonArgumentKind.POSITIONAL_ONLY, None, 'bool'),
|
None,
|
||||||
PythonFunctionArgument('arg', PythonArgumentKind.NORMAL, None, None),
|
[],
|
||||||
], 'bool', None, [])
|
[
|
||||||
])
|
PythonClassDefinition(
|
||||||
])
|
'C2',
|
||||||
])
|
[],
|
||||||
])
|
None,
|
||||||
])
|
[],
|
||||||
|
[
|
||||||
|
PythonClassDefinition(
|
||||||
|
'C3',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
PythonFunctionDefinition(
|
||||||
|
'function',
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'self',
|
||||||
|
PythonArgumentKind.POSITIONAL_ONLY,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'value',
|
||||||
|
PythonArgumentKind.POSITIONAL_ONLY,
|
||||||
|
None,
|
||||||
|
'bool',
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'arg',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'bool',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test___collect_definitions(module, expected):
|
def test___collect_definitions(module, expected):
|
||||||
assert list(_collect_definitions(module)) == expected
|
assert list(_collect_definitions(module)) == expected
|
||||||
@@ -12,15 +12,18 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from src.jcloud_docsgen.core.python._core import _fit_row_length
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@pytest.mark.parametrize('expected_length,row,expected', [
|
from src.jcloud_docsgen.core.python._core import _fit_row_length
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'expected_length,row,expected',
|
||||||
|
[
|
||||||
(0, (), ()),
|
(0, (), ()),
|
||||||
(1, (), (None,)),
|
(1, (), (None,)),
|
||||||
(2, (), (None, None)),
|
(2, (), (None, None)),
|
||||||
(2, (1,), (1, None)),
|
(2, (1,), (1, None)),
|
||||||
|
|
||||||
(0, (1,), ()),
|
(0, (1,), ()),
|
||||||
(1, (1, 2), (1,)),
|
(1, (1, 2), (1,)),
|
||||||
(1, (1, 2), (1,)),
|
(1, (1, 2), (1,)),
|
||||||
@@ -28,28 +31,35 @@ import pytest
|
|||||||
(0, (1, 2, 3), ()),
|
(0, (1, 2, 3), ()),
|
||||||
(1, (1, 2, 3), (1,)),
|
(1, (1, 2, 3), (1,)),
|
||||||
(2, (1, 2, 3), (1, 2)),
|
(2, (1, 2, 3), (1, 2)),
|
||||||
|
|
||||||
(1, (1,), (1,)),
|
(1, (1,), (1,)),
|
||||||
(2, (1, 1), (1, 1)),
|
(2, (1, 1), (1, 1)),
|
||||||
(2, (1, 2), (1, 2)),
|
(2, (1, 2), (1, 2)),
|
||||||
(3, (1, 2, 3), (1, 2, 3)),
|
(3, (1, 2, 3), (1, 2, 3)),
|
||||||
])
|
],
|
||||||
|
)
|
||||||
def test__fit_row_length(expected_length, row, expected):
|
def test__fit_row_length(expected_length, row, expected):
|
||||||
assert _fit_row_length(expected_length, row) == expected
|
assert _fit_row_length(expected_length, row) == expected
|
||||||
|
|
||||||
@pytest.mark.parametrize('row', [
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'row',
|
||||||
|
[
|
||||||
(),
|
(),
|
||||||
(1,),
|
(1,),
|
||||||
(1, 2),
|
(1, 2),
|
||||||
(1, 2, 3),
|
(1, 2, 3),
|
||||||
(1, 2, 3, 456),
|
(1, 2, 3, 456),
|
||||||
])
|
],
|
||||||
@pytest.mark.parametrize('expected_length,expected_exception', [
|
)
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'expected_length,expected_exception',
|
||||||
|
[
|
||||||
(-1, ValueError),
|
(-1, ValueError),
|
||||||
(-2, ValueError),
|
(-2, ValueError),
|
||||||
(-3, ValueError),
|
(-3, ValueError),
|
||||||
(-42, ValueError),
|
(-42, ValueError),
|
||||||
])
|
],
|
||||||
|
)
|
||||||
def test__fit_row_length_exceptions(expected_length, row, expected_exception):
|
def test__fit_row_length_exceptions(expected_length, row, expected_exception):
|
||||||
with pytest.raises(expected_exception) as exc_info:
|
with pytest.raises(expected_exception) as exc_info:
|
||||||
_fit_row_length(expected_length, row)
|
_fit_row_length(expected_length, row)
|
||||||
|
|||||||
@@ -12,13 +12,23 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from src.jcloud_docsgen.core.python._core import _function_params_info, _FunctionParamInfo
|
|
||||||
from src.jcloud_docsgen.core.python.arguments import PythonFunctionArgument, PythonArgumentKind
|
|
||||||
import pytest
|
|
||||||
import docstring_parser
|
import docstring_parser
|
||||||
|
import pytest
|
||||||
|
|
||||||
def docstring_args_list(docstring: str) -> list[docstring_parser.DocstringParam]:
|
from src.jcloud_docsgen.core.python._core import (
|
||||||
'''
|
_function_params_info,
|
||||||
|
_FunctionParamInfo,
|
||||||
|
)
|
||||||
|
from src.jcloud_docsgen.core.python.arguments import (
|
||||||
|
PythonArgumentKind,
|
||||||
|
PythonFunctionArgument,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_args_list(
|
||||||
|
docstring: str,
|
||||||
|
) -> list[docstring_parser.DocstringParam]:
|
||||||
|
"""
|
||||||
Returns the parameter list of a docstring.
|
Returns the parameter list of a docstring.
|
||||||
|
|
||||||
:param docstring: The docstring
|
:param docstring: The docstring
|
||||||
@@ -26,79 +36,164 @@ def docstring_args_list(docstring: str) -> list[docstring_parser.DocstringParam]
|
|||||||
|
|
||||||
:return: The parameter list.
|
:return: The parameter list.
|
||||||
:rtype: list[docstring_parser.DocstringParam]
|
:rtype: list[docstring_parser.DocstringParam]
|
||||||
'''
|
"""
|
||||||
|
|
||||||
return docstring_parser.parse(docstring).params
|
return docstring_parser.parse(docstring).params
|
||||||
|
|
||||||
@pytest.mark.parametrize('arg_list,docstring,expected', [
|
|
||||||
([
|
@pytest.mark.parametrize(
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', 'int'),
|
'arg_list,docstring,expected',
|
||||||
], ':param a: a\n:type a: str', {
|
[
|
||||||
'a': _FunctionParamInfo('int', 'a')
|
(
|
||||||
}),
|
[
|
||||||
([
|
PythonFunctionArgument(
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', None),
|
'a', PythonArgumentKind.NORMAL, '', 'int'
|
||||||
], ':param a: a\n:type a: str', {
|
),
|
||||||
'a': _FunctionParamInfo('str', 'a')
|
],
|
||||||
}),
|
':param a: a\n:type a: str',
|
||||||
([
|
{
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', None),
|
'a': _FunctionParamInfo('int', 'a'),
|
||||||
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, '', None),
|
},
|
||||||
], ':param a: a\n:type a: str', {
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a', PythonArgumentKind.NORMAL, '', None
|
||||||
|
),
|
||||||
|
],
|
||||||
|
':param a: a\n:type a: str',
|
||||||
|
{
|
||||||
'a': _FunctionParamInfo('str', 'a'),
|
'a': _FunctionParamInfo('str', 'a'),
|
||||||
'b': _FunctionParamInfo(None, None)
|
},
|
||||||
}),
|
),
|
||||||
([
|
(
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', None),
|
[
|
||||||
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, '', 'int'),
|
PythonFunctionArgument(
|
||||||
], ':param a: a\n:type a: str', {
|
'a', PythonArgumentKind.NORMAL, '', None
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'b', PythonArgumentKind.NORMAL, '', None
|
||||||
|
),
|
||||||
|
],
|
||||||
|
':param a: a\n:type a: str',
|
||||||
|
{
|
||||||
'a': _FunctionParamInfo('str', 'a'),
|
'a': _FunctionParamInfo('str', 'a'),
|
||||||
'b': _FunctionParamInfo('int', None)
|
'b': _FunctionParamInfo(None, None),
|
||||||
}),
|
},
|
||||||
([
|
),
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', None),
|
(
|
||||||
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, '', 'int'),
|
[
|
||||||
], ':param a: a\n:type a: str\n:param b: b\n:type b: str', {
|
PythonFunctionArgument(
|
||||||
|
'a', PythonArgumentKind.NORMAL, '', None
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'b', PythonArgumentKind.NORMAL, '', 'int'
|
||||||
|
),
|
||||||
|
],
|
||||||
|
':param a: a\n:type a: str',
|
||||||
|
{
|
||||||
'a': _FunctionParamInfo('str', 'a'),
|
'a': _FunctionParamInfo('str', 'a'),
|
||||||
'b': _FunctionParamInfo('int', 'b')
|
'b': _FunctionParamInfo('int', None),
|
||||||
}),
|
},
|
||||||
([
|
),
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', None),
|
(
|
||||||
], ':param a: a\n:type a: str\n:param b: b\n:type b: int', {
|
[
|
||||||
'a': _FunctionParamInfo('str', 'a')
|
PythonFunctionArgument(
|
||||||
}),
|
'a', PythonArgumentKind.NORMAL, '', None
|
||||||
([
|
),
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', None),
|
PythonFunctionArgument(
|
||||||
], '', {
|
'b', PythonArgumentKind.NORMAL, '', 'int'
|
||||||
'a': _FunctionParamInfo(None, None)
|
),
|
||||||
}),
|
],
|
||||||
([
|
':param a: a\n:type a: str\n:param b: b\n:type b: str',
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', 'str'),
|
{
|
||||||
], '', {
|
'a': _FunctionParamInfo('str', 'a'),
|
||||||
'a': _FunctionParamInfo('str', None)
|
'b': _FunctionParamInfo('int', 'b'),
|
||||||
}),
|
},
|
||||||
([
|
),
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', 'str'),
|
(
|
||||||
], ':param a:\n:type a: int', {
|
[
|
||||||
'a': _FunctionParamInfo('str', '')
|
PythonFunctionArgument(
|
||||||
}),
|
'a', PythonArgumentKind.NORMAL, '', None
|
||||||
([
|
),
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', None),
|
],
|
||||||
], ':param a:\n:type a: int', {
|
':param a: a\n:type a: str\n:param b: b\n:type b: int',
|
||||||
'a': _FunctionParamInfo('int', '')
|
{
|
||||||
}),
|
'a': _FunctionParamInfo('str', 'a'),
|
||||||
([
|
},
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', None),
|
),
|
||||||
], ':param a: a', {
|
(
|
||||||
'a': _FunctionParamInfo(None, 'a')
|
[
|
||||||
}),
|
PythonFunctionArgument(
|
||||||
([
|
'a', PythonArgumentKind.NORMAL, '', None
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', 'str'),
|
),
|
||||||
], ':param a: a', {
|
],
|
||||||
'a': _FunctionParamInfo('str', 'a')
|
'',
|
||||||
}),
|
{
|
||||||
|
'a': _FunctionParamInfo(None, None),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a', PythonArgumentKind.NORMAL, '', 'str'
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'',
|
||||||
|
{
|
||||||
|
'a': _FunctionParamInfo('str', None),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a', PythonArgumentKind.NORMAL, '', 'str'
|
||||||
|
),
|
||||||
|
],
|
||||||
|
':param a:\n:type a: int',
|
||||||
|
{
|
||||||
|
'a': _FunctionParamInfo('str', ''),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a', PythonArgumentKind.NORMAL, '', None
|
||||||
|
),
|
||||||
|
],
|
||||||
|
':param a:\n:type a: int',
|
||||||
|
{
|
||||||
|
'a': _FunctionParamInfo('int', ''),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a', PythonArgumentKind.NORMAL, '', None
|
||||||
|
),
|
||||||
|
],
|
||||||
|
':param a: a',
|
||||||
|
{
|
||||||
|
'a': _FunctionParamInfo(None, 'a'),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a', PythonArgumentKind.NORMAL, '', 'str'
|
||||||
|
),
|
||||||
|
],
|
||||||
|
':param a: a',
|
||||||
|
{
|
||||||
|
'a': _FunctionParamInfo('str', 'a'),
|
||||||
|
},
|
||||||
|
),
|
||||||
([], ':param a: a\n:type a: str', {}),
|
([], ':param a: a\n:type a: str', {}),
|
||||||
([], '', {}),
|
([], '', {}),
|
||||||
])
|
],
|
||||||
|
)
|
||||||
def test__function_params_types(arg_list, docstring, expected):
|
def test__function_params_types(arg_list, docstring, expected):
|
||||||
assert _function_params_info(arg_list, docstring_args_list(docstring)) == expected
|
assert (
|
||||||
|
_function_params_info(arg_list, docstring_args_list(docstring))
|
||||||
|
== expected
|
||||||
|
)
|
||||||
@@ -12,82 +12,413 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from src.jcloud_docsgen.core.python._core import _markdown_table
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@pytest.mark.parametrize('header,body,allow_markdown_table,force_row_lengths,one_line_values,missing_value,expected', [
|
from src.jcloud_docsgen.core.python._core import _markdown_table
|
||||||
([], [], False, False, True, '--', ''),
|
|
||||||
([], [('a',)], False, False, True, '--', ''),
|
|
||||||
(['a'], [], False, False, True, '--', ''),
|
@pytest.mark.parametrize(
|
||||||
(['a'], [(1,)], True, False, True, '--', '''| a |
|
(
|
||||||
|
'header,body,allow_markdown_table,force_row_le'
|
||||||
|
'ngths,one_line_values,missing_value,expected'
|
||||||
|
),
|
||||||
|
[
|
||||||
|
(
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
'',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[],
|
||||||
|
[('a',)],
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
'',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
['a'],
|
||||||
|
[],
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
'',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
['a'],
|
||||||
|
[(1,)],
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
"""| a |
|
||||||
| --- |
|
| --- |
|
||||||
| 1 |'''),
|
| 1 |""",
|
||||||
(['a'], [(1, 2)], True, False, True, '--', '''| a |
|
),
|
||||||
|
(
|
||||||
|
['a'],
|
||||||
|
[(1, 2)],
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
"""| a |
|
||||||
| --- |
|
| --- |
|
||||||
| 1 |'''),
|
| 1 |""",
|
||||||
(['a', 'b'], [(1, 2)], True, False, True, '--', '''| a | b |
|
),
|
||||||
|
(
|
||||||
|
['a', 'b'],
|
||||||
|
[(1, 2)],
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
"""| a | b |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| 1 | 2 |'''),
|
| 1 | 2 |""",
|
||||||
(['a', 'b'], [(1,)], True, False, True, '--', '''| a | b |
|
),
|
||||||
|
(
|
||||||
|
['a', 'b'],
|
||||||
|
[(1,)],
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
"""| a | b |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| 1 | -- |'''),
|
| 1 | -- |""",
|
||||||
(['a', 'b'], [()], True, False, True, '--', '''| a | b |
|
),
|
||||||
|
(
|
||||||
|
['a', 'b'],
|
||||||
|
[()],
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
"""| a | b |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| -- | -- |'''),
|
| -- | -- |""",
|
||||||
(['a', 'b'], [(1, 2), (3, 4)], True, False, True, '--', '''| a | b |
|
),
|
||||||
|
(
|
||||||
|
['a', 'b'],
|
||||||
|
[(1, 2), (3, 4)],
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
"""| a | b |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| 1 | 2 |
|
| 1 | 2 |
|
||||||
| 3 | 4 |'''),
|
| 3 | 4 |""",
|
||||||
(['a'], [('line1\nline2',)], True, False, True, '--', '''| a |
|
),
|
||||||
|
(
|
||||||
|
['a'],
|
||||||
|
[('line1\nline2',)],
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
"""| a |
|
||||||
| --- |
|
| --- |
|
||||||
| line1 line2 |'''),
|
| line1 line2 |""",
|
||||||
(['a'], [('line1\nline2',)], True, False, False, '--', '''| a |
|
),
|
||||||
|
(
|
||||||
|
['a'],
|
||||||
|
[('line1\nline2',)],
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
'--',
|
||||||
|
"""| a |
|
||||||
| --- |
|
| --- |
|
||||||
| line1\nline2 |'''),
|
| line1\nline2 |""",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
'',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[],
|
||||||
|
[('a',)],
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
'',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
['a'],
|
||||||
|
[],
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
'',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
['a'],
|
||||||
|
[(1,)],
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
'- a: 1',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
['a'],
|
||||||
|
[(1, 2)],
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
'- a: 1',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
['a', 'b'],
|
||||||
|
[(1, 2)],
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
"""- a: 1
|
||||||
|
|
||||||
([], [], False, False, True, '--', ''),
|
b: 2""",
|
||||||
([], [('a',)], False, False, True, '--', ''),
|
),
|
||||||
(['a'], [], False, False, True, '--', ''),
|
(
|
||||||
(['a'], [(1,)], False, False, True, '--', '''- a: 1'''),
|
['a', 'b'],
|
||||||
(['a'], [(1, 2)], False, False, True, '--', '''- a: 1'''),
|
[(1,)],
|
||||||
(['a', 'b'], [(1, 2)], False, False, True, '--', '''- a: 1
|
False,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
"""- a: 1
|
||||||
|
|
||||||
b: 2'''),
|
b: --""",
|
||||||
(['a', 'b'], [(1,)], False, False, True, '--', '''- a: 1
|
),
|
||||||
|
(
|
||||||
|
['a', 'b'],
|
||||||
|
[()],
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
"""- a: --
|
||||||
|
|
||||||
b: --'''),
|
b: --""",
|
||||||
(['a', 'b'], [()], False, False, True, '--', '''- a: --
|
),
|
||||||
|
(
|
||||||
b: --'''),
|
['a', 'b'],
|
||||||
(['a', 'b'], [(1, 2), (3, 4)], False, False, True, '--', '''- a: 1
|
[(1, 2), (3, 4)],
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
"""- a: 1
|
||||||
|
|
||||||
b: 2
|
b: 2
|
||||||
|
|
||||||
- a: 3
|
- a: 3
|
||||||
|
|
||||||
b: 4'''),
|
b: 4""",
|
||||||
(['a'], [('line1\nline2',)], False, False, True, '--', '- a: line1 line2'),
|
),
|
||||||
(['a'], [('line1\nline2',)], False, False, False, '--', '- a: line1\nline2'),
|
(
|
||||||
])
|
['a'],
|
||||||
def test__markdown_table(header, body, allow_markdown_table, force_row_lengths, one_line_values, missing_value, expected):
|
[('line1\nline2',)],
|
||||||
assert _markdown_table(header, body, allow_markdown_table = allow_markdown_table, force_row_lengths = force_row_lengths, one_line_values = one_line_values, missing_value = missing_value) == expected
|
False,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
'- a: line1 line2',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
['a'],
|
||||||
|
[('line1\nline2',)],
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
'--',
|
||||||
|
'- a: line1\nline2',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test__markdown_table(
|
||||||
|
header,
|
||||||
|
body,
|
||||||
|
allow_markdown_table,
|
||||||
|
force_row_lengths,
|
||||||
|
one_line_values,
|
||||||
|
missing_value,
|
||||||
|
expected,
|
||||||
|
):
|
||||||
|
assert (
|
||||||
|
_markdown_table(
|
||||||
|
header,
|
||||||
|
body,
|
||||||
|
allow_markdown_table=allow_markdown_table,
|
||||||
|
force_row_lengths=force_row_lengths,
|
||||||
|
one_line_values=one_line_values,
|
||||||
|
missing_value=missing_value,
|
||||||
|
)
|
||||||
|
== expected
|
||||||
|
)
|
||||||
|
|
||||||
@pytest.mark.parametrize('header,body,allow_markdown_table,force_row_lengths,one_line_values,missing_value,expected_exception,expected_exception_msg', [
|
|
||||||
(['a'], [(1, 2)], True, True, True, '--', ValueError, 'expected 1 value, got 2'),
|
|
||||||
(['a'], [(1, 2, 3)], True, True, True, '--', ValueError, 'expected 1 value, got 3'),
|
|
||||||
(['a'], [()], True, True, True, '--', ValueError, 'expected 1 value, got 0'),
|
|
||||||
(['a', 'b'], [()], True, True, True, '--', ValueError, 'expected 2 values, got 0'),
|
|
||||||
(['a', 'b'], [(1,)], True, True, True, '--', ValueError, 'expected 2 values, got 1'),
|
|
||||||
(['a', 'b'], [(1, 2, 3)], True, True, True, '--', ValueError, 'expected 2 values, got 3'),
|
|
||||||
|
|
||||||
(['a'], [(1, 2)], False, True, True, '--', ValueError, 'expected 1 value, got 2'),
|
@pytest.mark.parametrize(
|
||||||
(['a'], [(1, 2, 3)], False, True, True, '--', ValueError, 'expected 1 value, got 3'),
|
(
|
||||||
(['a'], [()], False, True, True, '--', ValueError, 'expected 1 value, got 0'),
|
'header,body,allow_markdown_table,force_row_lengths,one_line_v'
|
||||||
(['a', 'b'], [()], False, True, True, '--', ValueError, 'expected 2 values, got 0'),
|
'alues,missing_value,expected_exception,expected_exception_msg'
|
||||||
(['a', 'b'], [(1,)], False, True, True, '--', ValueError, 'expected 2 values, got 1'),
|
),
|
||||||
(['a', 'b'], [(1, 2, 3)], False, True, True, '--', ValueError, 'expected 2 values, got 3'),
|
[
|
||||||
])
|
(
|
||||||
def test__markdown_table_exceptions(header, body, allow_markdown_table, force_row_lengths, one_line_values, missing_value, expected_exception, expected_exception_msg):
|
['a'],
|
||||||
|
[(1, 2)],
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
ValueError,
|
||||||
|
'expected 1 value, got 2',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
['a'],
|
||||||
|
[(1, 2, 3)],
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
ValueError,
|
||||||
|
'expected 1 value, got 3',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
['a'],
|
||||||
|
[()],
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
ValueError,
|
||||||
|
'expected 1 value, got 0',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
['a', 'b'],
|
||||||
|
[()],
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
ValueError,
|
||||||
|
'expected 2 values, got 0',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
['a', 'b'],
|
||||||
|
[(1,)],
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
ValueError,
|
||||||
|
'expected 2 values, got 1',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
['a', 'b'],
|
||||||
|
[(1, 2, 3)],
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
ValueError,
|
||||||
|
'expected 2 values, got 3',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
['a'],
|
||||||
|
[(1, 2)],
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
ValueError,
|
||||||
|
'expected 1 value, got 2',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
['a'],
|
||||||
|
[(1, 2, 3)],
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
ValueError,
|
||||||
|
'expected 1 value, got 3',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
['a'],
|
||||||
|
[()],
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
ValueError,
|
||||||
|
'expected 1 value, got 0',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
['a', 'b'],
|
||||||
|
[()],
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
ValueError,
|
||||||
|
'expected 2 values, got 0',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
['a', 'b'],
|
||||||
|
[(1,)],
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
ValueError,
|
||||||
|
'expected 2 values, got 1',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
['a', 'b'],
|
||||||
|
[(1, 2, 3)],
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
'--',
|
||||||
|
ValueError,
|
||||||
|
'expected 2 values, got 3',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test__markdown_table_exceptions(
|
||||||
|
header,
|
||||||
|
body,
|
||||||
|
allow_markdown_table,
|
||||||
|
force_row_lengths,
|
||||||
|
one_line_values,
|
||||||
|
missing_value,
|
||||||
|
expected_exception,
|
||||||
|
expected_exception_msg,
|
||||||
|
):
|
||||||
with pytest.raises(expected_exception) as exc_info:
|
with pytest.raises(expected_exception) as exc_info:
|
||||||
_markdown_table(header, body, allow_markdown_table = allow_markdown_table, force_row_lengths = force_row_lengths, one_line_values = one_line_values, missing_value = missing_value)
|
_markdown_table(
|
||||||
|
header,
|
||||||
|
body,
|
||||||
|
allow_markdown_table=allow_markdown_table,
|
||||||
|
force_row_lengths=force_row_lengths,
|
||||||
|
one_line_values=one_line_values,
|
||||||
|
missing_value=missing_value,
|
||||||
|
)
|
||||||
assert str(exc_info.value) == expected_exception_msg
|
assert str(exc_info.value) == expected_exception_msg
|
||||||
@@ -12,86 +12,347 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from src.jcloud_docsgen.core.python._core import _signature_argument_list
|
|
||||||
from src.jcloud_docsgen.core.python.arguments import PythonFunctionArgument, PythonArgumentKind
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@pytest.mark.parametrize('argument_list,expected', [
|
from src.jcloud_docsgen.core.python._core import _signature_argument_list
|
||||||
([
|
from src.jcloud_docsgen.core.python.arguments import (
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, None)
|
PythonArgumentKind,
|
||||||
], ['a']),
|
PythonFunctionArgument,
|
||||||
([
|
)
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.POSITIONAL_ONLY, None, None)
|
|
||||||
], ['a', '/']),
|
|
||||||
([
|
@pytest.mark.parametrize(
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.POSITIONAL_ONLY, None, None),
|
'argument_list,expected',
|
||||||
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, None, None),
|
[
|
||||||
], ['a', '/', 'b']),
|
(
|
||||||
([
|
[
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.POSITIONAL_ONLY, None, None),
|
PythonFunctionArgument(
|
||||||
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, None, None),
|
'a',
|
||||||
PythonFunctionArgument('c', PythonArgumentKind.KEYWORD_ONLY, None, None),
|
PythonArgumentKind.NORMAL,
|
||||||
], ['a', '/', 'b', '*', 'c']),
|
None,
|
||||||
([
|
None,
|
||||||
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, None, None),
|
),
|
||||||
PythonFunctionArgument('c', PythonArgumentKind.KEYWORD_ONLY, None, None),
|
],
|
||||||
], ['b', '*', 'c']),
|
['a'],
|
||||||
([
|
),
|
||||||
PythonFunctionArgument('c', PythonArgumentKind.KEYWORD_ONLY, None, None),
|
(
|
||||||
], ['*', 'c']),
|
[
|
||||||
([
|
PythonFunctionArgument(
|
||||||
PythonFunctionArgument('b', PythonArgumentKind.POSITIONAL_ONLY, None, None),
|
'a',
|
||||||
PythonFunctionArgument('c', PythonArgumentKind.KEYWORD_ONLY, None, None),
|
PythonArgumentKind.POSITIONAL_ONLY,
|
||||||
], ['b', '/', '*', 'c']),
|
None,
|
||||||
([
|
None,
|
||||||
PythonFunctionArgument('args', PythonArgumentKind.VARARG, None, None),
|
),
|
||||||
], ['*args']),
|
],
|
||||||
([
|
['a', '/'],
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, None),
|
),
|
||||||
PythonFunctionArgument('args', PythonArgumentKind.VARARG, None, None),
|
(
|
||||||
], ['a', '*args']),
|
[
|
||||||
([
|
PythonFunctionArgument(
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.POSITIONAL_ONLY, None, None),
|
'a',
|
||||||
PythonFunctionArgument('args', PythonArgumentKind.VARARG, None, None),
|
PythonArgumentKind.POSITIONAL_ONLY,
|
||||||
], ['a', '/', '*args']),
|
None,
|
||||||
([
|
None,
|
||||||
PythonFunctionArgument('args', PythonArgumentKind.VARARG, None, None),
|
),
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.KEYWORD_ONLY, None, None),
|
PythonFunctionArgument(
|
||||||
], ['*args', 'a']),
|
'b',
|
||||||
([
|
PythonArgumentKind.NORMAL,
|
||||||
PythonFunctionArgument('args', PythonArgumentKind.VARARG, None, None),
|
None,
|
||||||
PythonFunctionArgument('kwargs', PythonArgumentKind.KWARGS, None, None),
|
None,
|
||||||
], ['*args', '**kwargs']),
|
),
|
||||||
([
|
],
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.POSITIONAL_ONLY, None, None),
|
['a', '/', 'b'],
|
||||||
PythonFunctionArgument('args', PythonArgumentKind.VARARG, None, None),
|
),
|
||||||
PythonFunctionArgument('kwargs', PythonArgumentKind.KWARGS, None, None),
|
(
|
||||||
], ['a', '/', '*args', '**kwargs']),
|
[
|
||||||
([
|
PythonFunctionArgument(
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, None),
|
'a',
|
||||||
PythonFunctionArgument('args', PythonArgumentKind.VARARG, None, None),
|
PythonArgumentKind.POSITIONAL_ONLY,
|
||||||
PythonFunctionArgument('kwargs', PythonArgumentKind.KWARGS, None, None),
|
None,
|
||||||
], ['a', '*args', '**kwargs']),
|
None,
|
||||||
([
|
),
|
||||||
PythonFunctionArgument('args', PythonArgumentKind.VARARG, None, None),
|
PythonFunctionArgument(
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.KEYWORD_ONLY, None, None),
|
'b',
|
||||||
PythonFunctionArgument('kwargs', PythonArgumentKind.KWARGS, None, None),
|
PythonArgumentKind.NORMAL,
|
||||||
], ['*args', 'a', '**kwargs']),
|
None,
|
||||||
([
|
None,
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.KEYWORD_ONLY, None, None),
|
),
|
||||||
PythonFunctionArgument('kwargs', PythonArgumentKind.KWARGS, None, None),
|
PythonFunctionArgument(
|
||||||
], ['*', 'a', '**kwargs']),
|
'c',
|
||||||
([
|
PythonArgumentKind.KEYWORD_ONLY,
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, None),
|
None,
|
||||||
PythonFunctionArgument('kwargs', PythonArgumentKind.KWARGS, None, None),
|
None,
|
||||||
], ['a', '**kwargs']),
|
),
|
||||||
([
|
],
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.POSITIONAL_ONLY, None, None),
|
['a', '/', 'b', '*', 'c'],
|
||||||
PythonFunctionArgument('kwargs', PythonArgumentKind.KWARGS, None, None),
|
),
|
||||||
], ['a', '/', '**kwargs']),
|
(
|
||||||
([
|
[
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '1', 'int'),
|
PythonFunctionArgument(
|
||||||
], ['a: int = 1']),
|
'b',
|
||||||
])
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'c',
|
||||||
|
PythonArgumentKind.KEYWORD_ONLY,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
['b', '*', 'c'],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'c',
|
||||||
|
PythonArgumentKind.KEYWORD_ONLY,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
['*', 'c'],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'b',
|
||||||
|
PythonArgumentKind.POSITIONAL_ONLY,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'c',
|
||||||
|
PythonArgumentKind.KEYWORD_ONLY,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
['b', '/', '*', 'c'],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'args',
|
||||||
|
PythonArgumentKind.VARARG,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
['*args'],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'args',
|
||||||
|
PythonArgumentKind.VARARG,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
['a', '*args'],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.POSITIONAL_ONLY,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'args',
|
||||||
|
PythonArgumentKind.VARARG,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
['a', '/', '*args'],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'args',
|
||||||
|
PythonArgumentKind.VARARG,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.KEYWORD_ONLY,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
['*args', 'a'],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'args',
|
||||||
|
PythonArgumentKind.VARARG,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'kwargs',
|
||||||
|
PythonArgumentKind.KWARGS,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
['*args', '**kwargs'],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.POSITIONAL_ONLY,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'args',
|
||||||
|
PythonArgumentKind.VARARG,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'kwargs',
|
||||||
|
PythonArgumentKind.KWARGS,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
['a', '/', '*args', '**kwargs'],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'args',
|
||||||
|
PythonArgumentKind.VARARG,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'kwargs',
|
||||||
|
PythonArgumentKind.KWARGS,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
['a', '*args', '**kwargs'],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'args',
|
||||||
|
PythonArgumentKind.VARARG,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.KEYWORD_ONLY,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'kwargs',
|
||||||
|
PythonArgumentKind.KWARGS,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
['*args', 'a', '**kwargs'],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.KEYWORD_ONLY,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'kwargs',
|
||||||
|
PythonArgumentKind.KWARGS,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
['*', 'a', '**kwargs'],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'kwargs',
|
||||||
|
PythonArgumentKind.KWARGS,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
['a', '**kwargs'],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.POSITIONAL_ONLY,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'kwargs',
|
||||||
|
PythonArgumentKind.KWARGS,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
['a', '/', '**kwargs'],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
'1',
|
||||||
|
'int',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
['a: int = 1'],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
'1',
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
['a=1'],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test__signature_argument_list(argument_list, expected):
|
def test__signature_argument_list(argument_list, expected):
|
||||||
assert _signature_argument_list(argument_list) == expected
|
assert _signature_argument_list(argument_list) == expected
|
||||||
@@ -1,9 +1,17 @@
|
|||||||
'''
|
"""
|
||||||
A test module.
|
A test module.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def fn(a: int, b: int = 42, c=42, d=42):
|
||||||
|
"""
|
||||||
|
:param c:
|
||||||
|
:type c: int
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def add(a: int | float, b: int | float) -> int | float:
|
def add(a: int | float, b: int | float) -> int | float:
|
||||||
'''
|
"""
|
||||||
Adds two numbers.
|
Adds two numbers.
|
||||||
|
|
||||||
:param a: The first number.
|
:param a: The first number.
|
||||||
@@ -13,38 +21,41 @@ def add(a: int | float, b: int | float) -> int | float:
|
|||||||
|
|
||||||
:return: The sum.
|
:return: The sum.
|
||||||
:rtype: int | float
|
:rtype: int | float
|
||||||
'''
|
"""
|
||||||
|
|
||||||
return a + b
|
return a + b
|
||||||
|
|
||||||
|
|
||||||
class Animal:
|
class Animal:
|
||||||
'''
|
"""
|
||||||
A class representing an animal.
|
A class representing an animal.
|
||||||
|
|
||||||
:param name: Its name.
|
:param name: Its name.
|
||||||
:type name: str
|
:type name: str
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def __init__(self, name: str) -> None:
|
def __init__(self, name: str) -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
def greet(self):
|
def greet(self):
|
||||||
'''
|
"""
|
||||||
Returns a greeting.
|
Returns a greeting.
|
||||||
|
|
||||||
:return: The greeting.
|
:return: The greeting.
|
||||||
:rtype: str
|
:rtype: str
|
||||||
'''
|
"""
|
||||||
|
|
||||||
return f'Hi there! My name is {self.name}'
|
return f'Hi there! My name is {self.name}'
|
||||||
|
|
||||||
|
|
||||||
class Dog(Animal):
|
class Dog(Animal):
|
||||||
'''
|
"""
|
||||||
A dog.
|
A dog.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def bark(self) -> None:
|
def bark(self) -> None:
|
||||||
'''
|
"""
|
||||||
Barks.
|
Barks.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
print('Woof!')
|
print('Woof!')
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -12,61 +12,384 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from src.jcloud_docsgen.core.python.arguments import PythonFunctionArgument, PythonArgumentKind
|
|
||||||
from src.jcloud_docsgen.exceptions import InvalidPythonIdentifierError, InvalidPythonAnnotationError, PythonArgumentStructureError
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@pytest.mark.parametrize('name,kind,default,annotation,expected_exception,expected_exception_msg', [
|
from src.jcloud_docsgen.core.python.arguments import (
|
||||||
(None, PythonArgumentKind.NORMAL, None, None, TypeError, 'expected \'str\', got \'NoneType\''),
|
PythonArgumentKind,
|
||||||
(1, PythonArgumentKind.NORMAL, None, None, TypeError, 'expected \'str\', got \'int\''),
|
PythonFunctionArgument,
|
||||||
(42, PythonArgumentKind.NORMAL, None, None, TypeError, 'expected \'str\', got \'int\''),
|
)
|
||||||
(4.2, PythonArgumentKind.NORMAL, None, None, TypeError, 'expected \'str\', got \'float\''),
|
from src.jcloud_docsgen.exceptions import (
|
||||||
(4.2, PythonArgumentKind.NORMAL, None, None, TypeError, 'expected \'str\', got \'float\''),
|
InvalidPythonAnnotationError,
|
||||||
('a', PythonArgumentKind.NORMAL, 1, None, TypeError, 'expected either \'str\' or \'NoneType\', got \'int\''),
|
InvalidPythonIdentifierError,
|
||||||
('a', PythonArgumentKind.NORMAL, None, 1, TypeError, 'expected either \'str\' or \'NoneType\', got \'int\''),
|
PythonArgumentStructureError,
|
||||||
('a', 0, None, None, TypeError, 'expected \'PythonArgumentKind\', got \'int\''),
|
)
|
||||||
('a', PythonArgumentKind.NORMAL, None, '', InvalidPythonAnnotationError, 'invalid annotation'),
|
|
||||||
('', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier'),
|
|
||||||
('.', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: .'),
|
@pytest.mark.parametrize(
|
||||||
('#', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: #'),
|
'name,kind,default,annotation,expected_exception,expected_exception_msg',
|
||||||
('1a', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: 1a'),
|
[
|
||||||
('1_', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: 1_'),
|
(
|
||||||
('1,', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: 1,'),
|
None,
|
||||||
(',', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: ,'),
|
PythonArgumentKind.NORMAL,
|
||||||
(':', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: :'),
|
None,
|
||||||
('-', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: -'),
|
None,
|
||||||
(';', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: ;'),
|
TypeError,
|
||||||
('|', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: |'),
|
"expected 'str', got 'NoneType'",
|
||||||
('<', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: <'),
|
),
|
||||||
('>', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: >'),
|
(
|
||||||
('a,', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: a,'),
|
1,
|
||||||
(',a', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: ,a'),
|
PythonArgumentKind.NORMAL,
|
||||||
('a:', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: a:'),
|
None,
|
||||||
(':a', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: :a'),
|
None,
|
||||||
('a-', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: a-'),
|
TypeError,
|
||||||
('-a', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: -a'),
|
"expected 'str', got 'int'",
|
||||||
('a;', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: a;'),
|
),
|
||||||
(';a', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: ;a'),
|
(
|
||||||
('a|', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: a|'),
|
42,
|
||||||
('|a', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: |a'),
|
PythonArgumentKind.NORMAL,
|
||||||
('a<', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: a<'),
|
None,
|
||||||
('<a', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: <a'),
|
None,
|
||||||
('a>', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: a>'),
|
TypeError,
|
||||||
('>a', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: >a'),
|
"expected 'str', got 'int'",
|
||||||
('class', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: class'),
|
),
|
||||||
('def', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: def'),
|
(
|
||||||
('lambda', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: lambda'),
|
4.2,
|
||||||
('None', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: None'),
|
PythonArgumentKind.NORMAL,
|
||||||
('True', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: True'),
|
None,
|
||||||
('a', PythonArgumentKind.VARARG, '1', None, PythonArgumentStructureError, '* or ** arguments cannot have default values: *a = 1'),
|
None,
|
||||||
('a', PythonArgumentKind.KWARGS, '1', None, PythonArgumentStructureError, '* or ** arguments cannot have default values: **a = 1'),
|
TypeError,
|
||||||
])
|
"expected 'str', got 'float'",
|
||||||
def test_PythonFunctionArgument_exceptions(name, kind, default, annotation, expected_exception, expected_exception_msg):
|
),
|
||||||
|
(
|
||||||
|
4.2,
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
TypeError,
|
||||||
|
"expected 'str', got 'float'",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
1,
|
||||||
|
None,
|
||||||
|
TypeError,
|
||||||
|
"expected either 'str' or 'NoneType', got 'int'",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
1,
|
||||||
|
TypeError,
|
||||||
|
"expected either 'str' or 'NoneType', got 'int'",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a',
|
||||||
|
0,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
TypeError,
|
||||||
|
"expected 'PythonArgumentKind', got 'int'",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
'',
|
||||||
|
InvalidPythonAnnotationError,
|
||||||
|
'invalid annotation',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'.',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: .',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'#',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: #',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'1a',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: 1a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'1_',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: 1_',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'1,',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: 1,',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
',',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: ,',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
':',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: :',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'-',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: -',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
';',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: ;',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'|',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: |',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'<',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: <',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'>',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: >',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a,',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a,',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
',a',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: ,a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a:',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a:',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
':a',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: :a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a-',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a-',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'-a',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: -a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a;',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a;',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
';a',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: ;a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a|',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a|',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'|a',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: |a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a<',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a<',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'<a',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: <a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a>',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a>',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'>a',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: >a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'class',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: class',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'def',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: def',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'lambda',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: lambda',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'None',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: None',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'True',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: True',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.VARARG,
|
||||||
|
'1',
|
||||||
|
None,
|
||||||
|
PythonArgumentStructureError,
|
||||||
|
'* or ** arguments cannot have default values: *a=1',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.KWARGS,
|
||||||
|
'1',
|
||||||
|
None,
|
||||||
|
PythonArgumentStructureError,
|
||||||
|
'* or ** arguments cannot have default values: **a=1',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_PythonFunctionArgument_exceptions(
|
||||||
|
name,
|
||||||
|
kind,
|
||||||
|
default,
|
||||||
|
annotation,
|
||||||
|
expected_exception,
|
||||||
|
expected_exception_msg,
|
||||||
|
):
|
||||||
with pytest.raises(expected_exception) as exc_info:
|
with pytest.raises(expected_exception) as exc_info:
|
||||||
PythonFunctionArgument(name, kind, default, annotation)
|
PythonFunctionArgument(name, kind, default, annotation)
|
||||||
assert str(exc_info.value) == expected_exception_msg
|
assert str(exc_info.value) == expected_exception_msg
|
||||||
|
|
||||||
@pytest.mark.parametrize('name', [
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'name',
|
||||||
|
[
|
||||||
'a',
|
'a',
|
||||||
'_a',
|
'_a',
|
||||||
'a1',
|
'a1',
|
||||||
@@ -83,28 +406,41 @@ def test_PythonFunctionArgument_exceptions(name, kind, default, annotation, expe
|
|||||||
'none',
|
'none',
|
||||||
'true',
|
'true',
|
||||||
'false',
|
'false',
|
||||||
])
|
],
|
||||||
@pytest.mark.parametrize('kind', [
|
)
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'kind',
|
||||||
|
[
|
||||||
PythonArgumentKind.NORMAL,
|
PythonArgumentKind.NORMAL,
|
||||||
PythonArgumentKind.POSITIONAL_ONLY,
|
PythonArgumentKind.POSITIONAL_ONLY,
|
||||||
PythonArgumentKind.KEYWORD_ONLY,
|
PythonArgumentKind.KEYWORD_ONLY,
|
||||||
])
|
],
|
||||||
@pytest.mark.parametrize('default', [
|
)
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'default',
|
||||||
|
[
|
||||||
None,
|
None,
|
||||||
'x',
|
'x',
|
||||||
'1',
|
'1',
|
||||||
None,
|
None,
|
||||||
])
|
],
|
||||||
@pytest.mark.parametrize('annotation', [
|
)
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'annotation',
|
||||||
|
[
|
||||||
None,
|
None,
|
||||||
'a',
|
'a',
|
||||||
'list[int]',
|
'list[int]',
|
||||||
'_',
|
'_',
|
||||||
])
|
],
|
||||||
|
)
|
||||||
def test_PythonFunctionArgument(name, kind, default, annotation):
|
def test_PythonFunctionArgument(name, kind, default, annotation):
|
||||||
PythonFunctionArgument(name, kind, default, annotation)
|
PythonFunctionArgument(name, kind, default, annotation)
|
||||||
|
|
||||||
@pytest.mark.parametrize('name', [
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'name',
|
||||||
|
[
|
||||||
'a',
|
'a',
|
||||||
'_a',
|
'_a',
|
||||||
'a1',
|
'a1',
|
||||||
@@ -121,37 +457,173 @@ def test_PythonFunctionArgument(name, kind, default, annotation):
|
|||||||
'none',
|
'none',
|
||||||
'true',
|
'true',
|
||||||
'false',
|
'false',
|
||||||
])
|
],
|
||||||
@pytest.mark.parametrize('kind', [
|
)
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'kind',
|
||||||
|
[
|
||||||
PythonArgumentKind.VARARG,
|
PythonArgumentKind.VARARG,
|
||||||
PythonArgumentKind.KWARGS,
|
PythonArgumentKind.KWARGS,
|
||||||
])
|
],
|
||||||
@pytest.mark.parametrize('annotation', [
|
)
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'annotation',
|
||||||
|
[
|
||||||
None,
|
None,
|
||||||
'a',
|
'a',
|
||||||
'list[int]',
|
'list[int]',
|
||||||
'_',
|
'_',
|
||||||
])
|
],
|
||||||
|
)
|
||||||
def test_PythonFunctionArgument_asterik(name, kind, annotation):
|
def test_PythonFunctionArgument_asterik(name, kind, annotation):
|
||||||
PythonFunctionArgument(name, kind, None, annotation)
|
PythonFunctionArgument(name, kind, None, annotation)
|
||||||
|
|
||||||
@pytest.mark.parametrize('argument,expected', [
|
|
||||||
(PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, None), 'a'),
|
@pytest.mark.parametrize(
|
||||||
(PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '1', None), 'a = 1'),
|
'argument,expected',
|
||||||
(PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, 'int'), 'a: int'),
|
[
|
||||||
(PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '1', 'int'), 'a: int = 1'),
|
(
|
||||||
(PythonFunctionArgument('a', PythonArgumentKind.POSITIONAL_ONLY, None, None), 'a'),
|
PythonFunctionArgument(
|
||||||
(PythonFunctionArgument('a', PythonArgumentKind.POSITIONAL_ONLY, '1', None), 'a = 1'),
|
'a',
|
||||||
(PythonFunctionArgument('a', PythonArgumentKind.POSITIONAL_ONLY, None, 'int'), 'a: int'),
|
PythonArgumentKind.NORMAL,
|
||||||
(PythonFunctionArgument('a', PythonArgumentKind.POSITIONAL_ONLY, '1', 'int'), 'a: int = 1'),
|
None,
|
||||||
(PythonFunctionArgument('a', PythonArgumentKind.KEYWORD_ONLY, None, None), 'a'),
|
None,
|
||||||
(PythonFunctionArgument('a', PythonArgumentKind.KEYWORD_ONLY, '1', None), 'a = 1'),
|
),
|
||||||
(PythonFunctionArgument('a', PythonArgumentKind.KEYWORD_ONLY, None, 'int'), 'a: int'),
|
'a',
|
||||||
(PythonFunctionArgument('a', PythonArgumentKind.KEYWORD_ONLY, '1', 'int'), 'a: int = 1'),
|
),
|
||||||
(PythonFunctionArgument('a', PythonArgumentKind.VARARG, None, None), '*a'),
|
(
|
||||||
(PythonFunctionArgument('a', PythonArgumentKind.VARARG, None, 'int'), '*a: int'),
|
PythonFunctionArgument(
|
||||||
(PythonFunctionArgument('a', PythonArgumentKind.KWARGS, None, None), '**a'),
|
'a',
|
||||||
(PythonFunctionArgument('a', PythonArgumentKind.KWARGS, None, 'int'), '**a: int'),
|
PythonArgumentKind.NORMAL,
|
||||||
])
|
'1',
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
'a=1',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a', PythonArgumentKind.NORMAL, None, 'int'
|
||||||
|
),
|
||||||
|
'a: int',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
'1',
|
||||||
|
'int',
|
||||||
|
),
|
||||||
|
'a: int = 1',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.POSITIONAL_ONLY,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
'a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.POSITIONAL_ONLY,
|
||||||
|
'1',
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
'a=1',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.POSITIONAL_ONLY,
|
||||||
|
None,
|
||||||
|
'int',
|
||||||
|
),
|
||||||
|
'a: int',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.POSITIONAL_ONLY,
|
||||||
|
'1',
|
||||||
|
'int',
|
||||||
|
),
|
||||||
|
'a: int = 1',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.KEYWORD_ONLY,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
'a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.KEYWORD_ONLY,
|
||||||
|
'1',
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
'a=1',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.KEYWORD_ONLY,
|
||||||
|
None,
|
||||||
|
'int',
|
||||||
|
),
|
||||||
|
'a: int',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.KEYWORD_ONLY,
|
||||||
|
'1',
|
||||||
|
'int',
|
||||||
|
),
|
||||||
|
'a: int = 1',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.VARARG,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
'*a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.VARARG,
|
||||||
|
None,
|
||||||
|
'int',
|
||||||
|
),
|
||||||
|
'*a: int',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.KWARGS,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
'**a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.KWARGS,
|
||||||
|
None,
|
||||||
|
'int',
|
||||||
|
),
|
||||||
|
'**a: int',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_PythonFunctionArgument_signature_repr(argument, expected):
|
def test_PythonFunctionArgument_signature_repr(argument, expected):
|
||||||
assert argument.signature_repr() == expected
|
assert argument.signature_repr() == expected
|
||||||
@@ -12,86 +12,489 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from src.jcloud_docsgen.core.python.definitions import PythonFunctionDefinition, PythonClassDefinition
|
import pytest
|
||||||
from src.jcloud_docsgen.core.python.arguments import PythonFunctionArgument, PythonArgumentKind
|
|
||||||
|
from src.jcloud_docsgen.core.python.arguments import (
|
||||||
|
PythonArgumentKind,
|
||||||
|
PythonFunctionArgument,
|
||||||
|
)
|
||||||
|
from src.jcloud_docsgen.core.python.definitions import (
|
||||||
|
PythonClassDefinition,
|
||||||
|
PythonFunctionDefinition,
|
||||||
|
)
|
||||||
from src.jcloud_docsgen.core.python.docstrings import PythonDocstring
|
from src.jcloud_docsgen.core.python.docstrings import PythonDocstring
|
||||||
from src.jcloud_docsgen.exceptions import InvalidPythonIdentifierError
|
from src.jcloud_docsgen.exceptions import InvalidPythonIdentifierError
|
||||||
from tests.utils.ast_node import ast_node
|
from tests.utils.ast_node import ast_node
|
||||||
import pytest
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('definition,expected', [
|
|
||||||
(PythonClassDefinition('A', [], None, None, []), 'PythonClassDefinition(\'A\', [], None, None, [])'),
|
@pytest.mark.parametrize(
|
||||||
(PythonClassDefinition('A', [], None, PythonDocstring('Hello, World!'), []), 'PythonClassDefinition(\'A\', [], None, PythonDocstring(\'Hello, World!\'), [])'),
|
'definition,expected',
|
||||||
])
|
[
|
||||||
|
(
|
||||||
|
PythonClassDefinition(
|
||||||
|
'A',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
"PythonClassDefinition('A', [], None, None, [])",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonClassDefinition(
|
||||||
|
'A',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
PythonDocstring('Hello, World!'),
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"PythonClassDefinition('A', [], None, "
|
||||||
|
"PythonDocstring('Hello, World!'), [])"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_PythonDefinition_string_representation(definition, expected):
|
def test_PythonDefinition_string_representation(definition, expected):
|
||||||
assert repr(definition) == expected
|
assert repr(definition) == expected
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('name,args,returns,doc,decorators,expected_exception,expected_exception_message', [
|
@pytest.mark.parametrize(
|
||||||
('', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier'),
|
(
|
||||||
('.', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: .'),
|
'name,args,returns,doc,decorators,expect'
|
||||||
('#', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: #'),
|
'ed_exception,expected_exception_message'
|
||||||
('1a', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: 1a'),
|
),
|
||||||
('1_', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: 1_'),
|
[
|
||||||
('1,', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: 1,'),
|
(
|
||||||
(',', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: ,'),
|
'',
|
||||||
(':', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: :'),
|
[],
|
||||||
('-', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: -'),
|
None,
|
||||||
(';', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: ;'),
|
None,
|
||||||
('|', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: |'),
|
[],
|
||||||
('<', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: <'),
|
InvalidPythonIdentifierError,
|
||||||
('>', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: >'),
|
'invalid identifier',
|
||||||
('a,', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: a,'),
|
),
|
||||||
(',a', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: ,a'),
|
(
|
||||||
('a:', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: a:'),
|
'.',
|
||||||
(':a', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: :a'),
|
[],
|
||||||
('a-', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: a-'),
|
None,
|
||||||
('-a', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: -a'),
|
None,
|
||||||
('a;', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: a;'),
|
[],
|
||||||
(';a', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: ;a'),
|
InvalidPythonIdentifierError,
|
||||||
('a|', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: a|'),
|
'invalid identifier: .',
|
||||||
('|a', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: |a'),
|
),
|
||||||
('a<', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: a<'),
|
(
|
||||||
('<a', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: <a'),
|
'#',
|
||||||
('a>', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: a>'),
|
[],
|
||||||
('>a', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: >a'),
|
None,
|
||||||
('class', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: class'),
|
None,
|
||||||
('def', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: def'),
|
[],
|
||||||
('lambda', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: lambda'),
|
InvalidPythonIdentifierError,
|
||||||
('None', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: None'),
|
'invalid identifier: #',
|
||||||
('True', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: True'),
|
),
|
||||||
])
|
(
|
||||||
def test_PythonFunctionDefinition_exceptions(name, args, returns, doc, decorators, expected_exception, expected_exception_message):
|
'1a',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: 1a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'1_',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: 1_',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'1,',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: 1,',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
',',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: ,',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
':',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: :',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'-',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: -',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
';',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: ;',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'|',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: |',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'<',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: <',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'>',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: >',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a,',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a,',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
',a',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: ,a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a:',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a:',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
':a',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: :a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a-',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a-',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'-a',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: -a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a;',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a;',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
';a',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: ;a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a|',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a|',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'|a',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: |a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a<',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a<',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'<a',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: <a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a>',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a>',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'>a',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: >a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'class',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: class',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'def',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: def',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'lambda',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: lambda',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'None',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: None',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'True',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: True',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_PythonFunctionDefinition_exceptions(
|
||||||
|
name,
|
||||||
|
args,
|
||||||
|
returns,
|
||||||
|
doc,
|
||||||
|
decorators,
|
||||||
|
expected_exception,
|
||||||
|
expected_exception_message,
|
||||||
|
):
|
||||||
with pytest.raises(expected_exception) as exc_info:
|
with pytest.raises(expected_exception) as exc_info:
|
||||||
PythonClassDefinition(name, args, returns, doc, decorators)
|
PythonClassDefinition(name, args, returns, doc, decorators)
|
||||||
assert str(exc_info.value) == expected_exception_message
|
assert str(exc_info.value) == expected_exception_message
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('node,expected', [
|
@pytest.mark.parametrize(
|
||||||
(ast_node('@decorator\nclass Class(BaseClass1, BaseClass2):\n\tdef __init__(self, value: object) -> None:\n\t\tself._value = value\n\n\t@property\n\tdef value(self) -> object:\n\t\treturn self._value'), PythonClassDefinition('Class', [
|
'node,expected',
|
||||||
'BaseClass1',
|
[
|
||||||
'BaseClass2'
|
(
|
||||||
], None, ['decorator'], [
|
ast_node(
|
||||||
PythonFunctionDefinition('__init__', [
|
(
|
||||||
PythonFunctionArgument('self', PythonArgumentKind.NORMAL, None, None),
|
'@decorator\nclass Class(BaseClass1, BaseClass2)'
|
||||||
PythonFunctionArgument('value', PythonArgumentKind.NORMAL, None, 'object')
|
':\n\tdef __init__(self, value: object) -> None:'
|
||||||
], 'None', None, []),
|
'\n\t\tself._value = value\n\n\t@property\n\tdef'
|
||||||
PythonFunctionDefinition('value', [
|
' value(self) -> object:\n\t\treturn self._value'
|
||||||
PythonFunctionArgument('self', PythonArgumentKind.NORMAL, None, None)
|
),
|
||||||
], 'object', None, ['property'])
|
),
|
||||||
])),
|
PythonClassDefinition(
|
||||||
(ast_node('class Class: ...'), PythonClassDefinition('Class', [], None, [], [])),
|
'Class',
|
||||||
(ast_node('class Class: \'\'\'docstring\'\'\''), PythonClassDefinition('Class', [], PythonDocstring('docstring'), [], [])),
|
['BaseClass1', 'BaseClass2'],
|
||||||
(ast_node('class Class:\n\tdef __init__(self): ...'), PythonClassDefinition('Class', [], None, [], [
|
None,
|
||||||
PythonFunctionDefinition('__init__', [
|
['decorator'],
|
||||||
PythonFunctionArgument('self', PythonArgumentKind.NORMAL, None, None)
|
[
|
||||||
], None, None, [])
|
PythonFunctionDefinition(
|
||||||
])),
|
'__init__',
|
||||||
(ast_node('class Class:\n\t\'\'\'doc\'\'\'\n\tdef __init__(self): ...'), PythonClassDefinition('Class', [], PythonDocstring('doc'), [], [
|
[
|
||||||
PythonFunctionDefinition('__init__', [
|
PythonFunctionArgument(
|
||||||
PythonFunctionArgument('self', PythonArgumentKind.NORMAL, None, None)
|
'self',
|
||||||
], None, None, [])
|
PythonArgumentKind.NORMAL,
|
||||||
])),
|
None,
|
||||||
])
|
None,
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'value',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
'object',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'None',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
PythonFunctionDefinition(
|
||||||
|
'value',
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'self',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'object',
|
||||||
|
None,
|
||||||
|
['property'],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ast_node('class Class: ...'),
|
||||||
|
PythonClassDefinition(
|
||||||
|
'Class',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ast_node("class Class: '''docstring'''"),
|
||||||
|
PythonClassDefinition(
|
||||||
|
'Class',
|
||||||
|
[],
|
||||||
|
PythonDocstring('docstring'),
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ast_node('class Class:\n\tdef __init__(self): ...'),
|
||||||
|
PythonClassDefinition(
|
||||||
|
'Class',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
PythonFunctionDefinition(
|
||||||
|
'__init__',
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'self',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ast_node("class Class:\n\t'''doc'''\n\tdef __init__(self): ..."),
|
||||||
|
PythonClassDefinition(
|
||||||
|
'Class',
|
||||||
|
[],
|
||||||
|
PythonDocstring('doc'),
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
PythonFunctionDefinition(
|
||||||
|
'__init__',
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'self',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_PythonDefinition_from_node(node, expected):
|
def test_PythonDefinition_from_node(node, expected):
|
||||||
assert PythonClassDefinition.from_node(node) == expected
|
assert PythonClassDefinition.from_node(node) == expected
|
||||||
@@ -12,73 +12,440 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
from src.jcloud_docsgen.core.python.definitions import PythonDefinition
|
from src.jcloud_docsgen.core.python.definitions import PythonDefinition
|
||||||
from src.jcloud_docsgen.core.python.docstrings import PythonDocstring
|
from src.jcloud_docsgen.core.python.docstrings import PythonDocstring
|
||||||
from src.jcloud_docsgen.exceptions import InvalidPythonIdentifierError
|
from src.jcloud_docsgen.exceptions import InvalidPythonIdentifierError
|
||||||
import pytest
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('definition,expected', [
|
|
||||||
(PythonDefinition('a', None, []), 'PythonDefinition(\'a\', None, [])'),
|
@pytest.mark.parametrize(
|
||||||
(PythonDefinition('a', PythonDocstring('Hello, World!'), []), 'PythonDefinition(\'a\', PythonDocstring(\'Hello, World!\'), [])'),
|
'definition,expected',
|
||||||
])
|
[
|
||||||
|
(
|
||||||
|
PythonDefinition(
|
||||||
|
'a',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
"PythonDefinition('a', None, [])",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonDefinition(
|
||||||
|
'a',
|
||||||
|
PythonDocstring('Hello, World!'),
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
"PythonDefinition('a', PythonDocstring('Hello, World!'), [])",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_PythonDefinition_string_representation(definition, expected):
|
def test_PythonDefinition_string_representation(definition, expected):
|
||||||
assert repr(definition) == expected
|
assert repr(definition) == expected
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('name,doc,decorators,expected_exception,expected_exception_message', [
|
@pytest.mark.parametrize(
|
||||||
('', None, [], InvalidPythonIdentifierError, 'invalid identifier'),
|
'name,doc,decorators,expected_exception,expected_exception_message',
|
||||||
('.', None, [], InvalidPythonIdentifierError, 'invalid identifier: .'),
|
[
|
||||||
('#', None, [], InvalidPythonIdentifierError, 'invalid identifier: #'),
|
(
|
||||||
('1a', None, [], InvalidPythonIdentifierError, 'invalid identifier: 1a'),
|
'',
|
||||||
('1_', None, [], InvalidPythonIdentifierError, 'invalid identifier: 1_'),
|
None,
|
||||||
('1,', None, [], InvalidPythonIdentifierError, 'invalid identifier: 1,'),
|
[],
|
||||||
(',', None, [], InvalidPythonIdentifierError, 'invalid identifier: ,'),
|
InvalidPythonIdentifierError,
|
||||||
(':', None, [], InvalidPythonIdentifierError, 'invalid identifier: :'),
|
'invalid identifier',
|
||||||
('-', None, [], InvalidPythonIdentifierError, 'invalid identifier: -'),
|
),
|
||||||
(';', None, [], InvalidPythonIdentifierError, 'invalid identifier: ;'),
|
(
|
||||||
('|', None, [], InvalidPythonIdentifierError, 'invalid identifier: |'),
|
'.',
|
||||||
('<', None, [], InvalidPythonIdentifierError, 'invalid identifier: <'),
|
None,
|
||||||
('>', None, [], InvalidPythonIdentifierError, 'invalid identifier: >'),
|
[],
|
||||||
('a,', None, [], InvalidPythonIdentifierError, 'invalid identifier: a,'),
|
InvalidPythonIdentifierError,
|
||||||
(',a', None, [], InvalidPythonIdentifierError, 'invalid identifier: ,a'),
|
'invalid identifier: .',
|
||||||
('a:', None, [], InvalidPythonIdentifierError, 'invalid identifier: a:'),
|
),
|
||||||
(':a', None, [], InvalidPythonIdentifierError, 'invalid identifier: :a'),
|
(
|
||||||
('a-', None, [], InvalidPythonIdentifierError, 'invalid identifier: a-'),
|
'#',
|
||||||
('-a', None, [], InvalidPythonIdentifierError, 'invalid identifier: -a'),
|
None,
|
||||||
('a;', None, [], InvalidPythonIdentifierError, 'invalid identifier: a;'),
|
[],
|
||||||
(';a', None, [], InvalidPythonIdentifierError, 'invalid identifier: ;a'),
|
InvalidPythonIdentifierError,
|
||||||
('a|', None, [], InvalidPythonIdentifierError, 'invalid identifier: a|'),
|
'invalid identifier: #',
|
||||||
('|a', None, [], InvalidPythonIdentifierError, 'invalid identifier: |a'),
|
),
|
||||||
('a<', None, [], InvalidPythonIdentifierError, 'invalid identifier: a<'),
|
(
|
||||||
('<a', None, [], InvalidPythonIdentifierError, 'invalid identifier: <a'),
|
'1a',
|
||||||
('a>', None, [], InvalidPythonIdentifierError, 'invalid identifier: a>'),
|
None,
|
||||||
('>a', None, [], InvalidPythonIdentifierError, 'invalid identifier: >a'),
|
[],
|
||||||
('class', None, [], InvalidPythonIdentifierError, 'invalid identifier: class'),
|
InvalidPythonIdentifierError,
|
||||||
('def', None, [], InvalidPythonIdentifierError, 'invalid identifier: def'),
|
'invalid identifier: 1a',
|
||||||
('lambda', None, [], InvalidPythonIdentifierError, 'invalid identifier: lambda'),
|
),
|
||||||
('None', None, [], InvalidPythonIdentifierError, 'invalid identifier: None'),
|
(
|
||||||
('True', None, [], InvalidPythonIdentifierError, 'invalid identifier: True'),
|
'1_',
|
||||||
])
|
None,
|
||||||
def test_PythonDefinition_exceptions(name, doc, decorators, expected_exception, expected_exception_message):
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: 1_',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'1,',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: 1,',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
',',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: ,',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
':',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: :',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'-',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: -',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
';',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: ;',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'|',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: |',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'<',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: <',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'>',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: >',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a,',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a,',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
',a',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: ,a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a:',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a:',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
':a',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: :a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a-',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a-',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'-a',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: -a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a;',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a;',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
';a',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: ;a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a|',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a|',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'|a',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: |a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a<',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a<',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'<a',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: <a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a>',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a>',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'>a',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: >a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'class',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: class',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'def',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: def',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'lambda',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: lambda',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'None',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: None',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'True',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: True',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_PythonDefinition_exceptions(
|
||||||
|
name,
|
||||||
|
doc,
|
||||||
|
decorators,
|
||||||
|
expected_exception,
|
||||||
|
expected_exception_message,
|
||||||
|
):
|
||||||
with pytest.raises(expected_exception) as exc_info:
|
with pytest.raises(expected_exception) as exc_info:
|
||||||
PythonDefinition(name, doc, decorators)
|
PythonDefinition(name, doc, decorators)
|
||||||
assert str(exc_info.value) == expected_exception_message
|
assert str(exc_info.value) == expected_exception_message
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('definition1,definition2,expected', [
|
@pytest.mark.parametrize(
|
||||||
(PythonDefinition('a', None, []), PythonDefinition('a', None, []), True),
|
'definition1,definition2,expected',
|
||||||
(PythonDefinition('a', PythonDocstring('doc'), []), PythonDefinition('a', PythonDocstring('doc'), []), True),
|
[
|
||||||
(PythonDefinition('a', PythonDocstring('doc'), ['a']), PythonDefinition('a', PythonDocstring('doc'), ['a']), True),
|
(
|
||||||
(PythonDefinition('a', PythonDocstring('doc'), ['a', 'b']), PythonDefinition('a', PythonDocstring('doc'), ['a', 'b']), True),
|
PythonDefinition(
|
||||||
(PythonDefinition('a', None, []), PythonDefinition('b', None, []), False),
|
'a',
|
||||||
(PythonDefinition('a', PythonDocstring('doc'), []), PythonDefinition('a', None, []), False),
|
None,
|
||||||
(PythonDefinition('a', PythonDocstring('doc'), []), PythonDefinition('a', PythonDocstring('docs'), []), False),
|
[],
|
||||||
(PythonDefinition('a', None, ['a']), PythonDefinition('a', None, ['b']), False),
|
),
|
||||||
(PythonDefinition('a', None, ['a']), PythonDefinition('a', None, []), False),
|
PythonDefinition(
|
||||||
(PythonDefinition('a', None, ['a']), PythonDefinition('a', None, ['a', 'b']), False),
|
'a',
|
||||||
(PythonDefinition('a', None, ['b', 'a']), PythonDefinition('a', None, ['a', 'b']), False),
|
None,
|
||||||
(PythonDefinition('a', PythonDocstring('doc'), []), PythonDefinition('b', None, ['a', 'b']), False),
|
[],
|
||||||
])
|
),
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonDefinition(
|
||||||
|
'a',
|
||||||
|
PythonDocstring('doc'),
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
PythonDefinition(
|
||||||
|
'a',
|
||||||
|
PythonDocstring('doc'),
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonDefinition(
|
||||||
|
'a',
|
||||||
|
PythonDocstring('doc'),
|
||||||
|
['a'],
|
||||||
|
),
|
||||||
|
PythonDefinition(
|
||||||
|
'a',
|
||||||
|
PythonDocstring('doc'),
|
||||||
|
['a'],
|
||||||
|
),
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonDefinition(
|
||||||
|
'a',
|
||||||
|
PythonDocstring('doc'),
|
||||||
|
['a', 'b'],
|
||||||
|
),
|
||||||
|
PythonDefinition(
|
||||||
|
'a',
|
||||||
|
PythonDocstring('doc'),
|
||||||
|
['a', 'b'],
|
||||||
|
),
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonDefinition(
|
||||||
|
'a',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
PythonDefinition(
|
||||||
|
'b',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonDefinition(
|
||||||
|
'a',
|
||||||
|
PythonDocstring('doc'),
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
PythonDefinition(
|
||||||
|
'a',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonDefinition(
|
||||||
|
'a',
|
||||||
|
PythonDocstring('doc'),
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
PythonDefinition(
|
||||||
|
'a',
|
||||||
|
PythonDocstring('docs'),
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonDefinition(
|
||||||
|
'a',
|
||||||
|
None,
|
||||||
|
['a'],
|
||||||
|
),
|
||||||
|
PythonDefinition(
|
||||||
|
'a',
|
||||||
|
None,
|
||||||
|
['b'],
|
||||||
|
),
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonDefinition(
|
||||||
|
'a',
|
||||||
|
None,
|
||||||
|
['a'],
|
||||||
|
),
|
||||||
|
PythonDefinition(
|
||||||
|
'a',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonDefinition(
|
||||||
|
'a',
|
||||||
|
None,
|
||||||
|
['a'],
|
||||||
|
),
|
||||||
|
PythonDefinition(
|
||||||
|
'a',
|
||||||
|
None,
|
||||||
|
['a', 'b'],
|
||||||
|
),
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonDefinition(
|
||||||
|
'a',
|
||||||
|
None,
|
||||||
|
['b', 'a'],
|
||||||
|
),
|
||||||
|
PythonDefinition(
|
||||||
|
'a',
|
||||||
|
None,
|
||||||
|
['a', 'b'],
|
||||||
|
),
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonDefinition(
|
||||||
|
'a',
|
||||||
|
PythonDocstring('doc'),
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
PythonDefinition(
|
||||||
|
'b',
|
||||||
|
None,
|
||||||
|
['a', 'b'],
|
||||||
|
),
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_PythonDefinition___eq__(definition1, definition2, expected):
|
def test_PythonDefinition___eq__(definition1, definition2, expected):
|
||||||
assert (definition1 == definition2) == expected
|
assert (definition1 == definition2) == expected
|
||||||
assert (definition2 == definition1) == expected
|
assert (definition2 == definition1) == expected
|
||||||
@@ -12,76 +12,460 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from src.jcloud_docsgen.core.python.arguments import (
|
||||||
|
PythonArgumentKind,
|
||||||
|
PythonFunctionArgument,
|
||||||
|
)
|
||||||
from src.jcloud_docsgen.core.python.definitions import PythonFunctionDefinition
|
from src.jcloud_docsgen.core.python.definitions import PythonFunctionDefinition
|
||||||
from src.jcloud_docsgen.core.python.arguments import PythonFunctionArgument, PythonArgumentKind
|
|
||||||
from src.jcloud_docsgen.core.python.docstrings import PythonDocstring
|
from src.jcloud_docsgen.core.python.docstrings import PythonDocstring
|
||||||
from src.jcloud_docsgen.exceptions import InvalidPythonIdentifierError
|
from src.jcloud_docsgen.exceptions import InvalidPythonIdentifierError
|
||||||
from tests.utils.ast_node import ast_node
|
from tests.utils.ast_node import ast_node
|
||||||
import pytest
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('definition,expected', [
|
|
||||||
(PythonFunctionDefinition('a', [], None, None, []), 'PythonFunctionDefinition(\'a\', [], None, None, [])'),
|
@pytest.mark.parametrize(
|
||||||
(PythonFunctionDefinition('a', [], None, PythonDocstring('Hello, World!'), []), 'PythonFunctionDefinition(\'a\', [], None, PythonDocstring(\'Hello, World!\'), [])'),
|
'definition,expected',
|
||||||
])
|
[
|
||||||
|
(
|
||||||
|
PythonFunctionDefinition(
|
||||||
|
'a',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
"PythonFunctionDefinition('a', [], None, None, [])",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonFunctionDefinition(
|
||||||
|
'a',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
PythonDocstring('Hello, World!'),
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"PythonFunctionDefinition('a', [], None,"
|
||||||
|
" PythonDocstring('Hello, World!'), [])"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_PythonDefinition_string_representation(definition, expected):
|
def test_PythonDefinition_string_representation(definition, expected):
|
||||||
assert repr(definition) == expected
|
assert repr(definition) == expected
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('name,args,returns,doc,decorators,expected_exception,expected_exception_message', [
|
@pytest.mark.parametrize(
|
||||||
('', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier'),
|
(
|
||||||
('.', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: .'),
|
'name,args,returns,doc,decorators,expect'
|
||||||
('#', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: #'),
|
'ed_exception,expected_exception_message'
|
||||||
('1a', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: 1a'),
|
),
|
||||||
('1_', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: 1_'),
|
[
|
||||||
('1,', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: 1,'),
|
(
|
||||||
(',', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: ,'),
|
'',
|
||||||
(':', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: :'),
|
[],
|
||||||
('-', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: -'),
|
None,
|
||||||
(';', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: ;'),
|
None,
|
||||||
('|', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: |'),
|
[],
|
||||||
('<', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: <'),
|
InvalidPythonIdentifierError,
|
||||||
('>', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: >'),
|
'invalid identifier',
|
||||||
('a,', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: a,'),
|
),
|
||||||
(',a', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: ,a'),
|
(
|
||||||
('a:', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: a:'),
|
'.',
|
||||||
(':a', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: :a'),
|
[],
|
||||||
('a-', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: a-'),
|
None,
|
||||||
('-a', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: -a'),
|
None,
|
||||||
('a;', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: a;'),
|
[],
|
||||||
(';a', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: ;a'),
|
InvalidPythonIdentifierError,
|
||||||
('a|', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: a|'),
|
'invalid identifier: .',
|
||||||
('|a', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: |a'),
|
),
|
||||||
('a<', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: a<'),
|
(
|
||||||
('<a', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: <a'),
|
'#',
|
||||||
('a>', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: a>'),
|
[],
|
||||||
('>a', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: >a'),
|
None,
|
||||||
('class', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: class'),
|
None,
|
||||||
('def', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: def'),
|
[],
|
||||||
('lambda', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: lambda'),
|
InvalidPythonIdentifierError,
|
||||||
('None', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: None'),
|
'invalid identifier: #',
|
||||||
('True', [], None, None, [], InvalidPythonIdentifierError, 'invalid identifier: True'),
|
),
|
||||||
])
|
(
|
||||||
def test_PythonFunctionDefinition_exceptions(name, args, returns, doc, decorators, expected_exception, expected_exception_message):
|
'1a',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: 1a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'1_',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: 1_',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'1,',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: 1,',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
',',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: ,',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
':',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: :',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'-',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: -',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
';',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: ;',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'|',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: |',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'<',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: <',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'>',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: >',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a,',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a,',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
',a',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: ,a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a:',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a:',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
':a',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: :a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a-',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a-',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'-a',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: -a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a;',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a;',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
';a',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: ;a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a|',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a|',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'|a',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: |a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a<',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a<',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'<a',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: <a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'a>',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: a>',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'>a',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: >a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'class',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: class',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'def',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: def',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'lambda',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: lambda',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'None',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: None',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'True',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
InvalidPythonIdentifierError,
|
||||||
|
'invalid identifier: True',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_PythonFunctionDefinition_exceptions(
|
||||||
|
name,
|
||||||
|
args,
|
||||||
|
returns,
|
||||||
|
doc,
|
||||||
|
decorators,
|
||||||
|
expected_exception,
|
||||||
|
expected_exception_message,
|
||||||
|
):
|
||||||
with pytest.raises(expected_exception) as exc_info:
|
with pytest.raises(expected_exception) as exc_info:
|
||||||
PythonFunctionDefinition(name, args, returns, doc, decorators)
|
PythonFunctionDefinition(name, args, returns, doc, decorators)
|
||||||
assert str(exc_info.value) == expected_exception_message
|
assert str(exc_info.value) == expected_exception_message
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('node,expected', [
|
@pytest.mark.parametrize(
|
||||||
(ast_node('def add(a: int, b: int) -> int: return a + b'), PythonFunctionDefinition('add', [
|
'node,expected',
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, 'int'),
|
[
|
||||||
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, None, 'int'),
|
(
|
||||||
], 'int', None, [])),
|
ast_node('def add(a: int, b: int) -> int: return a + b'),
|
||||||
(ast_node('@decorator\ndef add(a: int, b: int) -> int: return a + b'), PythonFunctionDefinition('add', [
|
PythonFunctionDefinition(
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, 'int'),
|
'add',
|
||||||
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, None, 'int'),
|
[
|
||||||
], 'int', None, ['decorator'])),
|
PythonFunctionArgument(
|
||||||
(ast_node('@decorator1\n@decorator2\ndef add(a: int, b: int) -> int: return a + b'), PythonFunctionDefinition('add', [
|
'a',
|
||||||
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, 'int'),
|
PythonArgumentKind.NORMAL,
|
||||||
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, None, 'int'),
|
None,
|
||||||
], 'int', None, ['decorator1', 'decorator2'])),
|
'int',
|
||||||
(ast_node('def func(): ...'), PythonFunctionDefinition('func', [], None, None, [])),
|
),
|
||||||
(ast_node('@decorator\ndef func(): ...'), PythonFunctionDefinition('func', [], None, None, ['decorator'])),
|
PythonFunctionArgument(
|
||||||
])
|
'b',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
'int',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'int',
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ast_node(
|
||||||
|
'@decorator\ndef add(a: int, b: int) -> int: return a + b'
|
||||||
|
),
|
||||||
|
PythonFunctionDefinition(
|
||||||
|
'add',
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
'int',
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'b',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
'int',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'int',
|
||||||
|
None,
|
||||||
|
['decorator'],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ast_node(
|
||||||
|
(
|
||||||
|
'@decorator1\n@decorator2\ndef add(a'
|
||||||
|
': int, b: int) -> int: return a + b'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
PythonFunctionDefinition(
|
||||||
|
'add',
|
||||||
|
[
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'a',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
'int',
|
||||||
|
),
|
||||||
|
PythonFunctionArgument(
|
||||||
|
'b',
|
||||||
|
PythonArgumentKind.NORMAL,
|
||||||
|
None,
|
||||||
|
'int',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'int',
|
||||||
|
None,
|
||||||
|
['decorator1', 'decorator2'],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ast_node('def func(): ...'),
|
||||||
|
PythonFunctionDefinition(
|
||||||
|
'func',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ast_node('@decorator\ndef func(): ...'),
|
||||||
|
PythonFunctionDefinition(
|
||||||
|
'func',
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
['decorator'],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_PythonDefinition_from_node(node, expected):
|
def test_PythonDefinition_from_node(node, expected):
|
||||||
assert PythonFunctionDefinition.from_node(node) == expected
|
assert PythonFunctionDefinition.from_node(node) == expected
|
||||||
@@ -12,20 +12,29 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from src.jcloud_docsgen.core.python.namespaces import PythonModuleNamespace
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from src.jcloud_docsgen.core.python.namespaces import PythonModuleNamespace
|
||||||
|
|
||||||
|
|
||||||
class StrSubclass(str): ...
|
class StrSubclass(str): ...
|
||||||
|
|
||||||
@pytest.mark.parametrize('namespace,expected_name', [
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'namespace,expected_name',
|
||||||
|
[
|
||||||
(PythonModuleNamespace('a'), 'a'),
|
(PythonModuleNamespace('a'), 'a'),
|
||||||
(PythonModuleNamespace('1'), '1'),
|
(PythonModuleNamespace('1'), '1'),
|
||||||
(PythonModuleNamespace(StrSubclass('a')), StrSubclass('a')),
|
(PythonModuleNamespace(StrSubclass('a')), StrSubclass('a')),
|
||||||
])
|
],
|
||||||
|
)
|
||||||
def test_PythonModuleNamespace_name_attribute(namespace, expected_name):
|
def test_PythonModuleNamespace_name_attribute(namespace, expected_name):
|
||||||
assert namespace.name == expected_name
|
assert namespace.name == expected_name
|
||||||
|
|
||||||
@pytest.mark.parametrize('namespace1,namespace2,expected', [
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'namespace1,namespace2,expected',
|
||||||
|
[
|
||||||
(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('1'), PythonModuleNamespace('1'), True),
|
||||||
@@ -33,15 +42,23 @@ def test_PythonModuleNamespace_name_attribute(namespace, expected_name):
|
|||||||
(PythonModuleNamespace('a'), PythonModuleNamespace('b'), False),
|
(PythonModuleNamespace('a'), PythonModuleNamespace('b'), False),
|
||||||
(PythonModuleNamespace('0'), PythonModuleNamespace('-0'), False),
|
(PythonModuleNamespace('0'), PythonModuleNamespace('-0'), False),
|
||||||
(PythonModuleNamespace('1'), PythonModuleNamespace('a'), False),
|
(PythonModuleNamespace('1'), PythonModuleNamespace('a'), False),
|
||||||
])
|
],
|
||||||
|
)
|
||||||
def test_PythonModuleNamespace___eq__(namespace1, namespace2, expected):
|
def test_PythonModuleNamespace___eq__(namespace1, namespace2, expected):
|
||||||
assert (namespace1 == namespace2) == expected
|
assert (namespace1 == namespace2) == expected
|
||||||
assert (namespace2 == namespace1) == expected
|
assert (namespace2 == namespace1) == expected
|
||||||
|
|
||||||
@pytest.mark.parametrize('namespace,expected', [
|
|
||||||
(PythonModuleNamespace('a'), 'PythonModuleNamespace(\'a\')'),
|
@pytest.mark.parametrize(
|
||||||
(PythonModuleNamespace('1'), 'PythonModuleNamespace(\'1\')'),
|
'namespace,expected',
|
||||||
(PythonModuleNamespace(StrSubclass('a')), 'PythonModuleNamespace(\'a\')'),
|
[
|
||||||
])
|
(PythonModuleNamespace('a'), "PythonModuleNamespace('a')"),
|
||||||
|
(PythonModuleNamespace('1'), "PythonModuleNamespace('1')"),
|
||||||
|
(
|
||||||
|
PythonModuleNamespace(StrSubclass('a')),
|
||||||
|
"PythonModuleNamespace('a')",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_PythonModuleNamespace_string_representation(namespace, expected):
|
def test_PythonModuleNamespace_string_representation(namespace, expected):
|
||||||
assert repr(namespace) == expected
|
assert repr(namespace) == expected
|
||||||
@@ -12,23 +12,33 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from src.jcloud_docsgen.core.python.namespaces import PythonNamespace
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from src.jcloud_docsgen.core.python.namespaces import PythonNamespace
|
||||||
|
|
||||||
|
|
||||||
class StrSubclass(str): ...
|
class StrSubclass(str): ...
|
||||||
|
|
||||||
@pytest.mark.parametrize('namespace,expected_name', [
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'namespace,expected_name',
|
||||||
|
[
|
||||||
(PythonNamespace('a'), 'a'),
|
(PythonNamespace('a'), 'a'),
|
||||||
(PythonNamespace('1'), '1'),
|
(PythonNamespace('1'), '1'),
|
||||||
(PythonNamespace(StrSubclass('a')), StrSubclass('a')),
|
(PythonNamespace(StrSubclass('a')), StrSubclass('a')),
|
||||||
])
|
],
|
||||||
|
)
|
||||||
def test_PythonNamespace_name_attribute(namespace, expected_name):
|
def test_PythonNamespace_name_attribute(namespace, expected_name):
|
||||||
assert namespace.name == expected_name
|
assert namespace.name == expected_name
|
||||||
|
|
||||||
@pytest.mark.parametrize('namespace,expected', [
|
|
||||||
(PythonNamespace('a'), 'PythonNamespace(\'a\')'),
|
@pytest.mark.parametrize(
|
||||||
(PythonNamespace('1'), 'PythonNamespace(\'1\')'),
|
'namespace,expected',
|
||||||
(PythonNamespace(StrSubclass('a')), 'PythonNamespace(\'a\')'),
|
[
|
||||||
])
|
(PythonNamespace('a'), "PythonNamespace('a')"),
|
||||||
|
(PythonNamespace('1'), "PythonNamespace('1')"),
|
||||||
|
(PythonNamespace(StrSubclass('a')), "PythonNamespace('a')"),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_PythonNamespace_string_representation(namespace, expected):
|
def test_PythonNamespace_string_representation(namespace, expected):
|
||||||
assert repr(namespace) == expected
|
assert repr(namespace) == expected
|
||||||
@@ -12,24 +12,58 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from src.jcloud_docsgen.core.python.namespaces import PythonPackageNamespace, PythonModuleNamespace
|
|
||||||
import pytest
|
import pytest
|
||||||
from src.jcloud_docsgen.exceptions import NamespaceNotFoundError, InvalidNamespaceError
|
|
||||||
|
from src.jcloud_docsgen.core.python.namespaces import (
|
||||||
|
PythonModuleNamespace,
|
||||||
|
PythonPackageNamespace,
|
||||||
|
)
|
||||||
|
from src.jcloud_docsgen.exceptions import (
|
||||||
|
InvalidNamespaceError,
|
||||||
|
NamespaceNotFoundError,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class StrSubclass(str): ...
|
class StrSubclass(str): ...
|
||||||
|
|
||||||
@pytest.mark.parametrize('namespace,expected_name', [
|
|
||||||
(PythonPackageNamespace('a', []), 'a'),
|
@pytest.mark.parametrize(
|
||||||
(PythonPackageNamespace('1', []), '1'),
|
'namespace,expected_name',
|
||||||
(PythonPackageNamespace(StrSubclass('a'), []), StrSubclass('a')),
|
[
|
||||||
])
|
(
|
||||||
|
PythonPackageNamespace(
|
||||||
|
'a',
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
'a',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonPackageNamespace(
|
||||||
|
'1',
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
'1',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonPackageNamespace(
|
||||||
|
StrSubclass('a'),
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
StrSubclass('a'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_PythonPackageNamespace_name_attribute(namespace, expected_name):
|
def test_PythonPackageNamespace_name_attribute(namespace, expected_name):
|
||||||
assert namespace.name == expected_name
|
assert namespace.name == expected_name
|
||||||
|
|
||||||
|
|
||||||
namespace_b = PythonModuleNamespace('b')
|
namespace_b = PythonModuleNamespace('b')
|
||||||
namespace_a = PythonPackageNamespace('a', [
|
namespace_a = PythonPackageNamespace(
|
||||||
namespace_b
|
'a',
|
||||||
])
|
[
|
||||||
|
namespace_b,
|
||||||
|
],
|
||||||
|
)
|
||||||
namespace_c = PythonModuleNamespace('c')
|
namespace_c = PythonModuleNamespace('c')
|
||||||
namespace_k = PythonModuleNamespace('k')
|
namespace_k = PythonModuleNamespace('k')
|
||||||
namespace_j = PythonPackageNamespace('j', [namespace_k])
|
namespace_j = PythonPackageNamespace('j', [namespace_k])
|
||||||
@@ -40,69 +74,247 @@ namespace_f = PythonPackageNamespace('f', [namespace_g])
|
|||||||
namespace_e = PythonPackageNamespace('e', [namespace_f])
|
namespace_e = PythonPackageNamespace('e', [namespace_f])
|
||||||
namespace_d = PythonPackageNamespace('d', [namespace_e])
|
namespace_d = PythonPackageNamespace('d', [namespace_e])
|
||||||
|
|
||||||
@pytest.mark.parametrize('namespace,sub_namespaces,expected', [
|
|
||||||
(PythonPackageNamespace('name', [
|
@pytest.mark.parametrize(
|
||||||
|
'namespace,sub_namespaces,expected',
|
||||||
|
[
|
||||||
|
(
|
||||||
|
PythonPackageNamespace(
|
||||||
|
'name',
|
||||||
|
[namespace_a, namespace_c],
|
||||||
|
),
|
||||||
|
['c'],
|
||||||
|
namespace_c,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonPackageNamespace(
|
||||||
|
'name',
|
||||||
|
[namespace_a, namespace_c],
|
||||||
|
),
|
||||||
|
['a'],
|
||||||
namespace_a,
|
namespace_a,
|
||||||
namespace_c
|
),
|
||||||
]), ['c'], namespace_c),
|
(
|
||||||
(PythonPackageNamespace('name', [
|
PythonPackageNamespace(
|
||||||
namespace_a,
|
'name',
|
||||||
namespace_c
|
[namespace_a, namespace_c],
|
||||||
]), ['a'], namespace_a),
|
),
|
||||||
(PythonPackageNamespace('name', [
|
['a', 'b'],
|
||||||
namespace_a,
|
namespace_b,
|
||||||
namespace_c
|
),
|
||||||
]), ['a', 'b'], namespace_b),
|
(
|
||||||
(namespace_d, ['e', 'f', 'g', 'h', 'i'], namespace_i),
|
namespace_d,
|
||||||
(namespace_d, ['e', 'f', 'g', 'h', 'i', 'j'], namespace_j),
|
['e', 'f', 'g', 'h', 'i'],
|
||||||
(namespace_d, ['e', 'f', 'g', 'h', 'i', 'j', 'k'], namespace_k),
|
namespace_i,
|
||||||
])
|
),
|
||||||
def test_PythonPackageNamespace_namespace(namespace: PythonPackageNamespace, sub_namespaces, expected):
|
(
|
||||||
|
namespace_d,
|
||||||
|
['e', 'f', 'g', 'h', 'i', 'j'],
|
||||||
|
namespace_j,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
namespace_d,
|
||||||
|
['e', 'f', 'g', 'h', 'i', 'j', 'k'],
|
||||||
|
namespace_k,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_PythonPackageNamespace_namespace(
|
||||||
|
namespace: PythonPackageNamespace,
|
||||||
|
sub_namespaces,
|
||||||
|
expected,
|
||||||
|
):
|
||||||
assert namespace.namespace(sub_namespaces) == expected
|
assert namespace.namespace(sub_namespaces) == expected
|
||||||
|
|
||||||
@pytest.mark.parametrize('namespace,sub_namespaces,expected_exception,expected_exception_msg', [
|
|
||||||
(namespace_a, ['c'], NamespaceNotFoundError, 'no such namespace: c'),
|
@pytest.mark.parametrize(
|
||||||
(namespace_h, ['i', 'k'], NamespaceNotFoundError, 'no such namespace: k'),
|
'namespace,sub_namespaces,expected_exception,expected_exception_msg',
|
||||||
(namespace_a, ['b', ''], InvalidNamespaceError, 'invalid namespace'),
|
[
|
||||||
(namespace_a, ['', 'b'], InvalidNamespaceError, 'invalid namespace'),
|
(
|
||||||
(namespace_a, ['b', '', 'b'], InvalidNamespaceError, 'invalid namespace'),
|
namespace_a,
|
||||||
])
|
['c'],
|
||||||
def test_PythonPackageNamespace_namespace_exceptions(namespace, sub_namespaces, expected_exception, expected_exception_msg):
|
NamespaceNotFoundError,
|
||||||
|
'no such namespace: c',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
namespace_h,
|
||||||
|
['i', 'k'],
|
||||||
|
NamespaceNotFoundError,
|
||||||
|
'no such namespace: k',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
namespace_a,
|
||||||
|
['b', ''],
|
||||||
|
InvalidNamespaceError,
|
||||||
|
'invalid namespace',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
namespace_a,
|
||||||
|
['', 'b'],
|
||||||
|
InvalidNamespaceError,
|
||||||
|
'invalid namespace',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
namespace_a,
|
||||||
|
['b', '', 'b'],
|
||||||
|
InvalidNamespaceError,
|
||||||
|
'invalid namespace',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_PythonPackageNamespace_namespace_exceptions(
|
||||||
|
namespace,
|
||||||
|
sub_namespaces,
|
||||||
|
expected_exception,
|
||||||
|
expected_exception_msg,
|
||||||
|
):
|
||||||
with pytest.raises(expected_exception) as exc_info:
|
with pytest.raises(expected_exception) as exc_info:
|
||||||
namespace.namespace(sub_namespaces)
|
namespace.namespace(sub_namespaces)
|
||||||
assert str(exc_info.value) == expected_exception_msg
|
assert str(exc_info.value) == expected_exception_msg
|
||||||
|
|
||||||
@pytest.mark.parametrize('namespace,expected', [
|
|
||||||
(PythonPackageNamespace('a', [PythonModuleNamespace('b')]), {'b': 'b'}),
|
@pytest.mark.parametrize(
|
||||||
(PythonPackageNamespace('a', [PythonModuleNamespace('b'), PythonPackageNamespace('c', [PythonModuleNamespace('d')])]), {'b': 'b', 'c': {'d': 'd'}}),
|
'namespace,expected',
|
||||||
(PythonPackageNamespace('a', []), {})
|
[
|
||||||
])
|
(
|
||||||
|
PythonPackageNamespace(
|
||||||
|
'a',
|
||||||
|
[PythonModuleNamespace('b')],
|
||||||
|
),
|
||||||
|
{'b': 'b'},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonPackageNamespace(
|
||||||
|
'a',
|
||||||
|
[
|
||||||
|
PythonModuleNamespace('b'),
|
||||||
|
PythonPackageNamespace(
|
||||||
|
'c',
|
||||||
|
[PythonModuleNamespace('d')],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
{
|
||||||
|
'b': 'b',
|
||||||
|
'c': {'d': 'd'},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonPackageNamespace('a', []),
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_PythonPackageNamespace_sub_namespace_names(namespace, expected):
|
def test_PythonPackageNamespace_sub_namespace_names(namespace, expected):
|
||||||
assert namespace.sub_namespace_names() == expected
|
assert namespace.sub_namespace_names() == expected
|
||||||
|
|
||||||
@pytest.mark.parametrize('namespace1,namespace2,expected', [
|
|
||||||
(PythonPackageNamespace('a', [PythonModuleNamespace('b')]), PythonPackageNamespace('a', [PythonModuleNamespace('b')]), True),
|
@pytest.mark.parametrize(
|
||||||
(PythonPackageNamespace('a', [PythonModuleNamespace('b'), PythonPackageNamespace('c', [PythonModuleNamespace('d')])]), PythonPackageNamespace('a', [PythonModuleNamespace('b'), PythonPackageNamespace('c', [PythonModuleNamespace('d')])]), True),
|
'namespace1,namespace2,expected',
|
||||||
(PythonPackageNamespace('a', []), PythonPackageNamespace('a', []), True),
|
[
|
||||||
(PythonPackageNamespace('a', []), PythonPackageNamespace('b', []), False),
|
(
|
||||||
])
|
PythonPackageNamespace(
|
||||||
|
'a',
|
||||||
|
[PythonModuleNamespace('b')],
|
||||||
|
),
|
||||||
|
PythonPackageNamespace(
|
||||||
|
'a',
|
||||||
|
[PythonModuleNamespace('b')],
|
||||||
|
),
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonPackageNamespace(
|
||||||
|
'a',
|
||||||
|
[
|
||||||
|
PythonModuleNamespace('b'),
|
||||||
|
PythonPackageNamespace(
|
||||||
|
'c',
|
||||||
|
[PythonModuleNamespace('d')],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
PythonPackageNamespace(
|
||||||
|
'a',
|
||||||
|
[
|
||||||
|
PythonModuleNamespace('b'),
|
||||||
|
PythonPackageNamespace(
|
||||||
|
'c',
|
||||||
|
[PythonModuleNamespace('d')],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonPackageNamespace('a', []),
|
||||||
|
PythonPackageNamespace('a', []),
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonPackageNamespace('a', []),
|
||||||
|
PythonPackageNamespace('b', []),
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_PythonPackageNamespace___eq__(namespace1, namespace2, expected):
|
def test_PythonPackageNamespace___eq__(namespace1, namespace2, expected):
|
||||||
assert (namespace1 == namespace2) == expected
|
assert (namespace1 == namespace2) == expected
|
||||||
assert (namespace2 == namespace1) == expected
|
assert (namespace2 == namespace1) == expected
|
||||||
|
|
||||||
@pytest.mark.parametrize('namespace,expected', [
|
|
||||||
(PythonPackageNamespace('a', []), 'PythonPackageNamespace(\'a\', [])'),
|
@pytest.mark.parametrize(
|
||||||
(PythonPackageNamespace('1', []), 'PythonPackageNamespace(\'1\', [])'),
|
'namespace,expected',
|
||||||
(PythonPackageNamespace(StrSubclass('a'), []), 'PythonPackageNamespace(\'a\', [])'),
|
[
|
||||||
(namespace_a, 'PythonPackageNamespace(\'a\', [PythonModuleNamespace(\'b\')])'),
|
(
|
||||||
(namespace_d, 'PythonPackageNamespace(\'d\', [PythonPackageNamespace(\'e\', [PythonPackageNamespace(\'f\', [PythonPackageNamespace(\'g\', [PythonPackageNamespace(\'h\', [PythonPackageNamespace(\'i\', [PythonPackageNamespace(\'j\', [PythonModuleNamespace(\'k\')])])])])])])])')
|
PythonPackageNamespace('a', []),
|
||||||
])
|
"PythonPackageNamespace('a', [])",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonPackageNamespace('1', []),
|
||||||
|
"PythonPackageNamespace('1', [])",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PythonPackageNamespace(StrSubclass('a'), []),
|
||||||
|
"PythonPackageNamespace('a', [])",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
namespace_a,
|
||||||
|
"PythonPackageNamespace('a', [PythonModuleNamespace('b')])",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
namespace_d,
|
||||||
|
(
|
||||||
|
"PythonPackageNamespace('d', [PythonPackageNamespac"
|
||||||
|
"e('e', [PythonPackageNamespace('f', [PythonPacka"
|
||||||
|
"geNamespace('g', [PythonPackageNamespace('h', [P"
|
||||||
|
"ythonPackageNamespace('i', [PythonPackageNamespace"
|
||||||
|
"('j', [PythonModuleNamespace('k')])])])])])])])"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_PythonPackageNamespace_string_representation(namespace, expected):
|
def test_PythonPackageNamespace_string_representation(namespace, expected):
|
||||||
assert repr(namespace) == expected
|
assert repr(namespace) == expected
|
||||||
|
|
||||||
@pytest.mark.parametrize('namespace,new_namespace,expected', [
|
|
||||||
(PythonPackageNamespace('a', []), PythonModuleNamespace('b'), PythonPackageNamespace('a', [PythonModuleNamespace('b')]))
|
@pytest.mark.parametrize(
|
||||||
])
|
'namespace,new_namespace,expected',
|
||||||
def test_PythonPackageNamespace___getitem__(namespace, new_namespace, expected):
|
[
|
||||||
|
(
|
||||||
|
PythonPackageNamespace('a', []),
|
||||||
|
PythonModuleNamespace('b'),
|
||||||
|
PythonPackageNamespace(
|
||||||
|
'a',
|
||||||
|
[PythonModuleNamespace('b')],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_PythonPackageNamespace_add(
|
||||||
|
namespace,
|
||||||
|
new_namespace,
|
||||||
|
expected,
|
||||||
|
):
|
||||||
namespace.add(new_namespace)
|
namespace.add(new_namespace)
|
||||||
assert namespace == expected
|
assert namespace == expected
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
from src.jcloud_docsgen.utils import ExistingDirectory
|
|
||||||
import pytest
|
|
||||||
import pathlib
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('path,expected', [
|
|
||||||
('tests/unit/utils/test_directory/', 'tests/unit/utils/test_directory'),
|
|
||||||
('tests/unit/utils/test_directory', 'tests/unit/utils/test_directory'),
|
|
||||||
('tests/unit/utils/', 'tests/unit/utils'),
|
|
||||||
('tests/unit/utils', 'tests/unit/utils'),
|
|
||||||
('/', '/'),
|
|
||||||
('./', '.'),
|
|
||||||
('.', '.'),
|
|
||||||
('../', '..'),
|
|
||||||
('..', '..'),
|
|
||||||
])
|
|
||||||
def test_ExistingDirectory(path, expected):
|
|
||||||
assert ExistingDirectory(path).as_posix() == expected
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('path,expected_exception,expected_exception_message', [
|
|
||||||
('tests/unit/utils/does_not_exist/', FileNotFoundError, '[Errno 2] no such file or directory: \'tests/unit/utils/does_not_exist/\''),
|
|
||||||
('tests/unit/utils/does_not_exist', FileNotFoundError, '[Errno 2] no such file or directory: \'tests/unit/utils/does_not_exist\''),
|
|
||||||
('', FileNotFoundError, '[Errno 2] no such file or directory: \'\''),
|
|
||||||
('README.md', NotADirectoryError, '[Errno 20] not a directory: \'README.md\''),
|
|
||||||
])
|
|
||||||
def test_ExistingDirectory_exceptions(path, expected_exception, expected_exception_message):
|
|
||||||
with pytest.raises(expected_exception) as exc_info:
|
|
||||||
ExistingDirectory(path)
|
|
||||||
assert str(exc_info.value) == expected_exception_message
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
from src.jcloud_docsgen.utils import ExistingFile
|
|
||||||
import pytest
|
|
||||||
import pathlib
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('path,expected', [
|
|
||||||
('tests/unit/utils/test_file', 'tests/unit/utils/test_file'),
|
|
||||||
])
|
|
||||||
def test_ExistingDirectory(path, expected):
|
|
||||||
assert ExistingFile(path).as_posix() == expected
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('path,expected_exception,expected_exception_message', [
|
|
||||||
('tests/unit/utils/does_not_exist', FileNotFoundError, '[Errno 2] no such file or directory: \'tests/unit/utils/does_not_exist\''),
|
|
||||||
('', FileNotFoundError, '[Errno 2] no such file or directory: \'\''),
|
|
||||||
('tests/unit/utils/test_directory', IsADirectoryError, '[Errno 21] is a directory: \'tests/unit/utils/test_directory\''),
|
|
||||||
('.', IsADirectoryError, '[Errno 21] is a directory: \'.\''),
|
|
||||||
('./', IsADirectoryError, '[Errno 21] is a directory: \'./\''),
|
|
||||||
])
|
|
||||||
def test_ExistingDirectory_exceptions(path, expected_exception, expected_exception_message):
|
|
||||||
with pytest.raises(expected_exception) as exc_info:
|
|
||||||
ExistingFile(path)
|
|
||||||
assert str(exc_info.value) == expected_exception_message
|
|
||||||
@@ -12,32 +12,69 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from src.jcloud_docsgen.utils import assert_that_is_instance
|
|
||||||
import pytest
|
|
||||||
import types
|
import types
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from src.jcloud_docsgen.utils import assert_that_is_instance
|
||||||
|
|
||||||
|
|
||||||
class TestType: ...
|
class TestType: ...
|
||||||
|
|
||||||
|
|
||||||
TestType.__name__ = 'NOT TestType'
|
TestType.__name__ = 'NOT TestType'
|
||||||
|
|
||||||
@pytest.mark.parametrize('obj,class_or_tuple', [
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'obj,class_or_tuple',
|
||||||
|
[
|
||||||
(1, int),
|
(1, int),
|
||||||
(1, (int,)),
|
(1, (int,)),
|
||||||
(1, str | int),
|
(1, str | int),
|
||||||
(1, int | str | list),
|
(1, int | str | list),
|
||||||
(TestType(), TestType),
|
(TestType(), TestType),
|
||||||
(None, types.NoneType),
|
(None, types.NoneType),
|
||||||
])
|
],
|
||||||
|
)
|
||||||
def test_assert_that_is_instance(obj, class_or_tuple):
|
def test_assert_that_is_instance(obj, class_or_tuple):
|
||||||
assert_that_is_instance(obj, class_or_tuple)
|
assert_that_is_instance(obj, class_or_tuple)
|
||||||
|
|
||||||
@pytest.mark.parametrize('obj,class_or_tuple,expected_exception_msg', [
|
|
||||||
(1, str, 'expected \'str\', got \'int\''),
|
@pytest.mark.parametrize(
|
||||||
(1, (str,), 'expected \'str\', got \'int\''),
|
'obj,class_or_tuple,expected_exception_msg',
|
||||||
(1, str | float, 'expected either \'str\' or \'float\', got \'int\''),
|
[
|
||||||
(1, str | float | list, 'expected either \'str\', \'float\' or \'list\', got \'int\''),
|
(
|
||||||
(1, TestType, 'expected \'NOT TestType\', got \'int\''),
|
1,
|
||||||
])
|
str,
|
||||||
def test_assert_that_is_instance_exceptions(obj, class_or_tuple, expected_exception_msg):
|
"expected 'str', got 'int'",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
1,
|
||||||
|
(str,),
|
||||||
|
"expected 'str', got 'int'",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
1,
|
||||||
|
str | float,
|
||||||
|
"expected either 'str' or 'float', got 'int'",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
1,
|
||||||
|
str | float | list,
|
||||||
|
"expected either 'str', 'float' or 'list', got 'int'",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
1,
|
||||||
|
TestType,
|
||||||
|
"expected 'NOT TestType', got 'int'",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_assert_that_is_instance_exceptions(
|
||||||
|
obj,
|
||||||
|
class_or_tuple,
|
||||||
|
expected_exception_msg,
|
||||||
|
):
|
||||||
with pytest.raises(TypeError) as exc_info:
|
with pytest.raises(TypeError) as exc_info:
|
||||||
assert_that_is_instance(obj, class_or_tuple)
|
assert_that_is_instance(obj, class_or_tuple)
|
||||||
assert str(exc_info.value) == expected_exception_msg
|
assert str(exc_info.value) == expected_exception_msg
|
||||||
@@ -12,11 +12,16 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from src.jcloud_docsgen.utils import get_relative_path_segments
|
|
||||||
import pytest
|
|
||||||
import pathlib
|
import pathlib
|
||||||
|
|
||||||
@pytest.mark.parametrize('path,root,expected', [
|
import pytest
|
||||||
|
|
||||||
|
from src.jcloud_docsgen.utils import get_relative_path_segments
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'path,root,expected',
|
||||||
|
[
|
||||||
(pathlib.Path('/'), pathlib.Path('/'), []),
|
(pathlib.Path('/'), pathlib.Path('/'), []),
|
||||||
(pathlib.Path('/a'), pathlib.Path('/'), ['a']),
|
(pathlib.Path('/a'), pathlib.Path('/'), ['a']),
|
||||||
(pathlib.Path('/a/'), pathlib.Path('/'), ['a']),
|
(pathlib.Path('/a/'), pathlib.Path('/'), ['a']),
|
||||||
@@ -34,7 +39,6 @@ import pathlib
|
|||||||
(pathlib.Path('/a/b/'), pathlib.Path('/a/b'), []),
|
(pathlib.Path('/a/b/'), pathlib.Path('/a/b'), []),
|
||||||
(pathlib.Path('/a/b'), pathlib.Path('/a/b/'), []),
|
(pathlib.Path('/a/b'), pathlib.Path('/a/b/'), []),
|
||||||
(pathlib.Path('/a/b/'), pathlib.Path('/a/b/'), []),
|
(pathlib.Path('/a/b/'), pathlib.Path('/a/b/'), []),
|
||||||
|
|
||||||
(pathlib.Path('./'), pathlib.Path('./'), []),
|
(pathlib.Path('./'), pathlib.Path('./'), []),
|
||||||
(pathlib.Path('./a'), pathlib.Path('./'), ['a']),
|
(pathlib.Path('./a'), pathlib.Path('./'), ['a']),
|
||||||
(pathlib.Path('./a/'), pathlib.Path('./'), ['a']),
|
(pathlib.Path('./a/'), pathlib.Path('./'), ['a']),
|
||||||
@@ -52,7 +56,6 @@ import pathlib
|
|||||||
(pathlib.Path('./a/b/'), pathlib.Path('./a/b'), []),
|
(pathlib.Path('./a/b/'), pathlib.Path('./a/b'), []),
|
||||||
(pathlib.Path('./a/b'), pathlib.Path('./a/b/'), []),
|
(pathlib.Path('./a/b'), pathlib.Path('./a/b/'), []),
|
||||||
(pathlib.Path('./a/b/'), pathlib.Path('./a/b/'), []),
|
(pathlib.Path('./a/b/'), pathlib.Path('./a/b/'), []),
|
||||||
|
|
||||||
(pathlib.Path(''), pathlib.Path(''), []),
|
(pathlib.Path(''), pathlib.Path(''), []),
|
||||||
(pathlib.Path('a'), pathlib.Path(''), ['a']),
|
(pathlib.Path('a'), pathlib.Path(''), ['a']),
|
||||||
(pathlib.Path('a/'), pathlib.Path(''), ['a']),
|
(pathlib.Path('a/'), pathlib.Path(''), ['a']),
|
||||||
@@ -70,7 +73,7 @@ import pathlib
|
|||||||
(pathlib.Path('a/b/'), pathlib.Path('a/b'), []),
|
(pathlib.Path('a/b/'), pathlib.Path('a/b'), []),
|
||||||
(pathlib.Path('a/b'), pathlib.Path('a/b/'), []),
|
(pathlib.Path('a/b'), pathlib.Path('a/b/'), []),
|
||||||
(pathlib.Path('a/b/'), pathlib.Path('a/b/'), []),
|
(pathlib.Path('a/b/'), pathlib.Path('a/b/'), []),
|
||||||
|
],
|
||||||
])
|
)
|
||||||
def test_get_relative_path_segments(path, root, expected):
|
def test_get_relative_path_segments(path, root, expected):
|
||||||
assert get_relative_path_segments(path, root) == expected
|
assert get_relative_path_segments(path, root) == expected
|
||||||
@@ -12,13 +12,17 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from src.jcloud_docsgen.utils import human_readable_list
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@pytest.mark.parametrize('ls,final_separator,quotation_mark,expected', [
|
from src.jcloud_docsgen.utils import human_readable_list
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'ls,final_separator,quotation_mark,expected',
|
||||||
|
[
|
||||||
([], '', '', ''),
|
([], '', '', ''),
|
||||||
([], 'and', '', ''),
|
([], 'and', '', ''),
|
||||||
([], 'and', '\'', ''),
|
([], 'and', "'", ''),
|
||||||
([1], '', '', '1'),
|
([1], '', '', '1'),
|
||||||
([-1], '', '', '-1'),
|
([-1], '', '', '-1'),
|
||||||
([0], '', '', '0'),
|
([0], '', '', '0'),
|
||||||
@@ -29,26 +33,32 @@ import pytest
|
|||||||
(['a'], '', '', 'a'),
|
(['a'], '', '', 'a'),
|
||||||
([1], 'and', '', '1'),
|
([1], 'and', '', '1'),
|
||||||
(['a'], 'and', '', 'a'),
|
(['a'], 'and', '', 'a'),
|
||||||
([1], 'and', '\'', '\'1\''),
|
([1], 'and', "'", "'1'"),
|
||||||
(['a'], 'and', '\'', '\'a\''),
|
(['a'], 'and', "'", "'a'"),
|
||||||
([1, 2], 'and', '', '1 and 2'),
|
([1, 2], 'and', '', '1 and 2'),
|
||||||
([1, 2], 'and', '\'', '\'1\' and \'2\''),
|
([1, 2], 'and', "'", "'1' and '2'"),
|
||||||
([1, 'a'], 'and', '', '1 and a'),
|
([1, 'a'], 'and', '', '1 and a'),
|
||||||
([1, 'a'], 'and', '\'', '\'1\' and \'a\''),
|
([1, 'a'], 'and', "'", "'1' and 'a'"),
|
||||||
([1, 'a'], 'and', '', '1 and a'),
|
([1, 'a'], 'and', '', '1 and a'),
|
||||||
([1, 'a'], 'and', '\'', '\'1\' and \'a\''),
|
([1, 'a'], 'and', "'", "'1' and 'a'"),
|
||||||
([1, 'a'], 'and', '\'', '\'1\' and \'a\''),
|
([1, 'a'], 'and', "'", "'1' and 'a'"),
|
||||||
([1, 'a'], '', '', '1 a'),
|
([1, 'a'], '', '', '1 a'),
|
||||||
([1, 'a'], '', '\'', '\'1\' \'a\''),
|
([1, 'a'], '', "'", "'1' 'a'"),
|
||||||
([1, 'a'], '', '', '1 a'),
|
([1, 'a'], '', '', '1 a'),
|
||||||
([1, 'a'], '', '\'', '\'1\' \'a\''),
|
([1, 'a'], '', "'", "'1' 'a'"),
|
||||||
([1, 'a'], '', '\'', '\'1\' \'a\''),
|
([1, 'a'], '', "'", "'1' 'a'"),
|
||||||
([1, 2, 3], 'and', '', '1, 2 and 3'),
|
([1, 2, 3], 'and', '', '1, 2 and 3'),
|
||||||
([1, 2, 3], '', '', '1, 2 3'),
|
([1, 2, 3], '', '', '1, 2 3'),
|
||||||
([1, 2, 3], 'and', '\'', '\'1\', \'2\' and \'3\''),
|
([1, 2, 3], 'and', "'", "'1', '2' and '3'"),
|
||||||
([1, 2, 3], '', '\'', '\'1\', \'2\' \'3\''),
|
([1, 2, 3], '', "'", "'1', '2' '3'"),
|
||||||
([1, 2, 3, 42, 'a', 23], 'and', '', '1, 2, 3, 42, a and 23'),
|
([1, 2, 3, 42, 'a', 23], 'and', '', '1, 2, 3, 42, a and 23'),
|
||||||
([1, 2, 3, 42, 'a', 23], 'and', '\'', '\'1\', \'2\', \'3\', \'42\', \'a\' and \'23\''),
|
(
|
||||||
])
|
[1, 2, 3, 42, 'a', 23],
|
||||||
|
'and',
|
||||||
|
"'",
|
||||||
|
"'1', '2', '3', '42', 'a' and '23'",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_human_readable_list(ls, final_separator, quotation_mark, expected):
|
def test_human_readable_list(ls, final_separator, quotation_mark, expected):
|
||||||
assert human_readable_list(ls, final_separator, quotation_mark) == expected
|
assert human_readable_list(ls, final_separator, quotation_mark) == expected
|
||||||
@@ -12,10 +12,14 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from src.jcloud_docsgen.utils import non_empty_str
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@pytest.mark.parametrize('value,expected', [
|
from src.jcloud_docsgen.utils import non_empty_str
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'value,expected',
|
||||||
|
[
|
||||||
(None, None),
|
(None, None),
|
||||||
('', None),
|
('', None),
|
||||||
(' ', None),
|
(' ', None),
|
||||||
@@ -25,6 +29,7 @@ import pytest
|
|||||||
(' a', ' a'),
|
(' a', ' a'),
|
||||||
('a ', 'a '),
|
('a ', 'a '),
|
||||||
('a', 'a'),
|
('a', 'a'),
|
||||||
])
|
],
|
||||||
|
)
|
||||||
def test_non_empty_str(value, expected):
|
def test_non_empty_str(value, expected):
|
||||||
assert non_empty_str(value) == expected
|
assert non_empty_str(value) == expected
|
||||||
@@ -12,23 +12,21 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from typing import Union
|
|
||||||
import ast
|
import ast
|
||||||
|
|
||||||
__all__ = [
|
__all__ = ['ast_node']
|
||||||
'ast_node'
|
|
||||||
]
|
|
||||||
|
|
||||||
def ast_node(statement: str) -> Union[ast.stmt, None]:
|
|
||||||
'''
|
def ast_node(statement: str) -> ast.stmt | None:
|
||||||
|
"""
|
||||||
Returns an AST node from the statement.
|
Returns an AST node from the statement.
|
||||||
|
|
||||||
:param statement: The statement.
|
:param statement: The statement.
|
||||||
:type statement: str
|
:type statement: str
|
||||||
|
|
||||||
:return: The node.
|
:return: The node.
|
||||||
:rtype: Union[ast.stmt, None]
|
:rtype: ast.stmt | None
|
||||||
'''
|
"""
|
||||||
|
|
||||||
body = ast.parse(statement).body
|
body = ast.parse(statement).body
|
||||||
if not body:
|
if not body:
|
||||||
|
|||||||
Reference in new issue
Block a user