Skip to content

maint: fix between & length validators #334

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/docs.yaml.bkp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ include .gitignore
# global-include

recursive-include tests *
recursive-include src/export *

# graft

Expand All @@ -16,6 +15,7 @@ recursive-include src/export *
# global-exclude

recursive-exclude docs *.rst
recursive-exclude docs/references *.md

prune docs/_build
prune **/__pycache__
18 changes: 0 additions & 18 deletions mkdocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,21 +64,3 @@ copyright: Copyright © 2013 - 2024 Konsta Vesterinen

nav:
- Home: index.md
- API:
- references/between.md
- references/btc_address.md
- references/card.md
- references/country_code.md
- references/domain.md
- references/email.md
- references/hashes.md
- references/hostname.md
- references/i18n.md
- references/iban.md
- references/ip_address.md
- references/length.md
- references/mac_address.md
- references/slug.md
- references/url.md
- references/utils.md
- references/uuid.md
File renamed without changes.
9 changes: 6 additions & 3 deletions src/export/__main__.py → package/export/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ def _parse_package(source: Path):

def _generate_reference(source: Path, destination: Path, ext: str):
"""Generate reference."""
nav_items: Dict[str, List[str]] = {"Code Reference": []}
nav_items: Dict[str, List[str]] = {"API": []}
# 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")
nav_items["API"].append(f"references/{module_name}.md")
return nav_items


Expand All @@ -65,6 +65,9 @@ def _update_mkdocs_config(source: Path, destination: Path, nav_items: Dict[str,

def _gen_md_docs(source: Path, refs_path: Path):
"""Generate Markdown docs."""
# remove existing markdown files
for md_files in (source / "docs/references").glob("*.md"):
md_files.unlink()
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)
Expand Down Expand Up @@ -166,7 +169,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(
Expand Down
2 changes: 1 addition & 1 deletion package/roll.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion package/roll.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
33 changes: 8 additions & 25 deletions src/validators/between.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
15 changes: 12 additions & 3 deletions src/validators/length.py
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -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))
1 change: 0 additions & 1 deletion tests/test_between.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down
2 changes: 1 addition & 1 deletion tests/test_length.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""
Expand Down