Skip to content

Commit

Permalink
PEP 561 x 3.
Browse files Browse the repository at this point in the history
This commit is the next in a commit chain rendering `beartype` compliant
with PEP 561 by annotating the codebase in a manner specifically
compatible with the most popular third-party static type checker, mypy,
en-route to eventually resolving issue #25 kindly submitted also by best
macOS package manager ever @harens. Specifically, this commit trivially
revises a number of type hints and docstrings for clarity. So it goes.
(*Unmentionable ions!*)
  • Loading branch information
leycec committed Feb 17, 2021
1 parent 4944835 commit c9ca6f5
Show file tree
Hide file tree
Showing 16 changed files with 112 additions and 110 deletions.
14 changes: 9 additions & 5 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
# Template with which setuptools generates this project's "MANIFEST" file.

# ....................{ INCLUDE }....................
# Include all requisite top-level installation-time files.
# Include all requisite top-level install-time files.
.mypy.ini
.readthedocs.yml
include LICENSE
include MANIFEST.in
Expand All @@ -17,12 +18,15 @@ include setup.cfg
include setup.py
include tox.ini

# Include all requisite package-level install-time files.
beartype/py.typed

# ....................{ INCLUDE ~ recursive }....................
# Include all requisite project-specific py.test and setuptools subpackages.
# Include all requisite project-specific test packages.
#
# Note that these subpackages are *ONLY* required at installation time and
# hence omitted from the "packages" key passed to the setup() function by
# "setup.py". Welcome to Setuptools Hell, dear friend.
# Note that these packages are *ONLY* required at test time and hence omitted
# from the "packages" key passed to the setup() function by "setup.py". Welcome
# to Setuptools Hell, dear friend.
recursive-include beartype_test *

# Include all optional documentation.
Expand Down
5 changes: 5 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1059,6 +1059,8 @@ Let's chart current and future compliance with Python's `typing`_ landscape:
+------------------+-----------------------------------------+-------------------------------+---------------------------+
| | `593 <PEP 593_>`__ | **0.4.0**\ \ *current* | **0.4.0**\ \ *current* |
+------------------+-----------------------------------------+-------------------------------+---------------------------+
| | `604 <PEP 604_>`__ | *none* | *none* |
+------------------+-----------------------------------------+-------------------------------+---------------------------+
| packages | `PyPI <beartype PyPI_>`__ | **0.1.0**\ \ *current* ||
+------------------+-----------------------------------------+-------------------------------+---------------------------+
| | `Anaconda <beartype Anaconda_>`__ | **0.1.0**\ \ *current* ||
Expand Down Expand Up @@ -1404,6 +1406,7 @@ Compliance
* `PEP 589 -- TypedDict: Type Hints for Dictionaries with a Fixed Set of Keys
<PEP 589_>`__.
* `PEP 591 -- Adding a final qualifier to typing <PEP 591_>`__.
* `PEP 604 -- Adding a final qualifier to typing <PEP 604_>`__.

See also the **PEP** and **typing** categories of our `features matrix
<Features_>`__ for further details.
Expand Down Expand Up @@ -3073,6 +3076,8 @@ application stack at tool rather than Python runtime) include:
https://www.python.org/dev/peps/pep-0591
.. _PEP 593:
https://www.python.org/dev/peps/pep-0593
.. _PEP 604:
https://www.python.org/dev/peps/pep-0604
.. _PEP 3141:
https://www.python.org/dev/peps/pep-3141

Expand Down
17 changes: 9 additions & 8 deletions beartype/_util/cache/pool/utilcachepool.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@

# ....................{ IMPORTS }....................
from beartype.roar import _BeartypeUtilCachedKeyPoolException
from collections import defaultdict, abc
from collections import defaultdict
from collections.abc import Hashable
from threading import Lock
from typing import Any, Hashable, Dict
from typing import Any, Callable, Dict

