From b5d871cd819851ef40071bf3ef15c82066ef5973 Mon Sep 17 00:00:00 2001 From: sg495 Date: Mon, 13 Dec 2021 14:05:23 +0000 Subject: [PATCH] Added type validation --- bases/__init__.py | 2 +- bases/alphabet/__init__.py | 11 +++++++ bases/alphabet/abstract.py | 6 ++++ bases/alphabet/range_alphabet.py | 5 ++++ bases/alphabet/string_alphabet.py | 4 +++ bases/encoding/__init__.py | 12 ++++++++ bases/encoding/base.py | 12 +++++--- bases/encoding/block.py | 8 ++++- bases/encoding/errors.py | 7 +++++ bases/encoding/fixchar.py | 15 +++++++--- bases/encoding/simple.py | 2 ++ bases/encoding/zeropad.py | 8 +++++ bases/random.py | 13 ++++++++ docs/bases/alphabet/abstract.html | 15 ++++++++++ docs/bases/alphabet/index.html | 21 +++++++++++++ docs/bases/alphabet/range_alphabet.html | 8 +++++ docs/bases/alphabet/string_alphabet.html | 7 +++++ docs/bases/encoding/base.html | 26 +++++++++++----- docs/bases/encoding/block.html | 15 ++++++++-- docs/bases/encoding/errors.html | 13 ++++++++ docs/bases/encoding/fixchar.html | 38 ++++++++++++++++-------- docs/bases/encoding/index.html | 23 ++++++++++++++ docs/bases/encoding/simple.html | 3 ++ docs/bases/encoding/zeropad.html | 19 ++++++++++++ docs/bases/index.html | 2 ++ docs/bases/random.html | 25 ++++++++++++++++ setup.cfg | 6 ++-- tox.ini | 3 +- 28 files changed, 293 insertions(+), 36 deletions(-) diff --git a/bases/__init__.py b/bases/__init__.py index 55d1fc6..3c7ffe2 100644 --- a/bases/__init__.py +++ b/bases/__init__.py @@ -57,7 +57,7 @@ """ -__version__ = "0.1.1" +__version__ = "0.2.0" from . import encoding as encoding from . import alphabet as alphabet diff --git a/bases/alphabet/__init__.py b/bases/alphabet/__init__.py index 80efd8a..38275cd 100644 --- a/bases/alphabet/__init__.py +++ b/bases/alphabet/__init__.py @@ -45,6 +45,7 @@ import re from typing import Collection, Dict, Iterator, Optional, overload, Tuple, Union from typing_extensions import Literal +from typing_validation import validate from .abstract import Alphabet as Alphabet from .string_alphabet import StringAlphabet as StringAlphabet @@ -63,6 +64,7 @@ def get(name: str) -> Alphabet: StringAlphabet('0123456789ABCDEF') ``` """ + validate(name, str) if name not in _alphabets: raise KeyError(f"Alphabet named {repr(name)} does not exist.") return _alphabets[name] @@ -79,6 +81,7 @@ def has(name: str) -> bool: True ``` """ + validate(name, str) return name in _alphabets def register(**kwargs: Alphabet) -> None: @@ -101,6 +104,8 @@ def register(**kwargs: Alphabet) -> None: re.match(r"^base[0-9][a-zA-Z0-9_]*$", name) ``` """ + for arg in kwargs.values(): + validate(arg, Alphabet) for name, alphabet in kwargs.items(): if not re.match(r"^base[0-9][a-zA-Z0-9_]*$", name): raise ValueError(f"Invalid alphabet name {repr(name)}") @@ -133,6 +138,8 @@ def unregister(*names: str) -> None: StringAlphabet('0123456789ABCDEF') ``` """ + for name in names: + validate(name, str) for name in names: if name not in _alphabets: raise KeyError(f"Alphabet named {repr(name)} does not exist.") @@ -153,6 +160,7 @@ def table(*, prefix: str = "") -> Iterator[Tuple[str, Alphabet]]: ``` """ + validate(prefix, str) alphabets = [(name, alphabet) for name, alphabet in _alphabets.items() if name.startswith(prefix)] alphabets = sorted(alphabets, key=lambda pair: pair[0]) @@ -188,6 +196,9 @@ def make(chars: Union[str, range], *, case_sensitive: bool = True, name: Optiona If the optional keyword argument `name` is specified, the alphabet is automatically registered using `register`. """ + validate(chars, Union[str, range]) + validate(case_sensitive, bool) + validate(name, Optional[str]) if isinstance(chars, str): string_alphabet = StringAlphabet(chars, case_sensitive=case_sensitive) if name is not None: diff --git a/bases/alphabet/abstract.py b/bases/alphabet/abstract.py index cdff1d8..97f92f3 100644 --- a/bases/alphabet/abstract.py +++ b/bases/alphabet/abstract.py @@ -4,6 +4,7 @@ from abc import ABC, abstractmethod from typing import Any, Mapping, Optional, overload, Sequence, TypeVar, Union +from typing_validation import validate Self = TypeVar("Self", bound="Alphabet") @@ -26,6 +27,7 @@ class Alphabet(ABC, Sequence[str]): _case_sensitive: bool def __init__(self, case_sensitive: bool = True): + validate(case_sensitive, bool) self._case_sensitive = case_sensitive @property @@ -68,6 +70,9 @@ def index(self, char: str, start: int = 0, stop: Optional[int] = None) -> int: ``` """ # pylint: disable = arguments-renamed + validate(char, str) + validate(start, int) + validate(stop, Optional[int]) if start < 0: start = max(len(self) + start, 0) if stop is None: @@ -87,6 +92,7 @@ def count(self, char: str) -> int: Returns 1 if `char` is in the alphabet and 0 otherwise. """ # pylint: disable = arguments-renamed + validate(char, str) return 1 if char in self else 0 def __contains__(self, char: Any) -> bool: diff --git a/bases/alphabet/range_alphabet.py b/bases/alphabet/range_alphabet.py index 5db7b31..728622c 100644 --- a/bases/alphabet/range_alphabet.py +++ b/bases/alphabet/range_alphabet.py @@ -3,6 +3,7 @@ """ from typing import Any, Iterator, Mapping, overload, Union +from typing_validation import validate from .abstract import Alphabet from .string_alphabet import StringAlphabet @@ -28,6 +29,7 @@ class RangeAlphabet(Alphabet): def __init__(self, codepoints: range, *, case_sensitive: bool = True): super().__init__(case_sensitive) + validate(codepoints, range) self._codepoints = codepoints self._revdir = _RangeAlphabetRevdir(self) self.__validate_init() @@ -75,12 +77,14 @@ def __getitem__(self, idx: slice) -> "RangeAlphabet": ... def __getitem__(self, idx: Union[int, slice]) -> Union[str, "RangeAlphabet"]: + validate(idx, Union[int, slice]) if isinstance(idx, slice): new_codepoints = self._codepoints[idx] return RangeAlphabet(new_codepoints, case_sensitive=self.case_sensitive) return chr(self._codepoints[idx]) def with_case_sensitivity(self, case_sensitive: bool) -> "RangeAlphabet": + validate(case_sensitive, bool) if case_sensitive == self.case_sensitive: return self return RangeAlphabet(self.codepoints, case_sensitive=case_sensitive) @@ -146,6 +150,7 @@ def __contains__(self, char: Any) -> bool: return ord(char.upper()) in alphabet.codepoints or ord(char.lower()) in alphabet.codepoints def __getitem__(self, char: str) -> int: + validate(char, str) alphabet = self._alphabet if ord(char) in alphabet.codepoints: return ord(char)-alphabet.codepoints.start diff --git a/bases/alphabet/string_alphabet.py b/bases/alphabet/string_alphabet.py index 4ab06f2..4501e0e 100644 --- a/bases/alphabet/string_alphabet.py +++ b/bases/alphabet/string_alphabet.py @@ -4,6 +4,7 @@ from types import MappingProxyType from typing import Any, Mapping, overload, Union +from typing_validation import validate from .abstract import Alphabet @@ -30,6 +31,7 @@ class StringAlphabet(Alphabet): def __init__(self, chars: str, *, case_sensitive: bool = True): super().__init__(case_sensitive) + validate(chars, str) self._chars = chars revdir = { c: idx for idx, c in enumerate(chars) @@ -88,12 +90,14 @@ def __getitem__(self, idx: slice) -> "StringAlphabet": ... def __getitem__(self, idx: Union[int, slice]) -> Union[str, "StringAlphabet"]: + validate(idx, Union[int, slice]) if isinstance(idx, slice): new_chars = self._chars[idx] return StringAlphabet(new_chars, case_sensitive=self.case_sensitive) return self._chars[idx] def with_case_sensitivity(self, case_sensitive: bool) -> "StringAlphabet": + validate(case_sensitive, bool) if case_sensitive == self.case_sensitive: return self return StringAlphabet(self.chars, case_sensitive=case_sensitive) diff --git a/bases/encoding/__init__.py b/bases/encoding/__init__.py index 92e0f09..c8ef7c4 100644 --- a/bases/encoding/__init__.py +++ b/bases/encoding/__init__.py @@ -63,6 +63,7 @@ import re from typing import Any, cast, Collection, Dict, Iterator, Mapping, Optional, overload, Tuple, Type, Union from typing_extensions import Literal +from typing_validation import validate from bases import alphabet from bases.alphabet import Alphabet @@ -89,6 +90,7 @@ def get(name: str) -> BaseEncoding: block_nchars=2) ``` """ + validate(name, str) if name not in _base_encodings: raise KeyError(f"Encoding named {repr(name)} does not exist.") return _base_encodings[name] @@ -101,6 +103,7 @@ def has(name: str) -> bool: True ``` """ + validate(name, str) return name in _base_encodings def register(**kwargs: BaseEncoding) -> None: @@ -126,6 +129,8 @@ def register(**kwargs: BaseEncoding) -> None: re.match(r"^base[0-9][a-zA-Z0-9_]*$", name) ``` """ + for arg in kwargs.values(): + validate(arg, BaseEncoding) for name, encoding in kwargs.items(): if not re.match(r"^base[0-9][a-zA-Z0-9_]*$", name): raise ValueError(f"Invalid encoding name {repr(name)}") @@ -161,6 +166,8 @@ def unregister(*names: str) -> None: block_nchars=2) ``` """ + for name in names: + validate(name, str) for name in names: if name not in _base_encodings: raise KeyError(f"Encoding named {repr(name)} does not exist.") @@ -190,6 +197,7 @@ def table(*, prefix: str = "") -> Iterator[Tuple[str, BaseEncoding]]: ``` """ + validate(prefix, str) encodings = [(name, encoding) for name, encoding in _base_encodings.items() if name.startswith(prefix)] encodings = sorted(encodings, key=lambda pair: pair[0]) @@ -248,6 +256,10 @@ def make(chars: Union[str, range, Alphabet, BaseEncoding], *, kind: str, name: O ``` """ + validate(chars, Union[str, range, Alphabet, BaseEncoding]) + validate(kind, str) + validate(name, Optional[str]) + validate(case_sensitive, Optional[bool]) kwargs["case_sensitive"] = case_sensitive if kind == "simple-enc": if isinstance(chars, BaseEncoding): diff --git a/bases/encoding/base.py b/bases/encoding/base.py index b475d18..01f96af 100644 --- a/bases/encoding/base.py +++ b/bases/encoding/base.py @@ -4,6 +4,7 @@ from abc import ABC, abstractmethod from typing import Any, Mapping, Optional, TypeVar, Union +from typing_validation import validate from bases import alphabet from bases.alphabet import Alphabet @@ -24,6 +25,8 @@ class BaseEncoding(ABC): def __init__(self, chars: Union[str, range, Alphabet], *, case_sensitive: Optional[bool] = None): + validate(chars, Union[str, range, Alphabet]) + validate(case_sensitive, Optional[bool]) if isinstance(chars, Alphabet): if case_sensitive is not None: chars = chars.with_case_sensitivity(case_sensitive) @@ -99,6 +102,8 @@ def with_alphabet(self: Self, chars: Union[str, range, Alphabet], *, Returns a new encoding with the same kind and options as this one, but a different alphabet and/or case sensitivity. """ + validate(chars, Union[str, range, Alphabet]) + validate(case_sensitive, Optional[bool]) options = {**self.options()} options["case_sensitive"] = case_sensitive return type(self)(chars, **options) @@ -121,6 +126,7 @@ def with_case_sensitivity(self: Self, case_sensitive: bool) -> Self: pad_char='=', padding='include') ``` """ + validate(case_sensitive, bool) return self.with_alphabet(self.alphabet.with_case_sensitivity(case_sensitive)) def upper(self: Self) -> Self: @@ -234,13 +240,11 @@ def canonical_string(self, s: str) -> str: def _validate_bytes(self, b: bytes) -> bytes: # pylint: disable = no-self-use - if not isinstance(b, bytes): - raise TypeError() + validate(b, bytes) return b def _validate_string(self, s: str) -> str: - if not isinstance(s, str): - raise TypeError() + validate(s, str) alphabet = self.alphabet for c in s: if c not in alphabet: diff --git a/bases/encoding/block.py b/bases/encoding/block.py index af6ca48..395ef68 100644 --- a/bases/encoding/block.py +++ b/bases/encoding/block.py @@ -5,6 +5,7 @@ import math from types import MappingProxyType from typing import Any, Dict, List, Mapping, Optional, Union +from typing_validation import validate from bases.alphabet import Alphabet from .base import BaseEncoding @@ -93,10 +94,13 @@ def __init__(self, encoding: Union[str, range, Alphabet, BaseEncoding], *, block_size: Union[int, Mapping[int, int]], sep_char: str = "", reverse_blocks: bool = False): + validate(encoding, Union[str, range, Alphabet, BaseEncoding]) + validate(block_size, Union[int, Mapping[int, int]]) + validate(sep_char, str) + validate(reverse_blocks, bool) self._init_encoding = encoding self._init_case_sensitive = case_sensitive self._init_block_size = block_size - if isinstance(encoding, BaseEncoding): alphabet: Union[str, range, Alphabet] = encoding.alphabet else: @@ -221,6 +225,7 @@ def _validate_bytes(self, b: bytes) -> bytes: return b def _validate_string(self, s: str) -> str: + validate(s, str) sep_char = self.sep_char block_nchars = self.block_nchars if sep_char: @@ -293,6 +298,7 @@ def _decode(self, s: str) -> bytes: return b"".join(byte_blocks) def options(self, skip_defaults: bool = False) -> Mapping[str, Any]: + validate(skip_defaults, bool) options: Dict[str, Any] = { "block_size": self._init_block_size, } diff --git a/bases/encoding/errors.py b/bases/encoding/errors.py index 09ea86b..2f803b3 100644 --- a/bases/encoding/errors.py +++ b/bases/encoding/errors.py @@ -3,6 +3,7 @@ """ import binascii +from typing_validation import validate from bases.alphabet import Alphabet @@ -28,6 +29,8 @@ class InvalidDigitError(EncodingError): base: int def __init__(self, digit: int, base: int) -> None: + validate(digit, int) + validate(base, int) self.digit = digit self.base = base if 0 <= digit < base: @@ -57,6 +60,8 @@ class NonAlphabeticCharError(DecodingError): alphabet: Alphabet def __init__(self, char: str, alphabet: Alphabet) -> None: + validate(char, str) + validate(alphabet, Alphabet) self.char = char self.alphabet = alphabet if char in alphabet: @@ -73,6 +78,8 @@ class PaddingError(DecodingError): expected_padding: int def __init__(self, padding: int, expected_padding: int) -> None: + validate(padding, int) + validate(expected_padding, int) self.padding = padding self.expected_padding = expected_padding if padding < expected_padding: diff --git a/bases/encoding/fixchar.py b/bases/encoding/fixchar.py index d4bf4e7..fa451a1 100644 --- a/bases/encoding/fixchar.py +++ b/bases/encoding/fixchar.py @@ -5,6 +5,7 @@ import math from typing import Any, Dict, List, Mapping, Optional, Union from typing_extensions import Literal +from typing_validation import validate from bases.alphabet import Alphabet from .base import BaseEncoding @@ -95,6 +96,9 @@ def __init__(self, alphabet: Union[str, range, Alphabet], *, char_nbits: Union[int, Literal["auto"]] = "auto", pad_char: Optional[str] = None, padding: PaddingOptions = "ignore"): + validate(char_nbits, Union[int, Literal["auto"]]) + validate(pad_char, Optional[str]) + validate(padding, PaddingOptions) if padding not in ("ignore", "include", "require"): raise TypeError("Allowed padding options are: 'ignore', 'include' and 'require'.") super().__init__(alphabet, case_sensitive=case_sensitive) @@ -221,6 +225,7 @@ def pad(self, require: bool = False) -> "FixcharBaseEncoding": pad_char='=', padding='include') ``` """ + validate(require, bool) options = dict(padding="require" if require else "include") return self.with_options(**options) @@ -248,6 +253,7 @@ def nopad(self, allow: bool = True) -> "FixcharBaseEncoding": case_sensitive=False)) ``` """ + validate(allow, bool) options = dict(padding="ignore", pad_char=self.pad_char if allow else None) return self.with_options(**options) @@ -272,6 +278,7 @@ def with_pad_char(self, pad_char: Optional[str]) -> "FixcharBaseEncoding": ``` """ + validate(pad_char, Optional[str]) options: Dict[str, Any] = dict(pad_char=pad_char) if pad_char is None: options["padding"] = "ignore" @@ -286,8 +293,7 @@ def pad_string(self, s: str) -> str: The value of `FixcharBaseEncoding.padding` is irrelevant to this method. """ - if not isinstance(s, str): - raise TypeError() + validate(s, str) pad_char = self.pad_char block_nchars = self._block_nchars # no padding available for this encoding scheme @@ -309,8 +315,7 @@ def strip_string(self, s: str) -> str: If `FixcharBaseEncoding.padding` is set to `"require"`, checks that the correct number of padding characters were included and raises `bases.encoding.errors.PaddingError` if not. """ - if not isinstance(s, str): - raise TypeError() + validate(s, str) pad_char = self.pad_char case_sensitive = self.case_sensitive block_nchars = self._block_nchars @@ -337,6 +342,7 @@ def canonical_bytes(self, b: bytes) -> bytes: return b def canonical_string(self, s: str) -> str: + validate(s, str) if self.include_padding: return self.pad_string(s) return self.strip_string(s) @@ -395,6 +401,7 @@ def _decode(self, s: str) -> bytes: return i.to_bytes(length=original_nbytes, byteorder="big") def options(self, skip_defaults: bool = False) -> Mapping[str, Any]: + validate(skip_defaults, bool) options: Dict[str, Any] = {} if not skip_defaults or self._init_char_nbits != "auto": options["char_nbits"] = self._init_char_nbits diff --git a/bases/encoding/simple.py b/bases/encoding/simple.py index 743ecff..51a07d5 100644 --- a/bases/encoding/simple.py +++ b/bases/encoding/simple.py @@ -3,6 +3,7 @@ """ from typing import Any, List, Mapping, Optional, Union +from typing_validation import validate from bases.alphabet import Alphabet from .base import BaseEncoding @@ -77,4 +78,5 @@ def _decode(self, s: str) -> bytes: return i.to_bytes(length=nbytes, byteorder="big") def options(self, skip_defaults: bool = False) -> Mapping[str, Any]: + validate(skip_defaults, bool) return {} diff --git a/bases/encoding/zeropad.py b/bases/encoding/zeropad.py index 0dc50cd..d1ae9ff 100644 --- a/bases/encoding/zeropad.py +++ b/bases/encoding/zeropad.py @@ -4,6 +4,7 @@ import math from typing import Any, Dict, Mapping, Optional, Union +from typing_validation import validate from bases.alphabet import Alphabet from .base import BaseEncoding @@ -49,6 +50,8 @@ def __init__(self, alphabet: Union[str, range, Alphabet], *, case_sensitive: Optional[bool] = None, block_nbytes: int = 1, block_nchars: int = 1): + validate(block_nbytes, int) + validate(block_nchars, int) super().__init__(alphabet, case_sensitive=case_sensitive) self._simple_encoding = SimpleBaseEncoding(self.alphabet) self._block_nbytes = block_nbytes @@ -79,6 +82,8 @@ def max_block_nchars(base: int, block_nbytes: int) -> int: 256**block_nbytes > base**(block_nchars-1) ``` """ + validate(base, int) + validate(block_nbytes, int) if base <= 1: raise ValueError("Base must be >= 2.") if block_nbytes <= 0: @@ -97,6 +102,8 @@ def max_block_nbytes(base: int, block_nchars: int) -> int: base**block_nchars > 256**(block_nbytes-1) ``` """ + validate(base, int) + validate(block_nchars, int) if base <= 1: raise ValueError("Base must be >= 2.") if block_nchars <= 0: @@ -174,6 +181,7 @@ def _decode(self, s: str) -> bytes: return b def options(self, skip_defaults: bool = False) -> Mapping[str, Any]: + validate(skip_defaults, bool) options: Dict[str, Any] = {} if not skip_defaults or self.block_nbytes != 1: options["block_nbytes"] = self.block_nbytes diff --git a/bases/random.py b/bases/random.py index 3bade4a..f55f349 100644 --- a/bases/random.py +++ b/bases/random.py @@ -52,6 +52,7 @@ from random import Random # pylint: disable = import-self from types import MappingProxyType from typing import Any, Dict, Iterator, Mapping, Optional +from typing_validation import validate from .alphabet import Alphabet from .encoding import BaseEncoding, SimpleBaseEncoding, ZeropadBaseEncoding, BlockBaseEncoding, FixcharBaseEncoding @@ -112,6 +113,8 @@ def options(*, See `set_options` for a description of the options. """ # pylint: disable = too-many-locals + for arg in (seed, min_bytes, max_bytes, min_chars, max_chars): + validate(arg, Optional[int]) global _options global _rand try: @@ -145,6 +148,8 @@ def set_options(*, """ # pylint: disable = too-many-branches, too-many-locals, too-many-statements + for arg in (seed, min_bytes, max_bytes, min_chars, max_chars): + validate(arg, Optional[int]) global _options global _rand # set newly passed options @@ -197,6 +202,8 @@ def rand_bytes(n: Optional[int] = None, *, encoding: Optional[BaseEncoding] = No [0, 96, 63]] ``` """ + validate(n, Optional[int]) + validate(encoding, Optional[BaseEncoding]) if encoding is None: return rand_raw_bytes(n) if isinstance(encoding, SimpleBaseEncoding): @@ -217,6 +224,9 @@ def rand_raw_bytes(n: Optional[int] = None, *, min_bytes: Optional[int] = None, The optional `min_bytes` and `max_bytes` parameters can be used to set a minimum/maximum length for the `bytes` objects: if `None`, the values are fetched from `get_options`. """ + validate(n, Optional[int]) + validate(min_bytes, Optional[int]) + validate(max_bytes, Optional[int]) if n is not None and n < 0: raise ValueError() if min_bytes is None: @@ -318,6 +328,9 @@ def rand_str(n: Optional[int] = None, *, encoding: Optional[BaseEncoding]=None, ``` """ + validate(n, Optional[int]) + validate(encoding, Optional[BaseEncoding]) + validate(alphabet, Optional[Alphabet]) if encoding is None: if alphabet is None: raise ValueError("One of 'encoding' or 'alphabet' must be specified.") diff --git a/docs/bases/alphabet/abstract.html b/docs/bases/alphabet/abstract.html index 45112a0..cf5988a 100644 --- a/docs/bases/alphabet/abstract.html +++ b/docs/bases/alphabet/abstract.html @@ -34,6 +34,7 @@

