Source code for cardinal_pythonlib.typing_helpers

#!/usr/bin/env python
# cardinal_pythonlib/typing_helpers.py

"""
===============================================================================

    Original code copyright (C) 2009-2022 Rudolf Cardinal (rudolf@pobox.com).

    This file is part of cardinal_pythonlib.

    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

        https://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.

===============================================================================

**Methods and unusual types for type hints.**

"""

from abc import abstractmethod
import csv
from typing import (
    Any,
    Iterator,
    List,
    Optional,
    Sequence,
    Tuple,
    Type,
    TYPE_CHECKING,
    TypeVar,
    Union,
)


# =============================================================================
# Constants
# =============================================================================

T = TypeVar("T")


# =============================================================================
# with_typehint
# =============================================================================


[docs]def with_typehint(baseclass: Type[T]) -> Type[T]: """ Useful function to make mixins with type hints from a base class. From https://stackoverflow.com/questions/51930339/how-do-i-correctly-add-type-hints-to-mixin-classes. Specimen usage: .. code-block:: python class MyMixin1(with_typehint(SomeBaseClass))): # ... """ # noqa if TYPE_CHECKING: return baseclass return object
[docs]def with_typehints(*baseclasses: Type[T]) -> Type[T]: """ Useful function to make mixins with type hints from multiple base classes. From https://stackoverflow.com/questions/51930339/how-do-i-correctly-add-type-hints-to-mixin-classes. Specimen usage: .. code-block:: python class MyMixin2(*with_typehints(SomeBaseClass, AnotherBaseClass))): # ... """ # noqa if TYPE_CHECKING: return baseclasses return object
# ============================================================================= # csv.writer # =============================================================================
[docs]class CSVWriterType(object): """ Type hint for the result of ``csv.writer()`` See https://stackoverflow.com/questions/51264355/how-to-type-annotate-object-returned-by-csv-writer """ # noqa @abstractmethod def writerow(self, row: List[str]) -> None: pass @abstractmethod def writerows(self, rows: List[List[str]]) -> None: pass @property @abstractmethod def dialect(self) -> csv.Dialect: pass
# ============================================================================= # Pep249DatabaseConnectionType # =============================================================================
[docs]class Pep249DatabaseConnectionType(object): """ Type hint for a database connection compliant with PEP 249. See https://www.python.org/dev/peps/pep-0249/. Not supported: - https://www.python.org/dev/peps/pep-0249/#optional-error-handling-extensions - https://www.python.org/dev/peps/pep-0249/#optional-two-phase-commit-extensions """ # noqa
[docs] @abstractmethod def close(self) -> None: """ See https://www.python.org/dev/peps/pep-0249/#connection-objects """ pass
[docs] @abstractmethod def commit(self) -> None: """ See https://www.python.org/dev/peps/pep-0249/#connection-objects """ pass
[docs] @abstractmethod def rollback(self) -> None: """ See https://www.python.org/dev/peps/pep-0249/#connection-objects """ pass
[docs] @abstractmethod def cursor(self) -> "Pep249DatabaseCursorType": """ See https://www.python.org/dev/peps/pep-0249/#connection-objects """ pass
@property @abstractmethod def messages(self) -> List[Tuple[Type, Any]]: """ See https://www.python.org/dev/peps/pep-0249/#optional-db-api-extensions """ pass
# ============================================================================= # Pep249DatabaseConnectionType # ============================================================================= _DATABASE_ROW_TYPE = Sequence[Any]
[docs]class Pep249DatabaseCursorType(object): """ Type hint for a database cursor compliant with PEP 249. See https://www.python.org/dev/peps/pep-0249/#cursor-objects Example, as per https://docs.python.org/3.6/library/sqlite3.html: .. code-block:: python import sqlite3 conn = sqlite3.connect(':memory:') c = conn.cursor() c.execute(''' CREATE TABLE stocks (date text, trans text, symbol text, qty real, price real) ''') c.execute(''' INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14) ''') conn.commit() c.execute("SELECT * FROM stocks") print(repr(c.description)) help(c) See also: - https://www.psycopg.org/docs/cursor.html """ @abstractmethod def __init__(self, *args, **kwargs) -> None: pass @abstractmethod def __iter__(self) -> Iterator[_DATABASE_ROW_TYPE]: """ See https://www.python.org/dev/peps/pep-0249/#optional-db-api-extensions """ pass @abstractmethod def __new__(cls, *args, **kwargs) -> "Pep249DatabaseCursorType": pass @abstractmethod def __next__(self) -> None: pass @property @abstractmethod def description(self) -> Optional[Sequence[Sequence[Any]]]: """ A sequence of column_description objects, where each column_description describes one result column and has the following items: - name: ``str`` - type_code: ``Optional[Type]``? Not sure. - display_size: ``Optional[int]`` - internal_size: ``Optional[int]`` - precision: ``Optional[int]`` - scale: ``Optional[int]`` - null_ok: ``Optional[bool]`` The attribute is ``None`` for operations that don't return rows, and for un-executed cursors. """ pass @property @abstractmethod def rowcount(self) -> int: """ See https://www.python.org/dev/peps/pep-0249/#cursor-objects """ pass
[docs] @abstractmethod def callproc(self, procname: str, *args, **kwargs) -> None: """ See https://www.python.org/dev/peps/pep-0249/#cursor-objects """ pass
[docs] @abstractmethod def close(self) -> None: """ See https://www.python.org/dev/peps/pep-0249/#cursor-objects """ pass
[docs] @abstractmethod def execute(self, operation: str, *args, **kwargs) -> None: """ See https://www.python.org/dev/peps/pep-0249/#cursor-objects """ pass
[docs] @abstractmethod def executemany(self, operation: str, *args, **kwargs) -> None: """ See https://www.python.org/dev/peps/pep-0249/#cursor-objects """ pass
[docs] @abstractmethod def fetchone(self) -> Optional[_DATABASE_ROW_TYPE]: """ See https://www.python.org/dev/peps/pep-0249/#cursor-objects """ pass
[docs] @abstractmethod def fetchmany(self, size: int = None) -> Sequence[_DATABASE_ROW_TYPE]: """ See https://www.python.org/dev/peps/pep-0249/#cursor-objects """ pass
[docs] @abstractmethod def fetchall(self) -> Sequence[_DATABASE_ROW_TYPE]: """ See https://www.python.org/dev/peps/pep-0249/#cursor-objects """ pass
[docs] @abstractmethod def nextset(self) -> Optional[bool]: """ See https://www.python.org/dev/peps/pep-0249/#cursor-objects """ pass
@property @abstractmethod def arraysize(self) -> int: """ See https://www.python.org/dev/peps/pep-0249/#cursor-objects """ # read/write attribute; see below pass # noinspection PyUnresolvedReferences @arraysize.setter @abstractmethod def arraysize(self, val: int) -> None: """ See https://www.python.org/dev/peps/pep-0249/#cursor-objects """ # https://stackoverflow.com/questions/35344209/python-abstract-property-setter-with-concrete-getter pass
[docs] @abstractmethod def setinputsizes(self, sizes: Sequence[Union[Type, int]]) -> None: """ See https://www.python.org/dev/peps/pep-0249/#cursor-objects """ pass
[docs] @abstractmethod def setoutputsize(self, size: int, column: Optional[int]) -> None: """ See https://www.python.org/dev/peps/pep-0249/#cursor-objects """ pass
@property @abstractmethod def connection(self) -> Pep249DatabaseConnectionType: """ See https://www.python.org/dev/peps/pep-0249/#optional-db-api-extensions """ pass @property @abstractmethod def lastrowid(self) -> Optional[int]: """ See https://www.python.org/dev/peps/pep-0249/#optional-db-api-extensions """ pass @property @abstractmethod def rownumber(self) -> Optional[int]: """ See https://www.python.org/dev/peps/pep-0249/#optional-db-api-extensions """ pass
[docs] @abstractmethod def scroll(self, value: int, mode: str = "relative") -> None: """ See https://www.python.org/dev/peps/pep-0249/#optional-db-api-extensions """ pass
@property @abstractmethod def messages(self) -> List[Tuple[Type, Any]]: """ See https://www.python.org/dev/peps/pep-0249/#optional-db-api-extensions """ pass
[docs] @abstractmethod def next(self) -> _DATABASE_ROW_TYPE: """ See https://www.python.org/dev/peps/pep-0249/#optional-db-api-extensions """ pass