# ....................{ CLASSES }....................
class KeyPool(object):
Expand Down Expand Up @@ -75,14 +76,14 @@ class KeyPool(object):
# ..................{ INITIALIZER }..................
def __init__(
self,
item_maker: 'abc.Callable[Hashable, Any]',
item_maker: Callable[[Hashable,], Any],
) -> None:
'''
Initialize this key pool with the passed factory callable.
Parameters
----------
item_maker : collections.abc.Callable[(HashableType,), Any]
item_maker : Callable[Hashable, Any]
Caller-defined factory callable internally called by the
:meth:`acquire` method on attempting to acquire a non-existent
object from an **empty pool** (i.e., either a missing key *or* an
Expand All @@ -95,8 +96,8 @@ def __init__(
.. code-block:: python
from beartype.cave import HashableType
def item_maker(key: HashableType) -> object: ...
from collections.abc import Hashable
def item_maker(key: Hashable) -> object: ...
'''
assert callable(item_maker), f'{repr(item_maker)} not callable.'

Expand All @@ -118,7 +119,7 @@ def item_maker(key: HashableType) -> object: ...
self._thread_lock = Lock()

# ..................{ METHODS }..................
def acquire(self, key: 'Hashable' = None) -> object:
def acquire(self, key: Hashable = None) -> object:
'''
Acquire an arbitrary object associated with the passed **arbitrary
key** (i.e., hashable object).
Expand Down Expand Up @@ -189,7 +190,7 @@ def acquire(self, key: 'Hashable' = None) -> object:
return pool_item


def release(self, item: object, key: 'Hashable' = None) -> None:
def release(self, item: object, key: Hashable = None) -> None:
'''
Release the passed object acquired by a prior call to the
:meth:`acquire` method passed the same passed **arbitrary key** (i.e.,
Expand Down
50 changes: 23 additions & 27 deletions beartype/_util/cache/pool/utilcachepoollistfixed.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,13 @@ def __init__(self, size: int) -> None:
# If this length is *NOT* an integer, raise an exception.
if not isinstance(size, int):
raise _BeartypeUtilCachedFixedListException(
'Fixed list length {!r} not integer.'.format(size))
f'Fixed list length {repr(size)} not integer.')
# Else, this length is an integer.

# If this length is non-positive, raise an exception.
if size <= 0:
raise _BeartypeUtilCachedFixedListException(
'Fixed list length {!r} <= 0.'.format(size))
f'Fixed list length {size} <= 0.')
# Else, this length is positive.

# Make it so with the standard Python idiom for preallocating list
Expand Down Expand Up @@ -122,19 +122,19 @@ def copy(self) -> 'FixedList':

def __delitem__(self, index):
raise _BeartypeUtilCachedFixedListException(
'{} index {!r} not deletable.'.format(self._label, index))
f'{self._label} index {repr(index)} not deletable.')


def __iadd__(self, value):
raise _BeartypeUtilCachedFixedListException(
'{} not addable by {}.'.format(
self._label, get_object_representation(value)))
f'{self._label} not addable by '
f'{get_object_representation(value)}.')


def __imul__(self, value):
raise _BeartypeUtilCachedFixedListException(
'{} not multipliable by {}.'.format(
self._label, get_object_representation(value)))
f'{self._label} not multipliable by '
f'{get_object_representation(value)}.')

# ..................{ BAD ~ dunders : setitem }..................
def __setitem__(self, index, value):
Expand Down Expand Up @@ -193,8 +193,8 @@ def _die_if_slice_len_ne_value_len(self, index, value) -> None:
# If this value is *NOT* a sized container, raise an exception.
if not isinstance(value, Sized):
raise _BeartypeUtilCachedFixedListException(
'{} slice {!r} not settable to unsized {}.'.format(
self._label, index, get_object_representation(value)))
f'{self._label} slice {repr(index)} not settable to unsized '
f'{get_object_representation(value)}.')
# Else, this value is a sized container.

# 0-based first and one-past-the-last indices sliced by this slice.
Expand All @@ -210,44 +210,40 @@ def _die_if_slice_len_ne_value_len(self, index, value) -> None:
# If these two lengths differ, raise an exception.
if slice_len != value_len:
raise _BeartypeUtilCachedFixedListException(
'{} slice {!r} of length {} not settable to '
'{} of differing length {}.'.format(
self._label,
index,
slice_len,
get_object_representation(value),
value_len,
))
f'{self._label} slice {repr(index)} of length {slice_len} not '
f'settable to {get_object_representation(value)} of differing '
f'length {value_len}.'
)