Module bases.alphabet.abstract

from abc import ABC, abstractmethod from typing import Any, Mapping, Optional, overload, Sequence, TypeVar, Union +from typing_validation import validate Self = TypeVar("Self", bound="Alphabet") @@ -56,6 +57,7 @@

Module bases.alphabet.abstract

_case_sensitive: bool def __init__(self, case_sensitive: bool = True): + validate(case_sensitive, bool) self._case_sensitive = case_sensitive @property @@ -98,6 +100,9 @@

Module bases.alphabet.abstract

``` """ # pylint: disable = arguments-renamed + validate(char, str) + validate(start, int) + validate(stop, Optional[int]) if start < 0: start = max(len(self) + start, 0) if stop is None: @@ -117,6 +122,7 @@

Module bases.alphabet.abstract

Returns 1 if `char` is in the alphabet and 0 otherwise. """ # pylint: disable = arguments-renamed + validate(char, str) return 1 if char in self else 0 def __contains__(self, char: Any) -> bool: @@ -266,6 +272,7 @@

Classes

_case_sensitive: bool def __init__(self, case_sensitive: bool = True): + validate(case_sensitive, bool) self._case_sensitive = case_sensitive @property @@ -308,6 +315,9 @@

Classes

``` """ # pylint: disable = arguments-renamed + validate(char, str) + validate(start, int) + validate(stop, Optional[int]) if start < 0: start = max(len(self) + start, 0) if stop is None: @@ -327,6 +337,7 @@

Classes

Returns 1 if `char` is in the alphabet and 0 otherwise. """ # pylint: disable = arguments-renamed + validate(char, str) return 1 if char in self else 0 def __contains__(self, char: Any) -> bool: @@ -548,6 +559,7 @@

