python3.9,removed windows build,kick vote,ban mute commands , rjcd

This commit is contained in:
imayushsaini 2021-11-10 17:26:07 +05:30
parent 94bdfb531a
commit dbe040a017
2453 changed files with 3797 additions and 437553 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -5,6 +5,7 @@
from __future__ import annotations
from typing import TYPE_CHECKING, TypeVar, Generic, Callable, cast
import functools
if TYPE_CHECKING:
from typing import Any, overload
@ -265,4 +266,8 @@ if TYPE_CHECKING:
def Call(*_args: Any, **_keywds: Any) -> Any:
...
Call = Call
# A convenient wrapper around functools.partial which adds type-safety
# (though it does not support keyword arguments).
partial = Call
else:
partial = functools.partial

View file

@ -19,7 +19,7 @@ from efro.dataclassio._prep import ioprep, ioprepped, is_ioprepped_dataclass
from efro.dataclassio._pathcapture import DataclassFieldLookup
if TYPE_CHECKING:
from typing import Any, Dict, Type, Tuple, Optional, List, Set
from typing import Any
__all__ = [
'Codec', 'IOAttrs', 'ioprep', 'ioprepped', 'is_ioprepped_dataclass',
@ -73,7 +73,7 @@ def dataclass_to_json(obj: Any,
return json.dumps(jdict, separators=(',', ':'))
def dataclass_from_dict(cls: Type[T],
def dataclass_from_dict(cls: type[T],
values: dict,
codec: Codec = Codec.JSON,
coerce_to_float: bool = True,
@ -109,7 +109,7 @@ def dataclass_from_dict(cls: Type[T],
discard_unknown_attrs=discard_unknown_attrs).run(values)
def dataclass_from_json(cls: Type[T],
def dataclass_from_json(cls: type[T],
json_str: str,
coerce_to_float: bool = True,
allow_unknown_attrs: bool = True,

View file

@ -8,10 +8,9 @@ import dataclasses
import typing
import datetime
from enum import Enum
from typing import TYPE_CHECKING
# Note: can pull this from typing once we update to Python 3.9+
from typing import TYPE_CHECKING, get_args
# noinspection PyProtectedMember
from typing_extensions import get_args, _AnnotatedAlias
from typing import _AnnotatedAlias # type: ignore
_pytz_utc: Any
@ -23,7 +22,7 @@ except ModuleNotFoundError:
_pytz_utc = None # pylint: disable=invalid-name
if TYPE_CHECKING:
from typing import Any, Dict, Type, Tuple, Optional, List, Set
from typing import Any, Optional
# Types which we can pass through as-is.
SIMPLE_TYPES = {int, bool, str, float, type(None)}
@ -41,8 +40,8 @@ def _ensure_datetime_is_timezone_aware(value: datetime.datetime) -> None:
'datetime values must have timezone set as timezone.utc')
def _raise_type_error(fieldpath: str, valuetype: Type,
expected: Tuple[Type, ...]) -> None:
def _raise_type_error(fieldpath: str, valuetype: type,
expected: tuple[type, ...]) -> None:
"""Raise an error when a field value's type does not match expected."""
assert isinstance(expected, tuple)
assert all(isinstance(e, type) for e in expected)
@ -121,7 +120,7 @@ class IOAttrs:
if whole_hours != cls.whole_hours:
self.whole_hours = whole_hours
def validate_for_field(self, cls: Type, field: dataclasses.Field) -> None:
def validate_for_field(self, cls: type, field: dataclasses.Field) -> None:
"""Ensure the IOAttrs instance is ok to use with the provided field."""
# Turning off store_default requires the field to have either
@ -161,7 +160,7 @@ def _get_origin(anntype: Any) -> Any:
return anntype if origin is None else origin
def _parse_annotated(anntype: Any) -> Tuple[Any, Optional[IOAttrs]]:
def _parse_annotated(anntype: Any) -> tuple[Any, Optional[IOAttrs]]:
"""Parse Annotated() constructs, returning annotated type & IOAttrs."""
# If we get an Annotated[foo, bar, eep] we take
# foo as the actual type and we look for IOAttrs instances in

View file

@ -22,7 +22,7 @@ from efro.dataclassio._base import (Codec, _parse_annotated, EXTRA_ATTRS_ATTR,
from efro.dataclassio._prep import PrepSession
if TYPE_CHECKING:
from typing import Any, Dict, Type, Tuple, Optional, List, Set
from typing import Any, Optional
from efro.dataclassio._base import IOAttrs
T = TypeVar('T')
@ -31,7 +31,7 @@ T = TypeVar('T')
class _Inputter(Generic[T]):
def __init__(self,
cls: Type[T],
cls: type[T],
codec: Codec,
coerce_to_float: bool,
allow_unknown_attrs: bool = True,
@ -52,7 +52,7 @@ class _Inputter(Generic[T]):
assert isinstance(out, self._cls)
return out
def _value_from_input(self, cls: Type, fieldpath: str, anntype: Any,
def _value_from_input(self, cls: type, fieldpath: str, anntype: Any,
value: Any, ioattrs: Optional[IOAttrs]) -> Any:
"""Convert an assigned value to what a dataclass field expects."""
# pylint: disable=too-many-return-statements
@ -122,7 +122,7 @@ class _Inputter(Generic[T]):
raise TypeError(
f"Field '{fieldpath}' of type '{anntype}' is unsupported here.")
def _bytes_from_input(self, cls: Type, fieldpath: str,
def _bytes_from_input(self, cls: type, fieldpath: str,
value: Any) -> bytes:
"""Given input data, returns bytes."""
import base64
@ -142,7 +142,7 @@ class _Inputter(Generic[T]):
f' on {cls.__name__}; got a {type(value)}.')
return base64.b64decode(value)
def _dataclass_from_input(self, cls: Type, fieldpath: str,
def _dataclass_from_input(self, cls: type, fieldpath: str,
values: dict) -> Any:
"""Given a dict, instantiates a dataclass of the given type.
@ -165,7 +165,7 @@ class _Inputter(Generic[T]):
# noinspection PyDataclass
fields = dataclasses.fields(cls)
fields_by_name = {f.name: f for f in fields}
args: Dict[str, Any] = {}
args: dict[str, Any] = {}
for rawkey, value in values.items():
key = prep.storage_names_to_attr_names.get(rawkey, rawkey)
field = fields_by_name.get(key)
@ -206,7 +206,7 @@ class _Inputter(Generic[T]):
setattr(out, EXTRA_ATTRS_ATTR, extra_attrs)
return out
def _dict_from_input(self, cls: Type, fieldpath: str, anntype: Any,
def _dict_from_input(self, cls: type, fieldpath: str, anntype: Any,
value: Any, ioattrs: Optional[IOAttrs]) -> Any:
# pylint: disable=too-many-branches
# pylint: disable=too-many-locals
@ -219,7 +219,7 @@ class _Inputter(Generic[T]):
childtypes = typing.get_args(anntype)
assert len(childtypes) in (0, 2)
out: Dict
out: dict
# We treat 'Any' dicts simply as json; we don't do any translating.
if not childtypes or childtypes[0] is typing.Any:
@ -305,8 +305,8 @@ class _Inputter(Generic[T]):
return out
def _sequence_from_input(self, cls: Type, fieldpath: str, anntype: Any,
value: Any, seqtype: Type,
def _sequence_from_input(self, cls: type, fieldpath: str, anntype: Any,
value: Any, seqtype: type,
ioattrs: Optional[IOAttrs]) -> Any:
# Because we are json-centric, we expect a list for all sequences.
@ -332,7 +332,7 @@ class _Inputter(Generic[T]):
self._value_from_input(cls, fieldpath, childanntype, i, ioattrs)
for i in value)
def _datetime_from_input(self, cls: Type, fieldpath: str, value: Any,
def _datetime_from_input(self, cls: type, fieldpath: str, value: Any,
ioattrs: Optional[IOAttrs]) -> Any:
# For firestore we expect a datetime object.
@ -364,10 +364,10 @@ class _Inputter(Generic[T]):
ioattrs.validate_datetime(out, fieldpath)
return out
def _tuple_from_input(self, cls: Type, fieldpath: str, anntype: Any,
def _tuple_from_input(self, cls: type, fieldpath: str, anntype: Any,
value: Any, ioattrs: Optional[IOAttrs]) -> Any:
out: List = []
out: list = []
# Because we are json-centric, we expect a list for all sequences.
if type(value) is not list:

View file

@ -21,7 +21,7 @@ from efro.dataclassio._base import (Codec, _parse_annotated, EXTRA_ATTRS_ATTR,
from efro.dataclassio._prep import PrepSession
if TYPE_CHECKING:
from typing import Any, Dict, Type, Tuple, Optional, List, Set
from typing import Any, Optional
from efro.dataclassio._base import IOAttrs
@ -39,13 +39,13 @@ class _Outputter:
"""Do the thing."""
return self._process_dataclass(type(self._obj), self._obj, '')
def _process_dataclass(self, cls: Type, obj: Any, fieldpath: str) -> Any:
def _process_dataclass(self, cls: type, obj: Any, fieldpath: str) -> Any:
# pylint: disable=too-many-locals
# pylint: disable=too-many-branches
prep = PrepSession(explicit=False).prep_dataclass(type(obj),
recursion_level=0)
fields = dataclasses.fields(obj)
out: Optional[Dict[str, Any]] = {} if self._create else None
out: Optional[dict[str, Any]] = {} if self._create else None
for field in fields:
fieldname = field.name
if fieldpath:
@ -95,7 +95,7 @@ class _Outputter:
out.update(extra_attrs)
return out
def _process_value(self, cls: Type, fieldpath: str, anntype: Any,
def _process_value(self, cls: type, fieldpath: str, anntype: Any,
value: Any, ioattrs: Optional[IOAttrs]) -> Any:
# pylint: disable=too-many-return-statements
# pylint: disable=too-many-branches
@ -259,7 +259,7 @@ class _Outputter:
raise TypeError(
f"Field '{fieldpath}' of type '{anntype}' is unsupported here.")
def _process_bytes(self, cls: Type, fieldpath: str, value: bytes) -> Any:
def _process_bytes(self, cls: type, fieldpath: str, value: bytes) -> Any:
import base64
if not isinstance(value, bytes):
raise TypeError(
@ -276,7 +276,7 @@ class _Outputter:
assert self._codec is Codec.FIRESTORE
return value
def _process_dict(self, cls: Type, fieldpath: str, anntype: Any,
def _process_dict(self, cls: type, fieldpath: str, anntype: Any,
value: dict, ioattrs: Optional[IOAttrs]) -> Any:
# pylint: disable=too-many-branches
if not isinstance(value, dict):
@ -299,7 +299,7 @@ class _Outputter:
# Ok; we've got a definite key type (which we verified as valid
# during prep). Make sure all keys match it.
out: Optional[Dict] = {} if self._create else None
out: Optional[dict] = {} if self._create else None
keyanntype, valanntype = childtypes
# str keys we just export directly since that's supported by json.

View file

@ -11,7 +11,7 @@ from efro.dataclassio._base import _parse_annotated, _get_origin
from efro.dataclassio._prep import PrepSession
if TYPE_CHECKING:
from typing import Any, Dict, Type, Tuple, Optional, List, Set, Callable
from typing import Any, Callable
T = TypeVar('T')
@ -19,7 +19,7 @@ T = TypeVar('T')
class _PathCapture:
"""Utility for obtaining dataclass storage paths in a type safe way."""
def __init__(self, obj: Any, pathparts: List[str] = None):
def __init__(self, obj: Any, pathparts: list[str] = None):
self._is_dataclass = dataclasses.is_dataclass(obj)
if pathparts is None:
pathparts = []
@ -55,7 +55,7 @@ class _PathCapture:
class DataclassFieldLookup(Generic[T]):
"""Get info about nested dataclass fields in type-safe way."""
def __init__(self, cls: Type[T]) -> None:
def __init__(self, cls: type[T]) -> None:
self.cls = cls
def path(self, callback: Callable[[T], Any]) -> str:
@ -85,7 +85,7 @@ class DataclassFieldLookup(Generic[T]):
return out.path
return ''
def paths(self, callback: Callable[[T], List[Any]]) -> List[str]:
def paths(self, callback: Callable[[T], list[Any]]) -> list[str]:
"""Look up multiple paths on child dataclass fields.
Functionality is identical to path() but for multiple paths at once.
@ -93,7 +93,7 @@ class DataclassFieldLookup(Generic[T]):
example:
DataclassFieldLookup(MyType).paths(lambda obj: [obj.foo, obj.bar])
"""
outvals: List[str] = []
outvals: list[str] = []
if not TYPE_CHECKING:
outs = callback(_PathCapture(self.cls))
assert isinstance(outs, list)

View file

@ -13,15 +13,13 @@ from enum import Enum
import dataclasses
import typing
import datetime
from typing import TYPE_CHECKING, TypeVar
# Note: can pull this from typing once we update to Python 3.9+
# noinspection PyProtectedMember
from typing_extensions import get_type_hints
from typing import TYPE_CHECKING, TypeVar, get_type_hints
# noinspection PyProtectedMember
from efro.dataclassio._base import _parse_annotated, _get_origin, SIMPLE_TYPES
if TYPE_CHECKING:
from typing import Any, Dict, Type, Tuple, Optional, List, Set
from typing import Any
T = TypeVar('T')
@ -33,7 +31,7 @@ MAX_RECURSION = 10
PREP_ATTR = '_DCIOPREP'
def ioprep(cls: Type) -> None:
def ioprep(cls: type) -> None:
"""Prep a dataclass type for use with this module's functionality.
Prepping ensures that all types contained in a data class as well as
@ -53,7 +51,7 @@ def ioprep(cls: Type) -> None:
PrepSession(explicit=True).prep_dataclass(cls, recursion_level=0)
def ioprepped(cls: Type[T]) -> Type[T]:
def ioprepped(cls: type[T]) -> type[T]:
"""Class decorator for easily prepping a dataclass at definition time.
Note that in some cases it may not be possible to prep a dataclass
@ -80,10 +78,10 @@ class PrepData:
"""
# Resolved annotation data with 'live' classes.
annotations: Dict[str, Any]
annotations: dict[str, Any]
# Map of storage names to attr names.
storage_names_to_attr_names: Dict[str, str]
storage_names_to_attr_names: dict[str, str]
class PrepSession:
@ -92,7 +90,7 @@ class PrepSession:
def __init__(self, explicit: bool):
self.explicit = explicit
def prep_dataclass(self, cls: Type, recursion_level: int) -> PrepData:
def prep_dataclass(self, cls: type, recursion_level: int) -> PrepData:
"""Run prep on a dataclass if necessary and return its prep data."""
# We should only need to do this once per dataclass.
@ -123,7 +121,6 @@ class PrepSession:
try:
# NOTE: Now passing the class' __dict__ (vars()) as locals
# which allows us to pick up nested classes, etc.
# pylint: disable=unexpected-keyword-arg
resolved_annotations = get_type_hints(cls,
localns=vars(cls),
include_extras=True)
@ -140,8 +137,8 @@ class PrepSession:
fields = dataclasses.fields(cls)
fields_by_name = {f.name: f for f in fields}
all_storage_names: Set[str] = set()
storage_names_to_attr_names: Dict[str, str] = {}
all_storage_names: set[str] = set()
storage_names_to_attr_names: dict[str, str] = {}
# Ok; we've resolved actual types for this dataclass.
# now recurse through them, verifying that we support all contained
@ -180,7 +177,7 @@ class PrepSession:
setattr(cls, PREP_ATTR, prepdata)
return prepdata
def prep_type(self, cls: Type, attrname: str, anntype: Any,
def prep_type(self, cls: type, attrname: str, anntype: Any,
recursion_level: int) -> None:
"""Run prep on a dataclass."""
# pylint: disable=too-many-return-statements
@ -301,7 +298,7 @@ class PrepSession:
f" type '{anntype}'"
f' which is not supported by dataclassio.')
def prep_union(self, cls: Type, attrname: str, anntype: Any,
def prep_union(self, cls: type, attrname: str, anntype: Any,
recursion_level: int) -> None:
"""Run prep on a Union type."""
typeargs = typing.get_args(anntype)
@ -317,7 +314,7 @@ class PrepSession:
childtype,
recursion_level=recursion_level + 1)
def prep_enum(self, enumtype: Type[Enum]) -> None:
def prep_enum(self, enumtype: type[Enum]) -> None:
"""Run prep on an enum type."""
valtype: Any = None

View file

@ -8,7 +8,7 @@ import dataclasses
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import Any, Dict, Type, Tuple, Optional, List, Set
from typing import Any, Optional
def dataclass_diff(obj1: Any, obj2: Any) -> str:
@ -42,7 +42,7 @@ def _diff(obj1: Any, obj2: Any, indent: int) -> str:
if type(obj1) is not type(obj2):
raise TypeError(f'Passed objects are not of the same'
f' type ({type(obj1)} and {type(obj2)}).')
bits: List[str] = []
bits: list[str] = []
indentstr = ' ' * indent
fields = dataclasses.fields(obj1)
for field in fields:

View file

@ -6,7 +6,7 @@ Supports static typing for message types and possible return types.
from __future__ import annotations
from typing import TYPE_CHECKING, TypeVar
from typing import TYPE_CHECKING, TypeVar, Annotated
from dataclasses import dataclass
from enum import Enum
import inspect
@ -14,15 +14,12 @@ import logging
import json
import traceback
from typing_extensions import Annotated
from efro.error import CleanError, RemoteError
from efro.dataclassio import (ioprepped, is_ioprepped_dataclass, IOAttrs,
dataclass_to_dict, dataclass_from_dict)
if TYPE_CHECKING:
from typing import (Dict, Type, Tuple, List, Any, Callable, Optional, Set,
Sequence, Union, Awaitable)
from typing import Any, Callable, Optional, Sequence, Union, Awaitable
TM = TypeVar('TM', bound='MessageSender')
@ -31,7 +28,7 @@ class Message:
"""Base class for messages."""
@classmethod
def get_response_types(cls) -> List[Type[Response]]:
def get_response_types(cls) -> list[type[Response]]:
"""Return all message types this Message can result in when sent.
The default implementation specifies EmptyResponse, so messages with
@ -102,8 +99,8 @@ class MessageProtocol:
"""
def __init__(self,
message_types: Dict[int, Type[Message]],
response_types: Dict[int, Type[Response]],
message_types: dict[int, type[Message]],
response_types: dict[int, type[Response]],
type_key: Optional[str] = None,
preserve_clean_errors: bool = True,
log_remote_exceptions: bool = True,
@ -127,10 +124,10 @@ class MessageProtocol:
be included in the responses if errors occur.
"""
# pylint: disable=too-many-locals
self.message_types_by_id: Dict[int, Type[Message]] = {}
self.message_ids_by_type: Dict[Type[Message], int] = {}
self.response_types_by_id: Dict[int, Type[Response]] = {}
self.response_ids_by_type: Dict[Type[Response], int] = {}
self.message_types_by_id: dict[int, type[Message]] = {}
self.message_ids_by_type: dict[type[Message], int] = {}
self.response_types_by_id: dict[int, type[Response]] = {}
self.response_ids_by_type: dict[type[Response], int] = {}
for m_id, m_type in message_types.items():
# Make sure only valid message types were passed and each
@ -155,7 +152,7 @@ class MessageProtocol:
# Go ahead and auto-register a few common response types
# if the user has not done so explicitly. Use unique IDs which
# will never change or overlap with user ids.
def _reg_if_not(reg_tp: Type[Response], reg_id: int) -> None:
def _reg_if_not(reg_tp: type[Response], reg_id: int) -> None:
if reg_tp in self.response_ids_by_type:
return
assert self.response_types_by_id.get(reg_id) is None
@ -170,7 +167,7 @@ class MessageProtocol:
if __debug__:
# Make sure all Message types' return types are valid
# and have been assigned an ID as well.
all_response_types: Set[Type[Response]] = set()
all_response_types: set[type[Response]] = set()
for m_id, m_type in message_types.items():
m_rtypes = m_type.get_response_types()
assert isinstance(m_rtypes, list)
@ -208,7 +205,7 @@ class MessageProtocol:
"""Encode a response to a json string for transport."""
return self._encode(response, self.response_ids_by_type, 'response')
def _encode(self, message: Any, ids_by_type: Dict[Type, int],
def _encode(self, message: Any, ids_by_type: dict[type, int],
opname: str) -> str:
"""Encode a message to a json string for transport."""
@ -242,7 +239,9 @@ class MessageProtocol:
assert isinstance(out, (Response, type(None)))
return out
def _decode(self, data: str, types_by_id: Dict[int, Type],
# Weeeird; we get mypy errors returning dict[int, type] but
# dict[int, typing.Type] or dict[int, type[Any]] works..
def _decode(self, data: str, types_by_id: dict[int, type[Any]],
opname: str) -> Any:
"""Decode a message from a json string."""
msgfull = json.loads(data)
@ -283,8 +282,8 @@ class MessageProtocol:
"""Return common parts of generated modules."""
# pylint: disable=too-many-locals, too-many-branches
import textwrap
tpimports: Dict[str, List[str]] = {}
imports: Dict[str, List[str]] = {}
tpimports: dict[str, list[str]] = {}
imports: dict[str, list[str]] = {}
single_message_type = len(self.message_ids_by_type) == 1
@ -390,7 +389,7 @@ class MessageProtocol:
f'class {ppre}Bound{basename}(BoundMessageSender):\n'
f' """Protocol-specific bound sender."""\n')
def _filt_tp_name(rtype: Type[Response]) -> str:
def _filt_tp_name(rtype: type[Response]) -> str:
# We accept None to equal EmptyResponse so reflect that
# in the type annotation.
return 'None' if rtype is EmptyResponse else rtype.__name__
@ -485,7 +484,7 @@ class MessageProtocol:
# Define handler() overloads for all registered message types.
def _filt_tp_name(rtype: Type[Response]) -> str:
def _filt_tp_name(rtype: type[Response]) -> str:
# We accept None to equal EmptyResponse so reflect that
# in the type annotation.
return 'None' if rtype is EmptyResponse else rtype.__name__
@ -705,7 +704,7 @@ class MessageReceiver:
def __init__(self, protocol: MessageProtocol) -> None:
self.protocol = protocol
self._handlers: Dict[Type[Message], Callable] = {}
self._handlers: dict[type[Message], Callable] = {}
# noinspection PyProtectedMember
def register_handler(
@ -750,7 +749,7 @@ class MessageReceiver:
assert issubclass(msgtype, Message)
ret = anns.get('return')
responsetypes: Tuple[Union[Type[Any], Type[None]], ...]
responsetypes: tuple[Union[type[Any], type[None]], ...]
# Return types can be a single type or a union of types.
if isinstance(ret, _GenericAlias):
@ -807,7 +806,7 @@ class MessageReceiver:
raise TypeError(msg)
def _decode_incoming_message(self,
msg: str) -> Tuple[Message, Type[Message]]:
msg: str) -> tuple[Message, type[Message]]:
# Decode the incoming message.
msg_decoded = self.protocol.decode_message(msg)
msgtype = type(msg_decoded)
@ -815,7 +814,7 @@ class MessageReceiver:
return msg_decoded, msgtype
def _encode_response(self, response: Optional[Response],
msgtype: Type[Message]) -> str:
msgtype: type[Message]) -> str:
# A return value of None equals EmptyResponse.
if response is None:
@ -982,7 +981,7 @@ def create_receiver_module(basename: str,
def _protocol_from_code(protocol_create_code: str) -> MessageProtocol:
env: Dict = {}
env: dict = {}
exec(protocol_create_code, env) # pylint: disable=exec-used
protocol = env.get('protocol')
if not isinstance(protocol, MessageProtocol):

View file

@ -9,7 +9,7 @@ from enum import Enum, unique
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import Any, ClassVar, Type
from typing import Any, ClassVar
@unique
@ -113,7 +113,10 @@ def _windows_enable_color() -> bool:
fdout = os.open('CONOUT$', os.O_RDWR)
try:
hout = msvcrt.get_osfhandle(fdout) # type: ignore
# pylint: disable=useless-suppression
# pylint: disable=no-value-for-parameter
old_mode = wintypes.DWORD()
# pylint: enable=useless-suppression
kernel32.GetConsoleMode(hout, ctypes.byref(old_mode))
mode = (new_mode & mask) | (old_mode.value & ~mask)
kernel32.SetConsoleMode(hout, mode)
@ -298,7 +301,7 @@ class ClrNever(ClrBase):
_envval = os.environ.get('EFRO_TERMCOLORS')
_color_enabled: bool = (True if _envval == '1' else
False if _envval == '0' else _default_color_enabled())
Clr: Type[ClrBase]
Clr: type[ClrBase]
if _color_enabled:
Clr = ClrAlways
else:

View file

@ -14,8 +14,7 @@ from typing import TYPE_CHECKING, cast, TypeVar, Generic
if TYPE_CHECKING:
import asyncio
from efro.call import Call as Call # 'as Call' so we re-export.
from weakref import ReferenceType
from typing import Any, Dict, Callable, Optional, Type
from typing import Any, Callable, Optional
T = TypeVar('T')
TVAL = TypeVar('TVAL')
@ -35,7 +34,7 @@ else:
Call = functools.partial
def enum_by_value(cls: Type[TENUM], value: Any) -> TENUM:
def enum_by_value(cls: type[TENUM], value: Any) -> TENUM:
"""Create an enum from a value.
This is basically the same as doing 'obj = EnumType(value)' except
@ -93,7 +92,18 @@ def utc_this_hour() -> datetime.datetime:
tzinfo=now.tzinfo)
def empty_weakref(objtype: Type[T]) -> ReferenceType[T]:
def utc_this_minute() -> datetime.datetime:
"""Get offset-aware beginning of current minute in the utc time zone."""
now = datetime.datetime.now(datetime.timezone.utc)
return datetime.datetime(year=now.year,
month=now.month,
day=now.day,
hour=now.hour,
minute=now.minute,
tzinfo=now.tzinfo)
def empty_weakref(objtype: type[T]) -> weakref.ref[T]:
"""Return an invalidated weak-reference for the specified type."""
# At runtime, all weakrefs are the same; our type arg is just
# for the static type checker.
@ -233,7 +243,7 @@ class DispatchMethodWrapper(Generic[TARG, TRET]):
def register(func: Callable[[Any, Any], TRET]) -> Callable:
"""Register a new dispatch handler for this dispatch-method."""
registry: Dict[Any, Callable]
registry: dict[Any, Callable]
# noinspection PyProtectedMember,PyTypeHints
@ -294,7 +304,7 @@ class ValueDispatcher(Generic[TVAL, TRET]):
def __init__(self, call: Callable[[TVAL], TRET]) -> None:
self._base_call = call
self._handlers: Dict[TVAL, Callable[[], TRET]] = {}
self._handlers: dict[TVAL, Callable[[], TRET]] = {}
def __call__(self, value: TVAL) -> TRET:
handler = self._handlers.get(value)
@ -325,7 +335,7 @@ class ValueDispatcher1Arg(Generic[TVAL, TARG, TRET]):
def __init__(self, call: Callable[[TVAL, TARG], TRET]) -> None:
self._base_call = call
self._handlers: Dict[TVAL, Callable[[TARG], TRET]] = {}
self._handlers: dict[TVAL, Callable[[TARG], TRET]] = {}
def __call__(self, value: TVAL, arg: TARG) -> TRET:
handler = self._handlers.get(value)
@ -370,7 +380,7 @@ def valuedispatchmethod(
# in the function call dict and simply return a call.
_base_call = call
_handlers: Dict[TVAL, Callable[[TSELF], TRET]] = {}
_handlers: dict[TVAL, Callable[[TSELF], TRET]] = {}
def _add_handler(value: TVAL, addcall: Callable[[TSELF], TRET]) -> None:
if value in _handlers:
@ -394,7 +404,8 @@ def valuedispatchmethod(
# To the type checker's eyes we return a ValueDispatchMethod instance;
# this lets it know about our register func and type-check its usage.
# In reality we just return a raw function call (for reasons listed above).
if TYPE_CHECKING: # pylint: disable=no-else-return
# pylint: disable=undefined-variable, no-else-return
if TYPE_CHECKING:
return ValueDispatcherMethod[TVAL, TRET]()
else:
return _call_wrapper
@ -427,39 +438,79 @@ def make_hash(obj: Any) -> int:
return hash(tuple(frozenset(sorted(new_obj.items()))))
def asserttype(obj: Any, typ: Type[T]) -> T:
def asserttype(obj: Any, typ: type[T]) -> T:
"""Return an object typed as a given type.
Assert is used to check its actual type, so only use this when
failures are not expected. Otherwise use checktype.
"""
assert isinstance(typ, type), 'only actual types accepted'
assert isinstance(obj, typ)
return obj
def checktype(obj: Any, typ: Type[T]) -> T:
def asserttype_o(obj: Any, typ: type[T]) -> Optional[T]:
"""Return an object typed as a given optional type.
Assert is used to check its actual type, so only use this when
failures are not expected. Otherwise use checktype.
"""
assert isinstance(typ, type), 'only actual types accepted'
assert isinstance(obj, (typ, type(None)))
return obj
def checktype(obj: Any, typ: type[T]) -> T:
"""Return an object typed as a given type.
Always checks the type at runtime with isinstance and throws a TypeError
on failure. Use asserttype for more efficient (but less safe) equivalent.
"""
assert isinstance(typ, type), 'only actual types accepted'
if not isinstance(obj, typ):
raise TypeError(f'Expected a {typ}; got a {type(obj)}.')
return obj
def warntype(obj: Any, typ: Type[T]) -> T:
def checktype_o(obj: Any, typ: type[T]) -> Optional[T]:
"""Return an object typed as a given optional type.
Always checks the type at runtime with isinstance and throws a TypeError
on failure. Use asserttype for more efficient (but less safe) equivalent.
"""
assert isinstance(typ, type), 'only actual types accepted'
if not isinstance(obj, (typ, type(None))):
raise TypeError(f'Expected a {typ} or None; got a {type(obj)}.')
return obj
def warntype(obj: Any, typ: type[T]) -> T:
"""Return an object typed as a given type.
Always checks the type at runtime and simply logs a warning if it is
not what is expected.
"""
assert isinstance(typ, type), 'only actual types accepted'
if not isinstance(obj, typ):
import logging
logging.warning('warntype: expected a %s, got a %s', typ, type(obj))
return obj # type: ignore
def warntype_o(obj: Any, typ: type[T]) -> Optional[T]:
"""Return an object typed as a given type.
Always checks the type at runtime and simply logs a warning if it is
not what is expected.
"""
assert isinstance(typ, type), 'only actual types accepted'
if not isinstance(obj, (typ, type(None))):
import logging
logging.warning('warntype: expected a %s or None, got a %s', typ,
type(obj))
return obj # type: ignore
def assert_non_optional(obj: Optional[T]) -> T:
"""Return an object with Optional typing removed.