@@ -0,0 +1 @@ | |||
Improve type hints. |
@@ -30,7 +30,7 @@ class OEmbedEndpointConfig: | |||
# The API endpoint to fetch. | |||
api_endpoint: str | |||
# The patterns to match. | |||
url_patterns: List[Pattern] | |||
url_patterns: List[Pattern[str]] | |||
# The supported formats. | |||
formats: Optional[List[str]] | |||
@@ -154,12 +154,13 @@ class _UpdateCurrentStateTask: | |||
_EventPersistQueueTask = Union[_PersistEventsTask, _UpdateCurrentStateTask] | |||
_PersistResult = TypeVar("_PersistResult") | |||
@attr.s(auto_attribs=True, slots=True) | |||
class _EventPersistQueueItem: | |||
class _EventPersistQueueItem(Generic[_PersistResult]): | |||
task: _EventPersistQueueTask | |||
deferred: ObservableDeferred | |||
deferred: ObservableDeferred[_PersistResult] | |||
parent_opentracing_span_contexts: List = attr.ib(factory=list) | |||
"""A list of opentracing spans waiting for this batch""" | |||
@@ -168,9 +169,6 @@ class _EventPersistQueueItem: | |||
"""The opentracing span under which the persistence actually happened""" | |||
_PersistResult = TypeVar("_PersistResult") | |||
class _EventPeristenceQueue(Generic[_PersistResult]): | |||
"""Queues up tasks so that they can be processed with only one concurrent | |||
transaction per room. | |||
@@ -19,6 +19,7 @@ import collections | |||
import inspect | |||
import itertools | |||
import logging | |||
import typing | |||
from contextlib import asynccontextmanager | |||
from typing import ( | |||
Any, | |||
@@ -29,6 +30,7 @@ from typing import ( | |||
Collection, | |||
Coroutine, | |||
Dict, | |||
Generator, | |||
Generic, | |||
Hashable, | |||
Iterable, | |||
@@ -398,7 +400,7 @@ class _LinearizerEntry: | |||
# The number of things executing. | |||
count: int | |||
# Deferreds for the things blocked from executing. | |||
deferreds: collections.OrderedDict | |||
deferreds: typing.OrderedDict["defer.Deferred[None]", Literal[1]] | |||
class Linearizer: | |||
@@ -717,30 +719,25 @@ def timeout_deferred( | |||
return new_d | |||
# This class can't be generic because it uses slots with attrs. | |||
# See: https://github.com/python-attrs/attrs/issues/313 | |||
@attr.s(slots=True, frozen=True, auto_attribs=True) | |||
class DoneAwaitable: # should be: Generic[R] | |||
class DoneAwaitable(Awaitable[R]): | |||
"""Simple awaitable that returns the provided value.""" | |||
value: Any # should be: R | |||
value: R | |||
def __await__(self) -> Any: | |||
return self | |||
def __iter__(self) -> "DoneAwaitable": | |||
return self | |||
def __next__(self) -> None: | |||
raise StopIteration(self.value) | |||
def __await__(self) -> Generator[Any, None, R]: | |||
yield None | |||
return self.value | |||
def maybe_awaitable(value: Union[Awaitable[R], R]) -> Awaitable[R]: | |||
"""Convert a value to an awaitable if not already an awaitable.""" | |||
if inspect.isawaitable(value): | |||
assert isinstance(value, Awaitable) | |||
return value | |||
# For some reason mypy doesn't deduce that value is not Awaitable here, even though | |||
# inspect.isawaitable returns a TypeGuard. | |||
assert not isinstance(value, Awaitable) | |||
return DoneAwaitable(value) | |||
@@ -14,7 +14,7 @@ | |||
import enum | |||
import logging | |||
import threading | |||
from typing import Any, Dict, Generic, Iterable, Optional, Set, Tuple, TypeVar, Union | |||
from typing import Dict, Generic, Iterable, Optional, Set, Tuple, TypeVar, Union | |||
import attr | |||
from typing_extensions import Literal | |||
@@ -33,10 +33,8 @@ DKT = TypeVar("DKT") | |||
DV = TypeVar("DV") | |||
# This class can't be generic because it uses slots with attrs. | |||
# See: https://github.com/python-attrs/attrs/issues/313 | |||
@attr.s(slots=True, frozen=True, auto_attribs=True) | |||
class DictionaryEntry: # should be: Generic[DKT, DV]. | |||
class DictionaryEntry(Generic[DKT, DV]): | |||
"""Returned when getting an entry from the cache | |||
If `full` is true then `known_absent` will be the empty set. | |||
@@ -50,8 +48,8 @@ class DictionaryEntry: # should be: Generic[DKT, DV]. | |||
""" | |||
full: bool | |||
known_absent: Set[Any] # should be: Set[DKT] | |||
value: Dict[Any, Any] # should be: Dict[DKT, DV] | |||
known_absent: Set[DKT] | |||
value: Dict[DKT, DV] | |||
def __len__(self) -> int: | |||
return len(self.value) | |||
@@ -14,7 +14,7 @@ | |||
import logging | |||
from collections import OrderedDict | |||
from typing import Any, Generic, Optional, TypeVar, Union, overload | |||
from typing import Any, Generic, Iterable, Optional, TypeVar, Union, overload | |||
import attr | |||
from typing_extensions import Literal | |||
@@ -73,7 +73,7 @@ class ExpiringCache(Generic[KT, VT]): | |||
self._expiry_ms = expiry_ms | |||
self._reset_expiry_on_get = reset_expiry_on_get | |||
self._cache: OrderedDict[KT, _CacheEntry] = OrderedDict() | |||
self._cache: OrderedDict[KT, _CacheEntry[VT]] = OrderedDict() | |||
self.iterable = iterable | |||
@@ -100,7 +100,10 @@ class ExpiringCache(Generic[KT, VT]): | |||
while self._max_size and len(self) > self._max_size: | |||
_key, value = self._cache.popitem(last=False) | |||
if self.iterable: | |||
self.metrics.inc_evictions(EvictionReason.size, len(value.value)) | |||
# type-ignore, here and below: if self.iterable is true, then the value | |||
# type VT should be Sized (i.e. have a __len__ method). We don't enforce | |||
# this via the type system at present. | |||
self.metrics.inc_evictions(EvictionReason.size, len(value.value)) # type: ignore[arg-type] | |||
else: | |||
self.metrics.inc_evictions(EvictionReason.size) | |||
@@ -134,7 +137,7 @@ class ExpiringCache(Generic[KT, VT]): | |||
return default | |||
if self.iterable: | |||
self.metrics.inc_evictions(EvictionReason.invalidation, len(value.value)) | |||
self.metrics.inc_evictions(EvictionReason.invalidation, len(value.value)) # type: ignore[arg-type] | |||
else: | |||
self.metrics.inc_evictions(EvictionReason.invalidation) | |||
@@ -182,7 +185,7 @@ class ExpiringCache(Generic[KT, VT]): | |||
for k in keys_to_delete: | |||
value = self._cache.pop(k) | |||
if self.iterable: | |||
self.metrics.inc_evictions(EvictionReason.time, len(value.value)) | |||
self.metrics.inc_evictions(EvictionReason.time, len(value.value)) # type: ignore[arg-type] | |||
else: | |||
self.metrics.inc_evictions(EvictionReason.time) | |||
@@ -195,7 +198,8 @@ class ExpiringCache(Generic[KT, VT]): | |||
def __len__(self) -> int: | |||
if self.iterable: | |||
return sum(len(entry.value) for entry in self._cache.values()) | |||
g: Iterable[int] = (len(entry.value) for entry in self._cache.values()) # type: ignore[arg-type] | |||
return sum(g) | |||
else: | |||
return len(self._cache) | |||
@@ -218,6 +222,6 @@ class ExpiringCache(Generic[KT, VT]): | |||
@attr.s(slots=True, auto_attribs=True) | |||
class _CacheEntry: | |||
class _CacheEntry(Generic[VT]): | |||
time: int | |||
value: Any | |||
value: VT |
@@ -35,10 +35,10 @@ class TTLCache(Generic[KT, VT]): | |||
def __init__(self, cache_name: str, timer: Callable[[], float] = time.time): | |||
# map from key to _CacheEntry | |||
self._data: Dict[KT, _CacheEntry] = {} | |||
self._data: Dict[KT, _CacheEntry[KT, VT]] = {} | |||
# the _CacheEntries, sorted by expiry time | |||
self._expiry_list: SortedList[_CacheEntry] = SortedList() | |||
self._expiry_list: SortedList[_CacheEntry[KT, VT]] = SortedList() | |||
self._timer = timer | |||
@@ -160,11 +160,11 @@ class TTLCache(Generic[KT, VT]): | |||
@attr.s(frozen=True, slots=True, auto_attribs=True) | |||
class _CacheEntry: # Should be Generic[KT, VT]. See python-attrs/attrs#313 | |||
class _CacheEntry(Generic[KT, VT]): | |||
"""TTLCache entry""" | |||
# expiry_time is the first attribute, so that entries are sorted by expiry. | |||
expiry_time: float | |||
ttl: float | |||
key: Any # should be KT | |||
value: Any # should be VT | |||
key: KT | |||
value: VT |