Methods

Returns 1 if `char` is in the alphabet and 0 otherwise. """ # pylint: disable = arguments-renamed + validate(char, str) return 1 if char in self else 0 @@ -594,6 +606,9 @@

Methods

``` """ # pylint: disable = arguments-renamed + validate(char, str) + validate(start, int) + validate(stop, Optional[int]) if start < 0: start = max(len(self) + start, 0) if stop is None: diff --git a/docs/bases/alphabet/index.html b/docs/bases/alphabet/index.html index 12aecbb..7273ac8 100644 --- a/docs/bases/alphabet/index.html +++ b/docs/bases/alphabet/index.html @@ -100,6 +100,7 @@

Module bases.alphabet

import re from typing import Collection, Dict, Iterator, Optional, overload, Tuple, Union from typing_extensions import Literal +from typing_validation import validate from .abstract import Alphabet as Alphabet from .string_alphabet import StringAlphabet as StringAlphabet @@ -118,6 +119,7 @@

Module bases.alphabet

StringAlphabet('0123456789ABCDEF') ``` """ + validate(name, str) if name not in _alphabets: raise KeyError(f"Alphabet named {repr(name)} does not exist.") return _alphabets[name] @@ -134,6 +136,7 @@

Module bases.alphabet

True ``` """ + validate(name, str) return name in _alphabets def register(**kwargs: Alphabet) -> None: @@ -156,6 +159,8 @@

Module bases.alphabet

re.match(r"^base[0-9][a-zA-Z0-9_]*$", name) ``` """ + for arg in kwargs.values(): + validate(arg, Alphabet) for name, alphabet in kwargs.items(): if not re.match(r"^base[0-9][a-zA-Z0-9_]*$", name): raise ValueError(f"Invalid alphabet name {repr(name)}") @@ -188,6 +193,8 @@