# ..................{ BAD ~ non-dunders }..................
# Prohibit non-dunder methods modifying list length by overriding these
# methods to raise exceptions.

def append(self, obj) -> None:
raise _BeartypeUtilCachedFixedListException(
'{} not appendable by {}.'.format(
self._label, get_object_representation(obj)))
f'{self._label} not appendable by '
f'{get_object_representation(obj)}.')


def clear(self) -> None:
raise _BeartypeUtilCachedFixedListException(
'{} not clearable.'.format(self._label))
f'{self._label} not clearable.')


def extend(self, obj) -> None:
raise _BeartypeUtilCachedFixedListException(
'{} not extendable by {}.'.format(
self._label, get_object_representation(obj)))
f'{self._label} not extendable by '
f'{get_object_representation(obj)}.')


def pop(self, *args) -> None:
raise _BeartypeUtilCachedFixedListException(
'{} not poppable.'.format(self._label))
f'{self._label} not poppable.')


def remove(self, *args) -> None:
raise _BeartypeUtilCachedFixedListException(
'{} not removable.'.format(self._label))
f'{self._label} not removable.')

# ..................{ PRIVATE ~ property }..................
# Read-only properties intentionally prohibiting mutation.
Expand All @@ -264,7 +260,7 @@ def _label(self) -> str:
'''

# One-liners for magnanimous pusillanimousness.
return 'Fixed list ' + get_object_representation(self)
return f'Fixed list {get_object_representation(self)}'

# ....................{ SINGLETONS ~ private }....................
_fixed_list_pool = KeyPool(item_maker=FixedList)
Expand Down Expand Up @@ -319,7 +315,7 @@ def acquire_fixed_list(size: int) -> FixedList:
# Thread-safely acquire a fixed list of this length.
fixed_list = _fixed_list_pool.acquire(size)
assert isinstance(fixed_list, FixedList), (
'{!r} not a fixed list.'.format(fixed_list))
f'{repr(fixed_list)} not fixed list.')

# Return this list.
return fixed_list
Expand Down Expand Up @@ -354,7 +350,7 @@ def release_fixed_list(fixed_list: FixedList) -> None:
Previously acquired fixed list to be released.
'''
assert isinstance(fixed_list, FixedList), (
'{!r} not a fixed list.'.format(fixed_list))
f'{repr(fixed_list)} not fixed list.')

# Thread-safely release this fixed list.
_fixed_list_pool.release(key=len(fixed_list), item=fixed_list)
4 changes: 2 additions & 2 deletions beartype/_util/cache/utilcachecall.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
from beartype._util.utilobject import SENTINEL, Iota
from functools import wraps
from inspect import Parameter
from typing import Callable, Optional
from typing import Callable
from warnings import warn

