-
Notifications
You must be signed in to change notification settings - Fork 48
Feature typeddict #270
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Feature typeddict #270
Changes from 6 commits
134f44d
2d81ec1
ca15a91
1821cb9
23e69ed
9e4f016
f3e42ff
0680d81
9eb6fc3
fc67637
8711197
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,20 +6,29 @@ | |
|
|
||
| """ | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import random | ||
| import threading | ||
| import time | ||
| import typing | ||
| from typing import Any | ||
| from typing import cast | ||
| from typing import Dict | ||
| from typing import Mapping | ||
| from typing import Optional | ||
| from typing import Sequence | ||
| from typing import TypedDict | ||
| from typing import Union | ||
| import warnings | ||
|
|
||
| from ..api import CacheBackend | ||
| from ..api import NO_VALUE | ||
| from ... import util | ||
|
|
||
|
|
||
| if typing.TYPE_CHECKING: | ||
| import ssl | ||
|
|
||
| import bmemcached | ||
| import memcache | ||
| import pylibmc | ||
|
|
@@ -41,6 +50,50 @@ | |
| ) | ||
|
|
||
|
|
||
| class GenericMemcachedBackendArguments(TypedDict, total=False): | ||
| url: str | ||
| distributed_lock: bool | ||
| lock_timeout: int | ||
|
|
||
|
|
||
| class MemcachedArgsArguments(GenericMemcachedBackendArguments, total=False): | ||
| min_compress_len: int | ||
| memcached_expire_time: int | ||
|
|
||
|
|
||
| class MemcachedBackendArguments(GenericMemcachedBackendArguments, total=False): | ||
| min_compress_len: int | ||
| memcached_expire_time: int | ||
| dead_retry: int | ||
| socket_timeout: int | ||
|
|
||
|
|
||
| class BMemcachedBackendArguments( | ||
| GenericMemcachedBackendArguments, total=False | ||
| ): | ||
| username: Optional[str] | ||
| password: Optional[bool] | ||
| tls_context: Optional["ssl.SSLContext"] | ||
|
|
||
|
|
||
| class PyMemcacheBackendArguments( | ||
| GenericMemcachedBackendArguments, total=False | ||
| ): | ||
| serde: Optional[Any] | ||
| default_noreply: bool | ||
| tls_context: Optional["ssl.SSLContext"] | ||
| socket_keepalive: "pymemcache.client.base.KeepaliveOpts" | ||
| enable_retry_client: bool | ||
| retry_attempts: Optional[int] | ||
| retry_delay: Union[int, float, None] | ||
| retry_for: Optional[Sequence[Exception]] | ||
| do_not_retry_for: Optional[Sequence[Exception]] | ||
| hashclient_retry_attempts: int | ||
| hashclient_retry_timeout: int | ||
| hashclient_dead_timeout: int | ||
| memcached_expire_time: int | ||
|
|
||
|
|
||
| class MemcachedLock: | ||
| """Simple distributed lock using memcached.""" | ||
|
|
||
|
|
@@ -117,16 +170,17 @@ class GenericMemcachedBackend(CacheBackend): | |
| serializer = None | ||
| deserializer = None | ||
|
|
||
| def __init__(self, arguments): | ||
| def __init__(self, arguments: GenericMemcachedBackendArguments): | ||
| _arguments = cast(Dict, arguments.copy()) | ||
| self._imports() | ||
| # using a plain threading.local here. threading.local | ||
| # automatically deletes the __dict__ when a thread ends, | ||
| # so the idea is that this is superior to pylibmc's | ||
| # own ThreadMappedPool which doesn't handle this | ||
| # automatically. | ||
| self.url = util.to_list(arguments["url"]) | ||
| self.distributed_lock = arguments.get("distributed_lock", False) | ||
| self.lock_timeout = arguments.get("lock_timeout", 0) | ||
| self.url = util.to_list(_arguments["url"]) | ||
| self.distributed_lock = _arguments.get("distributed_lock", False) | ||
| self.lock_timeout = _arguments.get("lock_timeout", 0) | ||
|
|
||
| def has_lock_timeout(self): | ||
| return self.lock_timeout != 0 | ||
|
|
@@ -226,17 +280,19 @@ class MemcacheArgs(GenericMemcachedBackend): | |
| of the value using the compressor | ||
| """ | ||
|
|
||
| def __init__(self, arguments): | ||
| self.min_compress_len = arguments.get("min_compress_len", 0) | ||
| def __init__(self, arguments: MemcachedArgsArguments): | ||
| _arguments = cast(Dict, arguments.copy()) | ||
| self.min_compress_len = _arguments.get("min_compress_len", 0) | ||
|
|
||
| self.set_arguments = {} | ||
| if "memcached_expire_time" in arguments: | ||
| self.set_arguments["time"] = arguments["memcached_expire_time"] | ||
| if "min_compress_len" in arguments: | ||
| self.set_arguments["min_compress_len"] = arguments[ | ||
| if "memcached_expire_time" in _arguments: | ||
| self.set_arguments["time"] = _arguments["memcached_expire_time"] | ||
| if "min_compress_len" in _arguments: | ||
| self.set_arguments["min_compress_len"] = _arguments[ | ||
| "min_compress_len" | ||
| ] | ||
| super(MemcacheArgs, self).__init__(arguments) | ||
| _arguments_super = cast(GenericMemcachedBackendArguments, _arguments) | ||
| super(MemcacheArgs, self).__init__(_arguments_super) | ||
|
|
||
|
|
||
| class PylibmcBackend(MemcacheArgs, GenericMemcachedBackend): | ||
|
|
@@ -274,9 +330,11 @@ class PylibmcBackend(MemcacheArgs, GenericMemcachedBackend): | |
| """ | ||
|
|
||
| def __init__(self, arguments): | ||
| self.binary = arguments.get("binary", False) | ||
| self.behaviors = arguments.get("behaviors", {}) | ||
| super(PylibmcBackend, self).__init__(arguments) | ||
| _arguments = cast(Dict, arguments.copy()) | ||
| self.binary = _arguments.get("binary", False) | ||
| self.behaviors = _arguments.get("behaviors", {}) | ||
| _arguments_super = cast(MemcachedArgsArguments, _arguments) | ||
| super(PylibmcBackend, self).__init__(_arguments_super) | ||
|
|
||
| def _imports(self): | ||
| global pylibmc | ||
|
|
@@ -324,10 +382,12 @@ class MemcachedBackend(MemcacheArgs, GenericMemcachedBackend): | |
|
|
||
| """ | ||
|
|
||
| def __init__(self, arguments): | ||
| self.dead_retry = arguments.get("dead_retry", 30) | ||
| self.socket_timeout = arguments.get("socket_timeout", 3) | ||
| super(MemcachedBackend, self).__init__(arguments) | ||
| def __init__(self, arguments: MemcachedBackendArguments): | ||
| _arguments = cast(Dict, arguments.copy()) | ||
| self.dead_retry = _arguments.get("dead_retry", 30) | ||
| self.socket_timeout = _arguments.get("socket_timeout", 3) | ||
| _arguments_super = cast(MemcachedArgsArguments, _arguments) | ||
| super(MemcachedBackend, self).__init__(_arguments_super) | ||
|
|
||
| def _imports(self): | ||
| global memcache | ||
|
|
@@ -400,11 +460,13 @@ class BMemcachedBackend(GenericMemcachedBackend): | |
|
|
||
| """ | ||
|
|
||
| def __init__(self, arguments): | ||
| self.username = arguments.get("username", None) | ||
| self.password = arguments.get("password", None) | ||
| self.tls_context = arguments.get("tls_context", None) | ||
| super(BMemcachedBackend, self).__init__(arguments) | ||
| def __init__(self, arguments: BMemcachedBackendArguments): | ||
| _arguments = cast(Dict, arguments.copy()) | ||
| self.username = _arguments.get("username", None) | ||
| self.password = _arguments.get("password", None) | ||
| self.tls_context = _arguments.get("tls_context", None) | ||
| _arguments_super = cast(GenericMemcachedBackendArguments, _arguments) | ||
|
||
| super(BMemcachedBackend, self).__init__(_arguments_super) | ||
|
|
||
| def _imports(self): | ||
| global bmemcached | ||
|
|
@@ -560,7 +622,7 @@ class PyMemcacheBackend(GenericMemcachedBackend): | |
|
|
||
| .. versionadded:: 1.1.5 | ||
|
|
||
| :param dead_timeout: Time in seconds before attempting to add a node | ||
| :param hashclient_dead_timeout: Time in seconds before attempting to add a node | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would this require a versionchanged note in the docstring and/or backward compat property what warns on access?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No. This is just correcting a docstring error. The docstring references
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh ok, the docs is of the dictionary not of the class attributes. got it. |
||
| back in the pool in the HashClient's internal mechanisms. | ||
|
|
||
| .. versionadded:: 1.1.5 | ||
|
|
@@ -589,25 +651,29 @@ class PyMemcacheBackend(GenericMemcachedBackend): | |
|
|
||
| """ # noqa E501 | ||
|
|
||
| def __init__(self, arguments): | ||
| super().__init__(arguments) | ||
|
|
||
| self.serde = arguments.get("serde", pymemcache.serde.pickle_serde) | ||
| self.default_noreply = arguments.get("default_noreply", False) | ||
| self.tls_context = arguments.get("tls_context", None) | ||
| self.socket_keepalive = arguments.get("socket_keepalive", None) | ||
| self.enable_retry_client = arguments.get("enable_retry_client", False) | ||
| self.retry_attempts = arguments.get("retry_attempts", None) | ||
| self.retry_delay = arguments.get("retry_delay", None) | ||
| self.retry_for = arguments.get("retry_for", None) | ||
| self.do_not_retry_for = arguments.get("do_not_retry_for", None) | ||
| self.hashclient_retry_attempts = arguments.get( | ||
| def __init__(self, arguments: PyMemcacheBackendArguments): | ||
| _arguments = cast(Dict, arguments.copy()) | ||
| _arguments_super = cast(GenericMemcachedBackendArguments, _arguments) | ||
| super().__init__(_arguments_super) | ||
|
|
||
| self.serde = _arguments.get("serde", pymemcache.serde.pickle_serde) | ||
| self.default_noreply = _arguments.get("default_noreply", False) | ||
| self.tls_context = _arguments.get("tls_context", None) | ||
| self.socket_keepalive = _arguments.get("socket_keepalive", None) | ||
| self.enable_retry_client = _arguments.get("enable_retry_client", False) | ||
| self.retry_attempts = _arguments.get("retry_attempts", None) | ||
| self.retry_delay = _arguments.get("retry_delay", None) | ||
| self.retry_for = _arguments.get("retry_for", None) | ||
| self.do_not_retry_for = _arguments.get("do_not_retry_for", None) | ||
| self.hashclient_retry_attempts = _arguments.get( | ||
| "hashclient_retry_attempts", 2 | ||
| ) | ||
| self.hashclient_retry_timeout = arguments.get( | ||
| self.hashclient_retry_timeout = _arguments.get( | ||
| "hashclient_retry_timeout", 1 | ||
| ) | ||
| self.dead_timeout = arguments.get("hashclient_dead_timeout", 60) | ||
| self.hashclient_dead_timeout = _arguments.get( | ||
| "hashclient_dead_timeout", 60 | ||
| ) | ||
| if ( | ||
| self.retry_delay is not None | ||
| or self.retry_attempts is not None | ||
|
|
@@ -619,8 +685,8 @@ def __init__(self, arguments): | |
| "will be ignored" | ||
| ) | ||
| self.set_arguments = {} | ||
| if "memcached_expire_time" in arguments: | ||
| self.set_arguments["expire"] = arguments["memcached_expire_time"] | ||
| if "memcached_expire_time" in _arguments: | ||
| self.set_arguments["expire"] = _arguments["memcached_expire_time"] | ||
|
|
||
| def _imports(self): | ||
| global pymemcache | ||
|
|
@@ -633,7 +699,7 @@ def _create_client(self): | |
| "tls_context": self.tls_context, | ||
| "retry_attempts": self.hashclient_retry_attempts, | ||
| "retry_timeout": self.hashclient_retry_timeout, | ||
| "dead_timeout": self.dead_timeout, | ||
| "dead_timeout": self.hashclient_dead_timeout, | ||
| } | ||
| if self.socket_keepalive is not None: | ||
| _kwargs.update({"socket_keepalive": self.socket_keepalive}) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since this backend doesn't modify the dicy, maybe we could avoid this?
I mean it may make sense for backends that use pop, but for the other maybe not? this applies also to the other cases
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I opted to standardize how all the backends work, because people will use them as reference when implementing a new one.