Module bases.alphabet

StringAlphabet('0123456789ABCDEF') ``` """ + for name in names: + validate(name, str) for name in names: if name not in _alphabets: raise KeyError(f"Alphabet named {repr(name)} does not exist.") @@ -208,6 +215,7 @@

Module bases.alphabet

``` """ + validate(prefix, str) alphabets = [(name, alphabet) for name, alphabet in _alphabets.items() if name.startswith(prefix)] alphabets = sorted(alphabets, key=lambda pair: pair[0]) @@ -243,6 +251,9 @@

Module bases.alphabet

If the optional keyword argument `name` is specified, the alphabet is automatically registered using `register`. """ + validate(chars, Union[str, range]) + validate(case_sensitive, bool) + validate(name, Optional[str]) if isinstance(chars, str): string_alphabet = StringAlphabet(chars, case_sensitive=case_sensitive) if name is not None: @@ -407,6 +418,7 @@

Functions

StringAlphabet('0123456789ABCDEF') ``` """ + validate(name, str) if name not in _alphabets: raise KeyError(f"Alphabet named {repr(name)} does not exist.") return _alphabets[name] @@ -438,6 +450,7 @@

Functions

True ``` """ + validate(name, str) return name in _alphabets @@ -483,6 +496,9 @@

Functions

If the optional keyword argument `name` is specified, the alphabet is automatically registered using `register`. """ + validate(chars, Union[str, range]) + validate(case_sensitive, bool) + validate(name, Optional[str]) if isinstance(chars, str): string_alphabet = StringAlphabet(chars, case_sensitive=case_sensitive) if name is not None: @@ -535,6 +551,8 @@

Functions

re.match(r"^base[0-9][a-zA-Z0-9_]*$", name) ``` """ + for arg in kwargs.values(): + validate(arg, Alphabet) for name, alphabet in kwargs.items(): if not re.match(r"^base[0-9][a-zA-Z0-9_]*$", name): raise ValueError(f"Invalid alphabet name {repr(name)}") @@ -576,6 +594,7 @@

Functions

``` """ + validate(prefix, str) alphabets = [(name, alphabet) for name, alphabet in _alphabets.items() if name.startswith(prefix)] alphabets = sorted(alphabets, key=lambda pair: pair[0]) @@ -627,6 +646,8 @@

Functions

StringAlphabet('0123456789ABCDEF') ``` """ + for name in names: + validate(name, str) for name in names: if name not in _alphabets: raise KeyError(f"Alphabet named {repr(name)} does not exist.") diff --git a/docs/bases/alphabet/range_alphabet.html b/docs/bases/alphabet/range_alphabet.html index 10dfc14..fa835b6 100644 --- a/docs/bases/alphabet/range_alphabet.html +++ b/docs/bases/alphabet/range_alphabet.html @@ -33,6 +33,7 @@

Module bases.alphabet.range_alphabet

