diff --git a/.github/workflows/docs.yaml.bkp b/.github/workflows/docs.yaml.bkp index 120c5dbd..ac5211ea 100644 --- a/.github/workflows/docs.yaml.bkp +++ b/.github/workflows/docs.yaml.bkp @@ -27,7 +27,7 @@ jobs: pip install . pip install -r package/requirements.mkdocs.txt - name: Build documentation - run: python src/export docs + run: python package/export docs # set up Pages - name: Set up Pages uses: actions/configure-pages@v3 diff --git a/.github/workflows/package.yaml b/.github/workflows/package.yaml index 041f98fc..aa82a7b9 100644 --- a/.github/workflows/package.yaml +++ b/.github/workflows/package.yaml @@ -34,7 +34,7 @@ jobs: - name: Build package run: | . ./.venv/bin/activate - python src/export package + python package/export pkg deactivate # upload package as artifact - name: Upload artifact diff --git a/MANIFEST.in b/MANIFEST.in index a5a305ed..b68967ac 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -7,7 +7,6 @@ include .gitignore # global-include recursive-include tests * -recursive-include src/export * # graft @@ -16,6 +15,7 @@ recursive-include src/export * # global-exclude recursive-exclude docs *.rst +recursive-exclude docs/references *.md prune docs/_build prune **/__pycache__ diff --git a/src/export/__init__.py b/package/export/__init__.py similarity index 100% rename from src/export/__init__.py rename to package/export/__init__.py diff --git a/src/export/__main__.py b/package/export/__main__.py similarity index 79% rename from src/export/__main__.py rename to package/export/__main__.py index dc501be2..6a18229d 100644 --- a/src/export/__main__.py +++ b/package/export/__main__.py @@ -7,7 +7,6 @@ from pathlib import Path from shutil import copy, move, rmtree from subprocess import Popen # nosec -from typing import Dict, List __all__ = ("generate_documentation",) @@ -38,36 +37,11 @@ def _parse_package(source: Path): yield (namespace.module, namespace.names) -def _generate_reference(source: Path, destination: Path, ext: str): - """Generate reference.""" - nav_items: Dict[str, List[str]] = {"Code Reference": []} - # generate reference content - for module_name, aliases in _parse_package(source): - for alias in aliases: - _write_ref_content(destination / f"{module_name}.{ext}", module_name, alias.name) - if ext == "md": - nav_items["Code Reference"].append(f"references/{module_name}.md") - return nav_items - - -def _update_mkdocs_config(source: Path, destination: Path, nav_items: Dict[str, List[str]]): - """Temporary update to mkdocs config.""" - # external - from yaml import safe_dump, safe_load - - copy(source, destination) - with open(source, "rt") as mkf: - mkdocs_conf = safe_load(mkf) - mkdocs_conf["nav"] += [nav_items] - with open(source, "wt") as mkf: - safe_dump(mkdocs_conf, mkf, sort_keys=False) - - def _gen_md_docs(source: Path, refs_path: Path): """Generate Markdown docs.""" - nav_items = _generate_reference(source / "src/validators/__init__.py", refs_path, "md") - # backup mkdocs config - _update_mkdocs_config(source / "mkdocs.yaml", source / "mkdocs.bak.yaml", nav_items) + # remove existing markdown files + for md_files in (source / "docs/references").glob("*.md"): + md_files.unlink() # build mkdocs as subprocess mkdocs_build = Popen(("mkdocs", "build")) # nosec mkdocs_build.communicate() @@ -94,7 +68,9 @@ def _gen_rst_docs(source: Path, refs_path: Path, only_web: bool = False, only_ma + "\n references/*\n" ) # generate RST reference documentation - _generate_reference(source / "src/validators/__init__.py", refs_path, "rst") + for module_name, aliases in _parse_package(source / "src/validators/__init__.py"): + for alias in aliases: + _write_ref_content(refs_path / f"{module_name}.rst", module_name, alias.name) exit_code = 0 if not only_man: # build sphinx web pages as subprocess @@ -166,7 +142,7 @@ def package(source: Path): if len(argv) != 2: quit(exit_code) - if argv[1] == "package": + if argv[1] == "pkg": exit_code = package(project_root) if argv[1] == "docs": exit_code = generate_documentation( diff --git a/package/roll.ps1 b/package/roll.ps1 index 4441807c..c565b83a 100644 --- a/package/roll.ps1 +++ b/package/roll.ps1 @@ -46,7 +46,7 @@ if ($IsLinux || $IsMacOS) { . $venv_dir\$bin_path\Activate.ps1 # Run export script -python src/export package +python package/export pkg # Deactivate virtual environment deactivate diff --git a/package/roll.sh b/package/roll.sh index 37ed0830..5287a162 100755 --- a/package/roll.sh +++ b/package/roll.sh @@ -40,7 +40,7 @@ $venv_dir/bin/pip install build . $venv_dir/bin/activate # Run export script -python src/export package +python package/export pkg # Deactivate virtual environment deactivate diff --git a/src/validators/__init__.py b/src/validators/__init__.py index 48696177..ae8b4210 100644 --- a/src/validators/__init__.py +++ b/src/validators/__init__.py @@ -79,4 +79,4 @@ "validator", ) -__version__ = "0.23.0" +__version__ = "0.23.1" diff --git a/src/validators/between.py b/src/validators/between.py index 2fc3a0c9..0cd79d46 100644 --- a/src/validators/between.py +++ b/src/validators/between.py @@ -57,42 +57,25 @@ def between( If `value` is not in between the given conditions. Raises: - ValueError: If both `min_val` and `max_val` are `None`, - or if `min_val` is greater than `max_val`. - TypeError: If there's a type mismatch before comparison. + (ValueError): If `min_val` is greater than `max_val`. + (TypeError): If there's a type mismatch during comparison. Note: - `PossibleValueTypes` = `TypeVar("PossibleValueTypes", int, float, str, datetime)` - - Either one of `min_val` or `max_val` must be provided. - - > *New in version 0.2.0*. + - If neither `min_val` nor `max_val` is provided, result will always be `True`. """ if value is None: return False - if min_val is max_val is None: - raise ValueError("At least one of either `min_val` or `max_val` must be specified") - if max_val is None: max_val = AbsMax() if min_val is None: min_val = AbsMin() - if isinstance(min_val, AbsMin): - if type(value) is type(max_val): - return min_val <= value <= max_val - raise TypeError("`value` and `max_val` must be of same type") - - if isinstance(max_val, AbsMax): - if type(value) is type(min_val): - return min_val <= value <= max_val - raise TypeError("`value` and `min_val` must be of same type") - - if type(min_val) is type(max_val): + try: if min_val > max_val: - raise ValueError("`min_val` cannot be more than `max_val`") - if type(value) is type(min_val): # or is type(max_val) - return min_val <= value <= max_val - raise TypeError("`value` and (`min_val` or `max_val`) must be of same type") + raise ValueError("`min_val` cannot be greater than `max_val`") + except TypeError as err: + raise TypeError("Comparison type mismatch") from err - raise TypeError("`value` and `min_val` and `max_val` must be of same type") + return min_val <= value <= max_val diff --git a/src/validators/length.py b/src/validators/length.py index 92a274d3..be60d06e 100644 --- a/src/validators/length.py +++ b/src/validators/length.py @@ -1,12 +1,15 @@ """Length.""" +# standard +from typing import Union + # local from .between import between from .utils import validator @validator -def length(value: str, /, *, min_val: int = 0, max_val: int = 0): +def length(value: str, /, *, min_val: Union[int, None] = None, max_val: Union[int, None] = None): """Return whether or not the length of given string is within a specified range. Examples: @@ -33,6 +36,12 @@ def length(value: str, /, *, min_val: int = 0, max_val: int = 0): (ValidationError): If `len(value)` is not in between the given conditions. - > *New in version 0.2.0*. + Raises: + (ValueError): If either `min_val` or `max_val` is negative. """ - return between(len(value), min_val=min_val, max_val=max_val) if value else False + if min_val is not None and min_val < 0: + raise ValueError("Length cannot be negative. `min_val` is less than zero.") + if max_val is not None and max_val < 0: + raise ValueError("Length cannot be negative. `max_val` is less than zero.") + + return bool(between(len(value), min_val=min_val, max_val=max_val)) diff --git a/tests/test_between.py b/tests/test_between.py index 6b1ccd72..bdb71551 100644 --- a/tests/test_between.py +++ b/tests/test_between.py @@ -28,7 +28,6 @@ def test_returns_true_on_valid_range(value: T, min_val: T, max_val: T): (None, 13, 14), (12, 13, 14), (12, None, 11), - (12, None, None), (12, 13, None), (12, "13.5", datetime(1970, 1, 1)), ("12", 20.5, "None"), diff --git a/tests/test_length.py b/tests/test_length.py index 65737254..c9cd1dc1 100644 --- a/tests/test_length.py +++ b/tests/test_length.py @@ -9,7 +9,7 @@ @pytest.mark.parametrize( ("value", "min_val", "max_val"), - [("password", 2, 10), ("password", 0, 10), ("password", 8, 8)], + [("password", 2, None), ("password", None, None), ("password", 0, 10), ("password", 8, 8)], ) def test_returns_true_on_valid_length(value: str, min_val: int, max_val: int): """Test returns true on valid length."""