Skip to content

Commit

Permalink
Add initial type stubs (pynamodb#537)
Browse files Browse the repository at this point in the history
  • Loading branch information
garrettheel authored Oct 16, 2018
1 parent 88368bb commit 140993f
Show file tree
Hide file tree
Showing 22 changed files with 951 additions and 14 deletions.
12 changes: 9 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,18 @@ language: python
python:
- "3.6"
- "3.5"
- "3.4"
- "3.3"
- "2.7"
- "2.6"
- "pypy"


# See https://github.com/travis-ci/travis-ci/issues/9815
matrix:
include:
- python: "3.7"
dist: xenial
sudo: true

env:
- AWS_SECRET_ACCESS_KEY=fake_key AWS_ACCESS_KEY_ID=fake_id

Expand All @@ -26,7 +32,7 @@ before_script:

script:
- py.test --cov-report term-missing --cov=pynamodb pynamodb/tests/
- if [[ "$TRAVIS_PYTHON_VERSION" == "3.7" ]]; then mypy .; fi

after_success:
- coveralls

14 changes: 14 additions & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[mypy]
strict_optional = True
check_untyped_defs = True
warn_no_return = True
ignore_missing_imports = True
warn_unused_ignores = True
warn_unused_configs = True
warn_redundant_casts = True
warn_incomplete_stub = True
follow_imports = normal

# TODO: burn these down
[mypy-pynamodb.tests.*]
ignore_errors = True
163 changes: 163 additions & 0 deletions pynamodb/attributes.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
from typing import Any, Callable, Dict, Generic, Iterable, List, Mapping, Optional, Text, Type, TypeVar, Union, Set, overload

from datetime import datetime

from pynamodb.expressions.condition import (
BeginsWith, Between, Comparison, Contains, NotExists, Exists, In
)
from pynamodb.expressions.operand import _ListAppend
from pynamodb.expressions.update import (
AddAction, DeleteAction, RemoveAction, SetAction
)


_T = TypeVar('_T')
_KT = TypeVar('_KT')
_VT = TypeVar('_VT')
_MT = TypeVar('_MT', bound='MapAttribute')

_A = TypeVar('_A')


class Attribute(Generic[_T]):
attr_name: Optional[Text]
attr_type: Text
null: bool
default: Any
is_hash_key: bool
is_range_key: bool
def __init__(self, hash_key: bool = ..., range_key: bool = ..., null: Optional[bool] = ..., default: Optional[Union[_T, Callable[..., _T]]] = ..., attr_name: Optional[Text] = ...) -> None: ...
def __set__(self, instance: Any, value: Optional[_T]) -> None: ...
def serialize(self, value: Any) -> Any: ...
def deserialize(self, value: Any) -> Any: ...
def get_value(self, value: Any) -> Any: ...
def is_type(self) -> Any: ...
def __eq__(self, other: Any) -> Comparison: ... # type: ignore
def __ne__(self, other: Any) -> Comparison: ... # type: ignore
def __lt__(self, other: Any) -> Comparison: ...
def __le__(self, other: Any) -> Comparison: ...
def __gt__(self, other: Any) -> Comparison: ...
def __ge__(self, other: Any) -> Comparison: ...
def between(self, lower: Any, upper: Any) -> Between: ...
def is_in(self, *values: Any) -> In: ...
def exists(self) -> Exists: ...
def does_not_exist(self) -> NotExists: ...
def startswith(self, prefix: str) -> BeginsWith: ...
def contains(self, item: Any) -> Contains: ...
def set(self, value: Any) -> SetAction: ...
def remove(self) -> RemoveAction: ...
def add(self, *values: Any) -> AddAction: ...
def delete(self, *values: Any) -> DeleteAction: ...
def append(self, other: Any) -> _ListAppend: ...
def prepend(self, other: Any) -> _ListAppend: ...


class AttributeContainer(object):
attribute_values: Dict[Text, Any]
def __init__(**attributes: Attribute) -> None: ...


class SetMixin(object):
def serialize(self, value): ...
def deserialize(self, value): ...

class BinaryAttribute(Attribute[bytes]):
@overload
def __get__(self: _A, instance: None, owner: Any) -> _A: ...
@overload
def __get__(self, instance: Any, owner: Any) -> bytes: ...

class BinarySetAttribute(SetMixin, Attribute[Set[bytes]]):
@overload
def __get__(self: _A, instance: None, owner: Any) -> _A: ...
@overload
def __get__(self, instance: Any, owner: Any) -> Set[bytes]: ...

class UnicodeSetAttribute(SetMixin, Attribute[Set[Text]]):
def element_serialize(self, value: Any) -> Any: ...
def element_deserialize(self, value: Any) -> Any: ...
@overload
def __get__(self: _A, instance: None, owner: Any) -> _A: ...
@overload
def __get__(self, instance: Any, owner: Any) -> Set[Text]: ...

class UnicodeAttribute(Attribute[Text]):
@overload
def __get__(self: _A, instance: None, owner: Any) -> _A: ...
@overload
def __get__(self, instance: Any, owner: Any) -> Text: ...

class JSONAttribute(Attribute[Any]):
@overload
def __get__(self: _A, instance: None, owner: Any) -> _A: ...
@overload
def __get__(self, instance: Any, owner: Any) -> Any: ...

class LegacyBooleanAttribute(Attribute[bool]):
@overload
def __get__(self: _A, instance: None, owner: Any) -> _A: ...
@overload
def __get__(self, instance: Any, owner: Any) -> bool: ...

class BooleanAttribute(Attribute[bool]):
@overload
def __get__(self: _A, instance: None, owner: Any) -> _A: ...
@overload
def __get__(self, instance: Any, owner: Any) -> bool: ...

class NumberSetAttribute(SetMixin, Attribute[Set[float]]):
@overload
def __get__(self: _A, instance: None, owner: Any) -> _A: ...
@overload
def __get__(self, instance: Any, owner: Any) -> Set[float]: ...

class NumberAttribute(Attribute[float]):
@overload
def __get__(self: _A, instance: None, owner: Any) -> _A: ...
@overload
def __get__(self, instance: Any, owner: Any) -> float: ...


class UTCDateTimeAttribute(Attribute[datetime]):
@overload
def __get__(self: _A, instance: None, owner: Any) -> _A: ...
@overload
def __get__(self, instance: Any, owner: Any) -> datetime: ...

class NullAttribute(Attribute[None]):
@overload
def __get__(self: _A, instance: None, owner: Any) -> _A: ...
@overload
def __get__(self, instance: Any, owner: Any) -> None: ...

class MapAttributeMeta(type):
def __init__(cls, name, bases, attrs) -> None: ...

class MapAttribute(Generic[_KT, _VT], Attribute[Mapping[_KT, _VT]], metaclass=MapAttributeMeta):
attribute_values: Any
def __init__(self, hash_key: bool = ..., range_key: bool = ..., null: Optional[bool] = ..., default: Optional[Union[Any, Callable[..., Any]]] = ..., attr_name: Optional[Text] = ..., **attrs) -> None: ...
def __iter__(self) -> Iterable[_VT]: ...
def __getattr__(self, attr: str) -> _VT: ...
def __getitem__(self, item: _KT) -> _VT: ...
def __set__(self, instance: Any, value: Union[None, MapAttribute[_KT, _VT], Mapping[_KT, _VT]]) -> None: ...
@overload
def __get__(self: _A, instance: None, owner: Any) -> _A: ...
@overload
def __get__(self: _MT, instance: Any, owner: Any) -> _MT: ...
def is_type_safe(self, key: Any, value: Any) -> bool: ...
def validate(self) -> bool: ...

class ListAttribute(Generic[_T], Attribute[List[_T]]):
element_type: Any
def __init__(self, hash_key: bool = ..., range_key: bool = ..., null: Optional[bool] = ..., default: Optional[Union[Any, Callable[..., Any]]] = ..., attr_name: Optional[Text] = ..., of: Optional[Type[_T]] = ...) -> None: ...
@overload
def __get__(self: _A, instance: None, owner: Any) -> _A: ...
@overload
def __get__(self, instance: Any, owner: Any) -> List[_T]: ...

DESERIALIZE_CLASS_MAP: Dict[Text, Attribute]
SERIALIZE_CLASS_MAP: Dict[Type, Attribute]
SERIALIZE_KEY_MAP: Dict[Type, Text]


def _get_class_for_serialize(value: Optional[Any]) -> Attribute: ...
130 changes: 130 additions & 0 deletions pynamodb/connection/base.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
from typing import Any, Dict, Iterator, Optional, Sequence, Text

from pynamodb.expressions.condition import Condition

BOTOCORE_EXCEPTIONS: Any
log: Any

class MetaTable:
data: Dict
def __init__(self, data: Dict) -> None: ...
@property
def range_keyname(self) -> Optional[Text]: ...
@property
def hash_keyname(self) -> Text: ...
def get_index_hash_keyname(self, index_name: Text) -> Optional[Text]: ...
def get_item_attribute_map(self, attributes, item_key: Any = ..., pythonic_key: bool = ...): ...
def get_attribute_type(self, attribute_name, value: Optional[Any] = ...): ...
def get_identifier_map(self, hash_key, range_key: Optional[Any] = ..., key: Any = ...): ...
def get_exclusive_start_key_map(self, exclusive_start_key): ...

class Connection:
host: Any
region: Any
session_cls: Any
def __init__(self, region: Optional[Any] = ..., host: Optional[Any] = ..., session_cls: Optional[Any] = ..., request_timeout_seconds: Optional[Any] = ..., max_retry_attempts: Optional[Any] = ..., base_backoff_ms: Optional[Any] = ...) -> None: ...
def dispatch(self, operation_name, operation_kwargs): ...
@property
def session(self): ...
@property
def requests_session(self): ...
@property
def client(self): ...
def get_meta_table(self, table_name: Text, refresh: bool = ...): ...
def create_table(self, table_name: Text, attribute_definitions: Optional[Any] = ..., key_schema: Optional[Any] = ..., read_capacity_units: Optional[Any] = ..., write_capacity_units: Optional[Any] = ..., global_secondary_indexes: Optional[Any] = ..., local_secondary_indexes: Optional[Any] = ..., stream_specification: Optional[Any] = ...): ...
def delete_table(self, table_name: Text): ...
def update_table(self, table_name: Text, read_capacity_units: Optional[Any] = ..., write_capacity_units: Optional[Any] = ..., global_secondary_index_updates: Optional[Any] = ...): ...
def list_tables(self, exclusive_start_table_name: Optional[Any] = ..., limit: Optional[Any] = ...): ...
def describe_table(self, table_name: Text): ...
def get_conditional_operator(self, operator): ...
def get_item_attribute_map(self, table_name: Text, attributes, item_key: Any = ..., pythonic_key: bool = ...): ...
def get_expected_map(self, table_name: Text, expected): ...
def parse_attribute(self, attribute, return_type: bool = ...): ...
def get_attribute_type(self, table_name: Text, attribute_name, value: Optional[Any] = ...): ...
def get_identifier_map(self, table_name: Text, hash_key, range_key: Optional[Any] = ..., key: Any = ...): ...
def get_query_filter_map(self, table_name: Text, query_filters): ...
def get_consumed_capacity_map(self, return_consumed_capacity): ...
def get_return_values_map(self, return_values): ...
def get_item_collection_map(self, return_item_collection_metrics): ...
def get_exclusive_start_key_map(self, table_name: Text, exclusive_start_key): ...

def delete_item(
self,
table_name: Text,
hash_key,
range_key: Optional[Any] = ...,
condition: Optional[Condition] = ...,
expected: Optional[Any] = ...,
conditional_operator: Optional[Any] = ...,
return_values: Optional[Any] = ...,
return_consumed_capacity: Optional[Any] = ...,
return_item_collection_metrics: Optional[Any] = ...
) -> Dict: ...

def update_item(
self,
table_name: Text,
hash_key,
range_key: Optional[Any] = ...,
attribute_updates: Optional[Any] = ...,
condition: Optional[Condition] = ...,
expected: Optional[Any] = ...,
return_consumed_capacity: Optional[Any] = ...,
conditional_operator: Optional[Any] = ...,
return_item_collection_metrics: Optional[Any] = ...,
return_values: Optional[Any] = ...
) -> Dict: ...

def put_item(
self,
table_name: Text,
hash_key,
range_key: Optional[Any] = ...,
attributes: Optional[Any] = ...,
condition: Optional[Condition] = ...,
expected: Optional[Any] = ...,
conditional_operator: Optional[Any] = ...,
return_values: Optional[Any] = ...,
return_consumed_capacity: Optional[Any] = ...,
return_item_collection_metrics: Optional[Any] = ...
) -> Dict: ...

def batch_write_item(self, table_name: Text, put_items: Optional[Any] = ..., delete_items: Optional[Any] = ..., return_consumed_capacity: Optional[Any] = ..., return_item_collection_metrics: Optional[Any] = ...): ...
def batch_get_item(self, table_name: Text, keys, consistent_read: Optional[Any] = ..., return_consumed_capacity: Optional[Any] = ..., attributes_to_get: Optional[Any] = ...): ...
def get_item(self, table_name: Text, hash_key, range_key: Optional[Any] = ..., consistent_read: bool = ..., attributes_to_get: Optional[Any] = ...): ...

def rate_limited_scan(
self,
table_name: Text,
filter_condition: Optional[Condition] = ...,
attributes_to_get: Optional[Sequence[str]] = ...,
page_size: Optional[int] = ...,
limit: Optional[int] = ...,
conditional_operator: Optional[Text] = ...,
scan_filter: Optional[Dict] = ...,
exclusive_start_key: Optional[Any] = ...,
segment: Optional[int] = ...,
total_segments: Optional[int] = ...,
timeout_seconds: Optional[float] = ...,
read_capacity_to_consume_per_second: int = ...,
allow_rate_limited_scan_without_consumed_capacity: Optional[bool] = ...,
max_sleep_between_retry: float = ...,
max_consecutive_exceptions: int = ...,
consistent_read: Optional[bool] = ...,
index_name: Optional[str] = ...
) -> Iterator[Dict]: ...

def scan(
self,
table_name: Text = ...,
attributes_to_get: Optional[Any] = ...,
limit: Optional[Any] = ...,
conditional_operator: Optional[Any] = ...,
scan_filter: Optional[Dict] = ...,
return_consumed_capacity: Optional[Any] = ...,
exclusive_start_key: Optional[Any] = ...,
segment: Optional[str] = ...,
total_segments: Optional[int] = ...,
) -> Dict: ...

def query(self, table_name: Text, hash_key, attributes_to_get: Optional[Any] = ..., consistent_read: bool = ..., exclusive_start_key: Optional[Any] = ..., index_name: Optional[Any] = ..., key_conditions: Optional[Any] = ..., query_filters: Optional[Any] = ..., conditional_operator: Optional[Any] = ..., limit: Optional[Any] = ..., return_consumed_capacity: Optional[Any] = ..., scan_index_forward: Optional[Any] = ..., select: Optional[Any] = ...): ...
Loading

0 comments on commit 140993f

Please sign in to comment.