""" from typing import Any, Iterator, Mapping, overload, Union +from typing_validation import validate from .abstract import Alphabet from .string_alphabet import StringAlphabet @@ -58,6 +59,7 @@

Module bases.alphabet.range_alphabet

def __init__(self, codepoints: range, *, case_sensitive: bool = True): super().__init__(case_sensitive) + validate(codepoints, range) self._codepoints = codepoints self._revdir = _RangeAlphabetRevdir(self) self.__validate_init() @@ -105,12 +107,14 @@

Module bases.alphabet.range_alphabet

... def __getitem__(self, idx: Union[int, slice]) -> Union[str, "RangeAlphabet"]: + validate(idx, Union[int, slice]) if isinstance(idx, slice): new_codepoints = self._codepoints[idx] return RangeAlphabet(new_codepoints, case_sensitive=self.case_sensitive) return chr(self._codepoints[idx]) def with_case_sensitivity(self, case_sensitive: bool) -> "RangeAlphabet": + validate(case_sensitive, bool) if case_sensitive == self.case_sensitive: return self return RangeAlphabet(self.codepoints, case_sensitive=case_sensitive) @@ -176,6 +180,7 @@

Module bases.alphabet.range_alphabet

return ord(char.upper()) in alphabet.codepoints or ord(char.lower()) in alphabet.codepoints def __getitem__(self, char: str) -> int: + validate(char, str) alphabet = self._alphabet if ord(char) in alphabet.codepoints: return ord(char)-alphabet.codepoints.start @@ -233,6 +238,7 @@

Classes

def __init__(self, codepoints: range, *, case_sensitive: bool = True): super().__init__(case_sensitive) + validate(codepoints, range) self._codepoints = codepoints self._revdir = _RangeAlphabetRevdir(self) self.__validate_init() @@ -280,12 +286,14 @@

Classes

... def __getitem__(self, idx: Union[int, slice]) -> Union[str, "RangeAlphabet"]: + validate(idx, Union[int, slice]) if isinstance(idx, slice): new_codepoints = self._codepoints[idx] return RangeAlphabet(new_codepoints, case_sensitive=self.case_sensitive) return chr(self._codepoints[idx]) def with_case_sensitivity(self, case_sensitive: bool) -> "RangeAlphabet": + validate(case_sensitive, bool) if case_sensitive == self.case_sensitive: return self return RangeAlphabet(self.codepoints, case_sensitive=case_sensitive) diff --git a/docs/bases/alphabet/string_alphabet.html b/docs/bases/alphabet/string_alphabet.html index cb1c560..11f071e 100644 --- a/docs/bases/alphabet/string_alphabet.html +++ b/docs/bases/alphabet/string_alphabet.html @@ -34,6 +34,7 @@

Module bases.alphabet.string_alphabet

from types import MappingProxyType from typing import Any, Mapping, overload, Union +from typing_validation import validate from .abstract import Alphabet @@ -60,6 +61,7 @@

Module bases.alphabet.string_alphabet

def __init__(self, chars: str, *, case_sensitive: bool = True): super().__init__(case_sensitive) + validate(chars, str) self._chars = chars revdir = { c: idx for idx, c in enumerate(chars) @@ -118,12 +120,14 @@

Module bases.alphabet.string_alphabet

... def __getitem__(self, idx: Union[int, slice]) -> Union[str, "StringAlphabet"]: + validate(idx, Union[int, slice]) if isinstance(idx, slice): new_chars = self._chars[idx] return StringAlphabet(new_chars, case_sensitive=self.case_sensitive) return self._chars[idx] def with_case_sensitivity(self, case_sensitive: bool) -> "StringAlphabet": + validate(case_sensitive, bool) if case_sensitive == self.case_sensitive: return self return StringAlphabet(self.chars, case_sensitive=case_sensitive) @@ -206,6 +210,7 @@

Classes

def __init__(self, chars: str, *, case_sensitive: bool = True): super().__init__(case_sensitive) + validate(chars, str) self._chars = chars revdir = { c: idx for idx, c in enumerate(chars) @@ -264,12 +269,14 @@

Classes

... def __getitem__(self, idx: Union[int, slice]) -> Union[str, "StringAlphabet"]: + validate(idx, Union[int, slice]) if isinstance(idx, slice): new_chars = self._chars[idx] return StringAlphabet(new_chars, case_sensitive=self.case_sensitive) return self._chars[idx] def with_case_sensitivity(self, case_sensitive: bool) -> "StringAlphabet": + validate(case_sensitive, bool) if case_sensitive == self.case_sensitive: return self return StringAlphabet(self.chars, case_sensitive=case_sensitive) diff --git a/docs/bases/encoding/base.html b/docs/bases/encoding/base.html index 8c5ea02..48eadf5 100644 --- a/docs/bases/encoding/base.html +++ b/docs/bases/encoding/base.html @@ -34,6 +34,7 @@

Module bases.encoding.base

from abc import ABC, abstractmethod from typing import Any, Mapping, Optional, TypeVar, Union +from typing_validation import validate from bases import alphabet from bases.alphabet import Alphabet @@ -54,6 +55,8 @@

Module bases.encoding.base

def __init__(self, chars: Union[str, range, Alphabet], *, case_sensitive: Optional[bool] = None): + validate(chars, Union[str, range, Alphabet]) + validate(case_sensitive, Optional[bool]) if isinstance(chars, Alphabet): if case_sensitive is not None: chars = chars.with_case_sensitivity(case_sensitive) @@ -129,6 +132,8 @@

Module bases.encoding.base

Returns a new encoding with the same kind and options as this one, but a different alphabet and/or case sensitivity. """ + validate(chars, Union[str, range, Alphabet]) + validate(case_sensitive, Optional[bool]) options = {**self.options()} options["case_sensitive"] = case_sensitive return type(self)(chars, **options) @@ -151,6 +156,7 @@

Module bases.encoding.base

pad_char='=', padding='include') ``` """ + validate(case_sensitive, bool) return self.with_alphabet(self.alphabet.with_case_sensitivity(case_sensitive)) def upper(self: Self) -> Self: @@ -264,13 +270,11 @@

Module bases.encoding.base

def _validate_bytes(self, b: bytes) -> bytes: # pylint: disable = no-self-use - if not isinstance(b, bytes): - raise TypeError() + validate(b, bytes) return b def _validate_string(self, s: str) -> str: - if not isinstance(s, str): - raise TypeError() + validate(s, str) alphabet = self.alphabet for c in s: if c not in alphabet: @@ -357,6 +361,8 @@

Classes

def __init__(self, chars: Union[str, range, Alphabet], *, case_sensitive: Optional[bool] = None): + validate(chars, Union[str, range, Alphabet]) + validate(case_sensitive, Optional[bool]) if isinstance(chars, Alphabet): if case_sensitive is not None: chars = chars.with_case_sensitivity(case_sensitive) @@ -432,6 +438,8 @@

Classes

Returns a new encoding with the same kind and options as this one, but a different alphabet and/or case sensitivity. """ + validate(chars, Union[str, range, Alphabet]) + validate(case_sensitive, Optional[bool]) options = {**self.options()} options["case_sensitive"] = case_sensitive return type(self)(chars, **options) @@ -454,6 +462,7 @@

Classes

pad_char='=', padding='include') ``` """ + validate(case_sensitive, bool) return self.with_alphabet(self.alphabet.with_case_sensitivity(case_sensitive)) def upper(self: Self) -> Self: @@ -567,13 +576,11 @@

Classes

def _validate_bytes(self, b: bytes) -> bytes: # pylint: disable = no-self-use - if not isinstance(b, bytes): - raise TypeError() + validate(b, bytes) return b def _validate_string(self, s: str) -> str: - if not isinstance(s, str): - raise TypeError() + validate(s, str) alphabet = self.alphabet for c in s: if c not in alphabet: @@ -1007,6 +1014,8 @@

Methods

Returns a new encoding with the same kind and options as this one, but a different alphabet and/or case sensitivity. """ + validate(chars, Union[str, range, Alphabet]) + validate(case_sensitive, Optional[bool]) options = {**self.options()} options["case_sensitive"] = case_sensitive return type(self)(chars, **options) @@ -1050,6 +1059,7 @@

Methods