# ....................{ CONSTANTS ~ private }....................
Expand Down Expand Up @@ -70,7 +70,7 @@
'''

# ....................{ DECORATORS }....................
def callable_cached(func: 'Callable') -> 'Callable':
def callable_cached(func: Callable) -> Callable:
'''
**Memoize** (i.e., efficiently cache and return all previously returned
values of the passed callable as well as all previously raised exceptions
Expand Down
6 changes: 3 additions & 3 deletions beartype/_util/cache/utilcachelru.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def __init__(self, size: int) -> None:

def __getitem__(
self,
key: 'Hashable',
key: Hashable,

# Superclass methods efficiently localized as default parameters.
__dict_delitem=dict.__delitem__,
Expand Down Expand Up @@ -185,7 +185,7 @@ def __getitem__(

def __setitem__(
self,
key: 'Hashable',
key: Hashable,
value: object,

# Superclass methods efficiently localized as default parameters.
Expand Down Expand Up @@ -239,7 +239,7 @@ def __setitem__(

def __contains__(
self,
key: 'Hashable',
key: Hashable,

# Superclass methods efficiently localized as default parameters.
__dict_contains = dict.__contains__,
Expand Down
4 changes: 2 additions & 2 deletions beartype/_util/hint/data/pep/proposal/utilhintdatapep593.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
'''

# ....................{ IMPORTS }....................
from beartype.cave import ModuleType
from beartype._util.py.utilpyversion import IS_PYTHON_AT_LEAST_3_9
from types import ModuleType

# See the "beartype.__init__" submodule for further commentary.
__all__ = ['STAR_IMPORTS_CONSIDERED_HARMFUL']

# ....................{ ADDERS }....................
def add_data(data_module: 'ModuleType') -> None:
def add_data(data_module: ModuleType) -> None:
'''
Add `PEP 593`_**-compliant type hint data to various global containers
declared by the passed module.
Expand Down
4 changes: 2 additions & 2 deletions beartype/_util/hint/pep/proposal/utilhintpep484.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

# ....................{ TESTERS ~ ignorable }....................
def is_hint_pep484_ignorable_or_none(
hint: object, hint_sign: object) -> 'Optional[bool]':
hint: object, hint_sign: object) -> Optional[bool]:
'''
``True`` only if the passed object is a `PEP 484`_-compliant **ignorable
type hint,** ``False`` only if this object is a `PEP 484`_-compliant
Expand Down Expand Up @@ -563,7 +563,7 @@ def get_hint_pep484_generic_base_erased_from_unerased(hint: object) -> type:


@callable_cached
def get_hint_pep484_generic_bases_unerased(hint: object) -> 'Tuple[object]':
def get_hint_pep484_generic_bases_unerased(hint: object) -> Tuple[object]:
'''
Tuple of all unerased :mod:`typing` **pseudo-superclasses** (i.e.,
:mod:`typing` objects originally listed as superclasses prior to their
Expand Down
6 changes: 3 additions & 3 deletions beartype/_util/hint/pep/proposal/utilhintpep544.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from typing import Protocol

def is_hint_pep544_ignorable_or_none(
hint: object, hint_sign: object) -> 'Optional[bool]':
hint: object, hint_sign: object) -> Optional[bool]:

# Return either:
# * If this hint is the "typing.Protocol" superclass directly
Expand Down Expand Up @@ -88,7 +88,7 @@ def is_hint_pep544_protocol(hint: object) -> bool:
# to unconditionally return False.
else:
def is_hint_pep544_ignorable_or_none(
hint: object, hint_sign: object) -> 'Optional[bool]':
hint: object, hint_sign: object) -> Optional[bool]:
return None


Expand Down Expand Up @@ -212,7 +212,7 @@ def noop(param_hint_ignorable: Protocol[T]) -> T: pass
'''

# ....................{ GETTTERS }....................
def get_hint_pep544_io_protocol_from_generic(hint: object) -> 'Protocol':
def get_hint_pep544_io_protocol_from_generic(hint: object) -> type:
'''
`PEP 544`_-compliant :mod:`beartype` **IO protocol** (i.e., either
:class:`beartype._util.hint.data.pep.proposal.utilhintdatapep544._Pep544IO`
Expand Down
6 changes: 3 additions & 3 deletions beartype/_util/hint/pep/proposal/utilhintpep585.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ def is_hint_pep585_generic(hint: object) -> bool:
'''

# ....................{ GETTERS }....................
def get_hint_pep585_generic_bases_unerased(hint: object) -> 'Tuple[object]':
def get_hint_pep585_generic_bases_unerased(hint: object) -> Tuple[object]:
'''
Tuple of all unerased `PEP 585`_-compliant **pseudo-superclasses** (i.e.,
:mod:`typing` objects originally listed as superclasses prior to their
Expand Down Expand Up @@ -255,7 +255,7 @@ def get_hint_pep585_generic_bases_unerased(hint: object) -> 'Tuple[object]':


@callable_cached
def get_hint_pep585_generic_typevars(hint: object) -> 'Tuple[TypeVar, ...]':
def get_hint_pep585_generic_typevars(hint: object) -> Tuple[type, ...]:
'''
Tuple of all **unique type variables** (i.e., subscripted :class:`TypeVar`
instances of the passed `PEP 585`_-compliant generic listed by the caller
Expand All @@ -281,7 +281,7 @@ def get_hint_pep585_generic_typevars(hint: object) -> 'Tuple[TypeVar, ...]':
Returns
----------
Tuple[TypeVar]
Tuple[TypeVar, ...]
Either:
* If this `PEP 585`_-compliant generic defines a ``__parameters__``
Expand Down

0 comments on commit c9ca6f5

Please sign in to comment.