mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-25 08:23:35 +08:00
Added checks for storage name clashes to dataclassio
This commit is contained in:
parent
7f1458304d
commit
f2c0067ee1
1
.idea/dictionaries/ericf.xml
generated
1
.idea/dictionaries/ericf.xml
generated
@ -1649,6 +1649,7 @@
|
||||
<w>positionadjusted</w>
|
||||
<w>posixpath</w>
|
||||
<w>posixsubprocess</w>
|
||||
<w>posonlyargs</w>
|
||||
<w>postinit</w>
|
||||
<w>postinited</w>
|
||||
<w>postrun</w>
|
||||
|
||||
@ -738,6 +738,7 @@
|
||||
<w>positivex</w>
|
||||
<w>positivey</w>
|
||||
<w>positivez</w>
|
||||
<w>posonlyargs</w>
|
||||
<w>postinit</w>
|
||||
<w>postrun</w>
|
||||
<w>powerup</w>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
|
||||
<h4><em>last updated on 2021-05-25 for Ballistica version 1.6.4 build 20369</em></h4>
|
||||
<h4><em>last updated on 2021-05-26 for Ballistica version 1.6.4 build 20369</em></h4>
|
||||
<p>This page documents the Python classes and functions in the 'ba' module,
|
||||
which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p>
|
||||
<hr>
|
||||
|
||||
@ -623,3 +623,31 @@ def test_dict() -> None:
|
||||
obj4.dval = {_GoodEnum.VAL1: 999} # type: ignore
|
||||
with pytest.raises(TypeError):
|
||||
dataclass_to_dict(obj4)
|
||||
|
||||
|
||||
def test_name_clashes() -> None:
|
||||
"""Make sure we catch name clashes since we can remap attr names."""
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class _TestClass:
|
||||
ival: Annotated[int, IOAttrs('i')] = 4
|
||||
ival2: Annotated[int, IOAttrs('i')] = 5
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class _TestClass2:
|
||||
ival: int = 4
|
||||
ival2: Annotated[int, IOAttrs('ival')] = 5
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class _TestClass3:
|
||||
ival: Annotated[int, IOAttrs(store_default=False)] = 4
|
||||
ival2: Annotated[int, IOAttrs('ival')] = 5
|
||||
|
||||
@ -38,7 +38,7 @@ except ModuleNotFoundError:
|
||||
_pytz_utc = None # pylint: disable=invalid-name
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Dict, Type, Tuple, Optional, List
|
||||
from typing import Any, Dict, Type, Tuple, Optional, List, Set
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
@ -58,8 +58,14 @@ EXTRA_ATTRS_ATTR = '_DCIOEXATTRS'
|
||||
|
||||
|
||||
class Codec(Enum):
|
||||
"""Influences format used for input/output."""
|
||||
"""Specifies expected data format exported to or imported from."""
|
||||
|
||||
# Use only types that will translate cleanly to/from json: lists,
|
||||
# dicts with str keys, bools, ints, floats, and None.
|
||||
JSON = 'json'
|
||||
|
||||
# Mostly like JSON but passes bytes and datetime objects through
|
||||
# as-is instead of converting them to json-friendly types.
|
||||
FIRESTORE = 'firestore'
|
||||
|
||||
|
||||
@ -267,8 +273,8 @@ class PrepSession:
|
||||
'efro.dataclassio: implicitly prepping dataclass: %s.'
|
||||
' It is highly recommended to explicitly prep dataclasses'
|
||||
' as soon as possible after definition (via'
|
||||
' efro.dataclassio.dataclass_prep() or the'
|
||||
' @efro.dataclassio.prepped decorator).', cls)
|
||||
' efro.dataclassio.ioprep() or the'
|
||||
' @efro.dataclassio.ioprepped decorator).', cls)
|
||||
|
||||
try:
|
||||
# NOTE: perhaps we want to expose the globalns/localns args
|
||||
@ -287,6 +293,7 @@ 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] = {}
|
||||
|
||||
# Ok; we've resolved actual types for this dataclass.
|
||||
@ -301,7 +308,18 @@ class PrepSession:
|
||||
if ioattrs is not None:
|
||||
ioattrs.validate_for_field(cls, fields_by_name[attrname])
|
||||
if ioattrs.storagename is not None:
|
||||
storagename = ioattrs.storagename
|
||||
storage_names_to_attr_names[ioattrs.storagename] = attrname
|
||||
else:
|
||||
storagename = attrname
|
||||
else:
|
||||
storagename = attrname
|
||||
|
||||
# Make sure we don't have any clashes in our storage names.
|
||||
if storagename in all_storage_names:
|
||||
raise TypeError(f'Multiple attrs on {cls} are using'
|
||||
f' storage-name \'{storagename}\'')
|
||||
all_storage_names.add(storagename)
|
||||
|
||||
self.prep_type(cls,
|
||||
attrname,
|
||||
|
||||
@ -140,6 +140,7 @@ def func_annotations_filter(node: nc.NodeNG) -> nc.NodeNG:
|
||||
node.args.varargannotation = None
|
||||
node.args.kwargannotation = None
|
||||
node.args.kwonlyargs_annotations = [None for _ in node.args.kwonlyargs]
|
||||
node.args.posonlyargs_annotations = [None for _ in node.args.kwonlyargs]
|
||||
|
||||
# Wipe out return-value annotation.
|
||||
if node.returns is not None:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user