pad_char='=', padding='include') ``` """ + validate(case_sensitive, bool) return self.with_alphabet(self.alphabet.with_case_sensitivity(case_sensitive)) diff --git a/docs/bases/encoding/block.html b/docs/bases/encoding/block.html index 87cf887..71cf89f 100644 --- a/docs/bases/encoding/block.html +++ b/docs/bases/encoding/block.html @@ -35,6 +35,7 @@

Module bases.encoding.block

import math from types import MappingProxyType from typing import Any, Dict, List, Mapping, Optional, Union +from typing_validation import validate from bases.alphabet import Alphabet from .base import BaseEncoding @@ -123,10 +124,13 @@

Module bases.encoding.block

block_size: Union[int, Mapping[int, int]], sep_char: str = "", reverse_blocks: bool = False): + validate(encoding, Union[str, range, Alphabet, BaseEncoding]) + validate(block_size, Union[int, Mapping[int, int]]) + validate(sep_char, str) + validate(reverse_blocks, bool) self._init_encoding = encoding self._init_case_sensitive = case_sensitive self._init_block_size = block_size - if isinstance(encoding, BaseEncoding): alphabet: Union[str, range, Alphabet] = encoding.alphabet else: @@ -251,6 +255,7 @@

Module bases.encoding.block

return b def _validate_string(self, s: str) -> str: + validate(s, str) sep_char = self.sep_char block_nchars = self.block_nchars if sep_char: @@ -323,6 +328,7 @@

Module bases.encoding.block

return b"".join(byte_blocks) def options(self, skip_defaults: bool = False) -> Mapping[str, Any]: + validate(skip_defaults, bool) options: Dict[str, Any] = { "block_size": self._init_block_size, } @@ -517,10 +523,13 @@

Classes

block_size: Union[int, Mapping[int, int]], sep_char: str = "", reverse_blocks: bool = False): + validate(encoding, Union[str, range, Alphabet, BaseEncoding]) + validate(block_size, Union[int, Mapping[int, int]]) + validate(sep_char, str) + validate(reverse_blocks, bool) self._init_encoding = encoding self._init_case_sensitive = case_sensitive self._init_block_size = block_size - if isinstance(encoding, BaseEncoding): alphabet: Union[str, range, Alphabet] = encoding.alphabet else: @@ -645,6 +654,7 @@

Classes

return b def _validate_string(self, s: str) -> str: + validate(s, str) sep_char = self.sep_char block_nchars = self.block_nchars if sep_char: @@ -717,6 +727,7 @@

Classes

return b"".join(byte_blocks) def options(self, skip_defaults: bool = False) -> Mapping[str, Any]: + validate(skip_defaults, bool) options: Dict[str, Any] = { "block_size": self._init_block_size, } diff --git a/docs/bases/encoding/errors.html b/docs/bases/encoding/errors.html index 72c3aa6..d17dced 100644 --- a/docs/bases/encoding/errors.html +++ b/docs/bases/encoding/errors.html @@ -33,6 +33,7 @@

Module bases.encoding.errors

""" import binascii +from typing_validation import validate from bases.alphabet import Alphabet @@ -58,6 +59,8 @@

Module bases.encoding.errors

base: int def __init__(self, digit: int, base: int) -> None: + validate(digit, int) + validate(base, int) self.digit = digit self.base = base if 0 <= digit < base: @@ -87,6 +90,8 @@

Module bases.encoding.errors

alphabet: Alphabet def __init__(self, char: str, alphabet: Alphabet) -> None: + validate(char, str) + validate(alphabet, Alphabet) self.char = char self.alphabet = alphabet if char in alphabet: @@ -103,6 +108,8 @@

Module bases.encoding.errors

expected_padding: int def __init__(self, padding: int, expected_padding: int) -> None: + validate(padding, int) + validate(expected_padding, int) self.padding = padding self.expected_padding = expected_padding if padding < expected_padding: @@ -292,6 +299,8 @@

Ancestors

base: int def __init__(self, digit: int, base: int) -> None: + validate(digit, int) + validate(base, int) self.digit = digit self.base = base if 0 <= digit < base: @@ -341,6 +350,8 @@

Class variables

alphabet: Alphabet def __init__(self, char: str, alphabet: Alphabet) -> None: + validate(char, str) + validate(alphabet, Alphabet) self.char = char self.alphabet = alphabet if char in alphabet: @@ -388,6 +399,8 @@

Class variables

expected_padding: int def __init__(self, padding: int, expected_padding: int) -> None: + validate(padding, int) + validate(expected_padding, int) self.padding = padding self.expected_padding = expected_padding if padding < expected_padding: diff --git a/docs/bases/encoding/fixchar.html b/docs/bases/encoding/fixchar.html index 80affb5..b6ad3b3 100644 --- a/docs/bases/encoding/fixchar.html +++ b/docs/bases/encoding/fixchar.html @@ -35,6 +35,7 @@

Module bases.encoding.fixchar

import math from typing import Any, Dict, List, Mapping, Optional, Union from typing_extensions import Literal +from typing_validation import validate from bases.alphabet import Alphabet from .base import BaseEncoding @@ -125,6 +126,9 @@

Module bases.encoding.fixchar

char_nbits: Union[int, Literal["auto"]] = "auto", pad_char: Optional[str] = None, padding: PaddingOptions = "ignore"): + validate(char_nbits, Union[int, Literal["auto"]]) + validate(pad_char, Optional[str]) + validate(padding, PaddingOptions) if padding not in ("ignore", "include", "require"): raise TypeError("Allowed padding options are: 'ignore', 'include' and 'require'.") super().__init__(alphabet, case_sensitive=case_sensitive) @@ -251,6 +255,7 @@

Module bases.encoding.fixchar

pad_char='=', padding='include') ``` """ + validate(require, bool) options = dict(padding="require" if require else "include") return self.with_options(**options) @@ -278,6 +283,7 @@

Module bases.encoding.fixchar

case_sensitive=False)) ``` """ + validate(allow, bool) options = dict(padding="ignore", pad_char=self.pad_char if allow else None) return self.with_options(**options) @@ -302,6 +308,7 @@

Module bases.encoding.fixchar

``` """ + validate(pad_char, Optional[str]) options: Dict[str, Any] = dict(pad_char=pad_char) if pad_char is None: options["padding"] = "ignore" @@ -316,8 +323,7 @@

Module bases.encoding.fixchar

The value of `FixcharBaseEncoding.padding` is irrelevant to this method. """ - if not isinstance(s, str): - raise TypeError() + validate(s, str) pad_char = self.pad_char block_nchars = self._block_nchars # no padding available for this encoding scheme @@ -339,8 +345,7 @@

Module bases.encoding.fixchar

If `FixcharBaseEncoding.padding` is set to `"require"`, checks that the correct number of padding characters were included and raises `bases.encoding.errors.PaddingError` if not. """ - if not isinstance(s, str): - raise TypeError() + validate(s, str) pad_char = self.pad_char case_sensitive = self.case_sensitive block_nchars = self._block_nchars @@ -367,6 +372,7 @@

Module bases.encoding.fixchar

return b def canonical_string(self, s: str) -> str: + validate(s, str) if self.include_padding: return self.pad_string(s) return self.strip_string(s) @@ -425,6 +431,7 @@

Module bases.encoding.fixchar

return i.to_bytes(length=original_nbytes, byteorder="big") def options(self, skip_defaults: bool = False) -> Mapping[str, Any]: + validate(skip_defaults, bool) options: Dict[str, Any] = {} if not skip_defaults or self._init_char_nbits != "auto": options["char_nbits"] = self._init_char_nbits @@ -579,6 +586,9 @@

Classes

char_nbits: Union[int, Literal["auto"]] = "auto", pad_char: Optional[str] = None, padding: PaddingOptions = "ignore"): + validate(char_nbits, Union[int, Literal["auto"]]) + validate(pad_char, Optional[str]) + validate(padding, PaddingOptions) if padding not in ("ignore", "include", "require"): raise TypeError("Allowed padding options are: 'ignore', 'include' and 'require'.") super().__init__(alphabet, case_sensitive=case_sensitive) @@ -705,6 +715,7 @@

Classes

pad_char='=', padding='include') ``` """ + validate(require, bool) options = dict(padding="require" if require else "include") return self.with_options(**options) @@ -732,6 +743,7 @@

Classes

case_sensitive=False)) ``` """ + validate(allow, bool) options = dict(padding="ignore", pad_char=self.pad_char if allow else None) return self.with_options(**options) @@ -756,6 +768,7 @@

