Skip to content

Commit

Permalink
Datatype coercion config
Browse files Browse the repository at this point in the history
Unifies STRICT_TYPE_CONFORMANCE and DISABLE_TYPE_CONFORMANCE into `datatypes.config.COERCION`.
  • Loading branch information
ManicJamie committed Apr 28, 2024
1 parent 9e6ea2b commit da34e69
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 25 deletions.
6 changes: 3 additions & 3 deletions src/speedruncompy/datatypes/_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def __init__(self, template: Union[dict, tuple, "Datatype", None] = None, skipCh
self.__dict__[name] = template[pos]
elif isinstance(template, Datatype):
self.__dict__ |= template.get_dict()
if not skipChecking and not config.DISABLE_TYPE_CONFORMANCE:
if not skipChecking and config.COERCION != -1:
self.enforce_types()

@classmethod
Expand Down Expand Up @@ -108,12 +108,12 @@ def enforce_types(self):
if true_type == Any: _log.debug(f"Undocumented attr {fieldname} has value {raw} of type {type(raw)}")
elif not is_type(attr, hint):
msg = f"Datatype {type(self).__name__}'s attribute {fieldname} expects {nullable_type} but received {type(attr).__name__} = {attr}"
if config.STRICT_TYPE_CONFORMANCE: raise AttributeError(msg)
if config.COERCION == 1: raise AttributeError(msg)
else: _log.warning(msg)

if len(missing_fields) > 0:
msg = f"Datatype {type(self).__name__} constructed missing mandatory fields {missing_fields}"
if config.STRICT_TYPE_CONFORMANCE: raise IncompleteDatatype(msg)
if config.COERCION == 1: raise IncompleteDatatype(msg)
else: _log.warning(msg)


Expand Down
22 changes: 11 additions & 11 deletions src/speedruncompy/datatypes/config.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
STRICT_TYPE_CONFORMANCE = False
"""Whether to raise an error or just warn when a type is incomplete.
import enum, typing

Setting this to True might screw you over if SRC decide to remove parts of a type."""
class CoercionLevel(enum.IntEnum):
DISABLED = -1
ENABLED = 0
STRICT = 1

DISABLE_TYPE_CONFORMANCE = False
"""Whether to automatically convert calls and nested datatypes from dictionaries to their typed equivalents.
COERCION: typing.Union[CoercionLevel, int] = 0
"""How aggressively to enforce type coercion.
Will probably improve performance on responses that retrieve a lot of data."""

#TODO: combine into single param, since Strict does nothing when Disabled

SUPPRESS_FIELD_WARNINGS = False
"""Suppress warnings that a type is """
-1: Disabled; types will not be coerced. WARN: field accessors will break!
0: Enabled; types will be coerced. Sends log warnings on incomplete types.
1: Strict; types will be coerced. Raises errors on incomplete types.
"""
11 changes: 5 additions & 6 deletions test/test_datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from random import randint, sample

from speedruncompy.datatypes import *
from speedruncompy.datatypes._impl import _OptFieldMarker
from speedruncompy import datatypes
from speedruncompy.endpoints import *
from speedruncompy.exceptions import IncompleteDatatype
Expand All @@ -21,19 +20,19 @@
# All tests are done with strict type conformance to catch errors early
# In downstream this is default False, and warnings are given instead of errors.
# See `TestDatatypes.test_Missing_Fields_Loose` for behaviour without STRICT.
datatypes.config.STRICT_TYPE_CONFORMANCE = True
datatypes.config.COERCION = 1

@pytest.fixture()
def loose_type_conformance():
datatypes.config.STRICT_TYPE_CONFORMANCE = False
datatypes.config.COERCION = 0
yield
datatypes.config.STRICT_TYPE_CONFORMANCE = True
datatypes.config.COERCION = 1

@pytest.fixture()
def disable_type_checking():
datatypes.config.DISABLE_TYPE_CONFORMANCE = True
datatypes.config.COERCION = -1
yield
datatypes.config.DISABLE_TYPE_CONFORMANCE = False
datatypes.config.COERCION = 1

class TestDatatypes():
def test_Datatype_conformance(self):
Expand Down
10 changes: 5 additions & 5 deletions test/test_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,19 +66,19 @@
# All tests are done with strict type conformance to catch errors early
# In downstream this is default False, and warnings are given instead of errors.
# See `TestDatatypes.test_Missing_Fields_Loose` for behaviour without STRICT.
defs.STRICT_TYPE_CONFORMANCE = True
datatypes.config.COERCION = datatypes.config.CoercionLevel.STRICT

@pytest.fixture()
def loose_type_conformance():
defs.STRICT_TYPE_CONFORMANCE = False
datatypes.config.COERCION = datatypes.config.CoercionLevel.ENABLED
yield
defs.STRICT_TYPE_CONFORMANCE = True
datatypes.config.COERCION = datatypes.config.CoercionLevel.STRICT

@pytest.fixture()
def disable_type_checking():
defs.DISABLE_TYPE_CONFORMANCE = True
datatypes.config.COERCION = datatypes.config.CoercionLevel.DISABLED
yield
defs.DISABLE_TYPE_CONFORMANCE = False
datatypes.config.COERCION = datatypes.config.CoercionLevel.STRICT

@pytest.fixture(autouse=True)
def check_api_conformance():
Expand Down

0 comments on commit da34e69

Please sign in to comment.