Classes

``` """ + validate(pad_char, Optional[str]) options: Dict[str, Any] = dict(pad_char=pad_char) if pad_char is None: options["padding"] = "ignore" @@ -770,8 +783,7 @@

Classes

The value of `FixcharBaseEncoding.padding` is irrelevant to this method. """ - if not isinstance(s, str): - raise TypeError() + validate(s, str) pad_char = self.pad_char block_nchars = self._block_nchars # no padding available for this encoding scheme @@ -793,8 +805,7 @@

Classes

If `FixcharBaseEncoding.padding` is set to `"require"`, checks that the correct number of padding characters were included and raises `bases.encoding.errors.PaddingError` if not. """ - if not isinstance(s, str): - raise TypeError() + validate(s, str) pad_char = self.pad_char case_sensitive = self.case_sensitive block_nchars = self._block_nchars @@ -821,6 +832,7 @@

Classes

return b def canonical_string(self, s: str) -> str: + validate(s, str) if self.include_padding: return self.pad_string(s) return self.strip_string(s) @@ -879,6 +891,7 @@

Classes

return i.to_bytes(length=original_nbytes, byteorder="big") def options(self, skip_defaults: bool = False) -> Mapping[str, Any]: + validate(skip_defaults, bool) options: Dict[str, Any] = {} if not skip_defaults or self._init_char_nbits != "auto": options["char_nbits"] = self._init_char_nbits @@ -1065,6 +1078,7 @@

Methods

case_sensitive=False)) ``` """ + validate(allow, bool) options = dict(padding="ignore", pad_char=self.pad_char if allow else None) return self.with_options(**options) @@ -1144,6 +1158,7 @@

Methods

pad_char='=', padding='include') ``` """ + validate(require, bool) options = dict(padding="require" if require else "include") return self.with_options(**options) @@ -1170,8 +1185,7 @@

Methods

The value of `FixcharBaseEncoding.padding` is irrelevant to this method. """ - if not isinstance(s, str): - raise TypeError() + validate(s, str) pad_char = self.pad_char block_nchars = self._block_nchars # no padding available for this encoding scheme @@ -1207,8 +1221,7 @@

Methods

If `FixcharBaseEncoding.padding` is set to `"require"`, checks that the correct number of padding characters were included and raises `bases.encoding.errors.PaddingError` if not. """ - if not isinstance(s, str): - raise TypeError() + validate(s, str) pad_char = self.pad_char case_sensitive = self.case_sensitive block_nchars = self._block_nchars @@ -1274,6 +1287,7 @@

Methods

``` """ + validate(pad_char, Optional[str]) options: Dict[str, Any] = dict(pad_char=pad_char) if pad_char is None: options["padding"] = "ignore" diff --git a/docs/bases/encoding/index.html b/docs/bases/encoding/index.html index 559db31..f64c412 100644 --- a/docs/bases/encoding/index.html +++ b/docs/bases/encoding/index.html @@ -135,6 +135,7 @@

Module bases.encoding

import re from typing import Any, cast, Collection, Dict, Iterator, Mapping, Optional, overload, Tuple, Type, Union from typing_extensions import Literal +from typing_validation import validate from bases import alphabet from bases.alphabet import Alphabet @@ -161,6 +162,7 @@

Module bases.encoding

block_nchars=2) ``` """ + validate(name, str) if name not in _base_encodings: raise KeyError(f"Encoding named {repr(name)} does not exist.") return _base_encodings[name] @@ -173,6 +175,7 @@

Module bases.encoding

True ``` """ + validate(name, str) return name in _base_encodings def register(**kwargs: BaseEncoding) -> None: @@ -198,6 +201,8 @@

Module bases.encoding

re.match(r"^base[0-9][a-zA-Z0-9_]*$", name) ``` """ + for arg in kwargs.values(): + validate(arg, BaseEncoding) for name, encoding in kwargs.items(): if not re.match(r"^base[0-9][a-zA-Z0-9_]*$", name): raise ValueError(f"Invalid encoding name {repr(name)}") @@ -233,6 +238,8 @@

Module bases.encoding

block_nchars=2) ``` """ + for name in names: + validate(name, str) for name in names: if name not in _base_encodings: raise KeyError(f"Encoding named {repr(name)} does not exist.") @@ -262,6 +269,7 @@

Module bases.encoding

``` """ + validate(prefix, str) encodings = [(name, encoding) for name, encoding in _base_encodings.items() if name.startswith(prefix)] encodings = sorted(encodings, key=lambda pair: pair[0]) @@ -320,6 +328,10 @@

Module bases.encoding

``` """ + validate(chars, Union[str, range, Alphabet, BaseEncoding]) + validate(kind, str) + validate(name, Optional[str]) + validate(case_sensitive, Optional[bool]) kwargs["case_sensitive"] = case_sensitive if kind == "simple-enc": if isinstance(chars, BaseEncoding): @@ -554,6 +566,7 @@

Functions

block_nchars=2) ``` """ + validate(name, str) if name not in _base_encodings: raise KeyError(f"Encoding named {repr(name)} does not exist.") return _base_encodings[name] @@ -579,6 +592,7 @@

Functions

True ``` """ + validate(name, str) return name in _base_encodings @@ -641,6 +655,10 @@

Functions

``` """ + validate(chars, Union[str, range, Alphabet, BaseEncoding]) + validate(kind, str) + validate(name, Optional[str]) + validate(case_sensitive, Optional[bool]) kwargs["case_sensitive"] = case_sensitive if kind == "simple-enc": if isinstance(chars, BaseEncoding): @@ -708,6 +726,8 @@

Functions

re.match(r"^base[0-9][a-zA-Z0-9_]*$", name) ``` """ + for arg in kwargs.values(): + validate(arg, BaseEncoding) for name, encoding in kwargs.items(): if not re.match(r"^base[0-9][a-zA-Z0-9_]*$", name): raise ValueError(f"Invalid encoding name {repr(name)}") @@ -767,6 +787,7 @@

Functions

``` """ + validate(prefix, str) encodings = [(name, encoding) for name, encoding in _base_encodings.items() if name.startswith(prefix)] encodings = sorted(encodings, key=lambda pair: pair[0]) @@ -824,6 +845,8 @@

Functions

block_nchars=2) ``` """ + for name in names: + validate(name, str) for name in names: if name not in _base_encodings: raise KeyError(f"Encoding named {repr(name)} does not exist.") diff --git a/docs/bases/encoding/simple.html b/docs/bases/encoding/simple.html index bad6b97..ad8956b 100644 --- a/docs/bases/encoding/simple.html +++ b/docs/bases/encoding/simple.html @@ -33,6 +33,7 @@

Module bases.encoding.simple

""" from typing import Any, List, Mapping, Optional, Union +from typing_validation import validate from bases.alphabet import Alphabet from .base import BaseEncoding @@ -107,6 +108,7 @@

Module bases.encoding.simple

return i.to_bytes(length=nbytes, byteorder="big") def options(self, skip_defaults: bool = False) -> Mapping[str, Any]: + validate(skip_defaults, bool) return {} @@ -210,6 +212,7 @@

Classes

return i.to_bytes(length=nbytes, byteorder="big") def options(self, skip_defaults: bool = False) -> Mapping[str, Any]: + validate(skip_defaults, bool) return {}

Ancestors

diff --git a/docs/bases/encoding/zeropad.html b/docs/bases/encoding/zeropad.html index 92a0342..db2de64 100644 --- a/docs/bases/encoding/zeropad.html +++ b/docs/bases/encoding/zeropad.html @@ -34,6 +34,7 @@

Module bases.encoding.zeropad

import math from typing import Any, Dict, Mapping, Optional, Union +from typing_validation import validate from bases.alphabet import Alphabet from .base import BaseEncoding @@ -79,6 +80,8 @@

Module bases.encoding.zeropad

case_sensitive: Optional[bool] = None, block_nbytes: int = 1, block_nchars: int = 1): + validate(block_nbytes, int) + validate(block_nchars, int) super().__init__(alphabet, case_sensitive=case_sensitive) self._simple_encoding = SimpleBaseEncoding(self.alphabet) self._block_nbytes = block_nbytes @@ -109,6 +112,8 @@

Module bases.encoding.zeropad

256**block_nbytes > base**(block_nchars-1) ``` """ + validate(base, int) + validate(block_nbytes, int) if base <= 1: raise ValueError("Base must be >= 2.") if block_nbytes <= 0: @@ -127,6 +132,8 @@

Module bases.encoding.zeropad

base**block_nchars > 256**(block_nbytes-1) ``` """ + validate(base, int) + validate(block_nchars, int) if base <= 1: raise ValueError("Base must be >= 2.") if block_nchars <= 0: @@ -204,6 +211,7 @@

Module bases.encoding.zeropad

return b def options(self, skip_defaults: bool = False) -> Mapping[str, Any]: + validate(skip_defaults, bool) options: Dict[str, Any] = {} if not skip_defaults or self.block_nbytes != 1: options["block_nbytes"] = self.block_nbytes @@ -297,6 +305,8 @@

Classes

case_sensitive: Optional[bool] = None, block_nbytes: int = 1, block_nchars: int = 1): + validate(block_nbytes, int) + validate(block_nchars, int) super().__init__(alphabet, case_sensitive=case_sensitive) self._simple_encoding = SimpleBaseEncoding(self.alphabet) self._block_nbytes = block_nbytes @@ -327,6 +337,8 @@

Classes

256**block_nbytes > base**(block_nchars-1) ``` """ + validate(base, int) + validate(block_nbytes, int) if base <= 1: raise ValueError("Base must be >= 2.") if block_nbytes <= 0: @@ -345,6 +357,8 @@

Classes

base**block_nchars > 256**(block_nbytes-1) ``` """ + validate(base, int) + validate(block_nchars, int) if base <= 1: raise ValueError("Base must be >= 2.") if block_nchars <= 0: @@ -422,6 +436,7 @@

Classes

return b def options(self, skip_defaults: bool = False) -> Mapping[str, Any]: + validate(skip_defaults, bool) options: Dict[str, Any] = {} if not skip_defaults or self.block_nbytes != 1: options["block_nbytes"] = self.block_nbytes @@ -456,6 +471,8 @@

Static methods

base**block_nchars > 256**(block_nbytes-1) ``` """ + validate(base, int) + validate(block_nchars, int) if base <= 1: raise ValueError("Base must be >= 2.") if block_nchars <= 0: @@ -485,6 +502,8 @@

Static methods

256**block_nbytes > base**(block_nchars-1) ``` """ + validate(base, int) + validate(block_nbytes, int) if base <= 1: raise ValueError("Base must be >= 2.") if block_nbytes <= 0: diff --git a/docs/bases/index.html b/docs/bases/index.html index 3403379..534a75f 100644 --- a/docs/bases/index.html +++ b/docs/bases/index.html @@ -133,6 +133,8 @@

Package bases

""" +__version__ = "0.2.0" + from . import encoding as encoding from . import alphabet as alphabet from .encoding import (base2, base16, base8, base10, base36, base58btc, base58flickr, base58ripple, diff --git a/docs/bases/random.html b/docs/bases/random.html index f306017..40c82cd 100644 --- a/docs/bases/random.html +++ b/docs/bases/random.html @@ -119,6 +119,7 @@

Module bases.random

from random import Random # pylint: disable = import-self from types import MappingProxyType from typing import Any, Dict, Iterator, Mapping, Optional +from typing_validation import validate from .alphabet import Alphabet from .encoding import BaseEncoding, SimpleBaseEncoding, ZeropadBaseEncoding, BlockBaseEncoding, FixcharBaseEncoding @@ -179,6 +180,8 @@

Module bases.random

See `set_options` for a description of the options. """ # pylint: disable = too-many-locals + for arg in (seed, min_bytes, max_bytes, min_chars, max_chars): + validate(arg, Optional[int]) global _options global _rand try: @@ -212,6 +215,8 @@

Module bases.random

""" # pylint: disable = too-many-branches, too-many-locals, too-many-statements + for arg in (seed, min_bytes, max_bytes, min_chars, max_chars): + validate(arg, Optional[int]) global _options global _rand # set newly passed options @@ -264,6 +269,8 @@

Module bases.random

[0, 96, 63]] ``` """ + validate(n, Optional[int]) + validate(encoding, Optional[BaseEncoding]) if encoding is None: return rand_raw_bytes(n) if isinstance(encoding, SimpleBaseEncoding): @@ -284,6 +291,9 @@

Module bases.random

The optional `min_bytes` and `max_bytes` parameters can be used to set a minimum/maximum length for the `bytes` objects: if `None`, the values are fetched from `get_options`. """ + validate(n, Optional[int]) + validate(min_bytes, Optional[int]) + validate(max_bytes, Optional[int]) if n is not None and n < 0: raise ValueError() if min_bytes is None: @@ -385,6 +395,9 @@

Module bases.random

``` """ + validate(n, Optional[int]) + validate(encoding, Optional[BaseEncoding]) + validate(alphabet, Optional[Alphabet]) if encoding is None: if alphabet is None: raise ValueError("One of 'encoding' or 'alphabet' must be specified.") @@ -646,6 +659,8 @@

Functions

See `set_options` for a description of the options. """ # pylint: disable = too-many-locals + for arg in (seed, min_bytes, max_bytes, min_chars, max_chars): + validate(arg, Optional[int]) global _options global _rand try: @@ -731,6 +746,8 @@

Functions

[0, 96, 63]] ``` """ + validate(n, Optional[int]) + validate(encoding, Optional[BaseEncoding]) if encoding is None: return rand_raw_bytes(n) if isinstance(encoding, SimpleBaseEncoding): @@ -793,6 +810,9 @@

Functions

The optional `min_bytes` and `max_bytes` parameters can be used to set a minimum/maximum length for the `bytes` objects: if `None`, the values are fetched from `get_options`. """ + validate(n, Optional[int]) + validate(min_bytes, Optional[int]) + validate(max_bytes, Optional[int]) if n is not None and n < 0: raise ValueError() if min_bytes is None: @@ -846,6 +866,9 @@

Functions

``` """ + validate(n, Optional[int]) + validate(encoding, Optional[BaseEncoding]) + validate(alphabet, Optional[Alphabet]) if encoding is None: if alphabet is None: raise ValueError("One of 'encoding' or 'alphabet' must be specified.") @@ -916,6 +939,8 @@

Functions

""" # pylint: disable = too-many-branches, too-many-locals, too-many-statements + for arg in (seed, min_bytes, max_bytes, min_chars, max_chars): + validate(arg, Optional[int]) global _options global _rand # set newly passed options diff --git a/setup.cfg b/setup.cfg index 9615180..b4f0b9f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -19,16 +19,16 @@ classifiers = Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.7 - Programming Language :: Python :: 3.6 Operating System :: OS Independent Natural Language :: English Typing :: Typed [options] packages = find: -python_requires = >=3.6 +python_requires = >=3.7 install_requires = - typing_extensions + typing-extensions + typing-validation [options.package_data] * = py.typed diff --git a/tox.ini b/tox.ini index cad94b2..c0ca378 100644 --- a/tox.ini +++ b/tox.ini @@ -1,10 +1,11 @@ # content of: tox.ini, put in same dir as setup.py [tox] -envlist = py36, py37, py38, py39, py310 +envlist = py37, py38, py39, py310 isolated_build = True [testenv] deps = + -rrequirements.txt mypy pylint pytest