fixing corner-cases on dataclassio soft_defaults

This commit is contained in:
Eric Froemling 2022-04-21 22:39:13 -07:00
parent 87460145db
commit 6c7c346983
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
6 changed files with 97 additions and 61 deletions

View File

@ -3971,50 +3971,50 @@
"assets/src/ba_data/python/ba/_generated/__init__.py": "https://files.ballistica.net/cache/ba1/ee/e8/cad05aa531c7faf7ff7b96db7f6e",
"assets/src/ba_data/python/ba/_generated/enums.py": "https://files.ballistica.net/cache/ba1/b2/e5/0ee0561e16257a32830645239f34",
"ballisticacore-windows/Generic/BallisticaCore.ico": "https://files.ballistica.net/cache/ba1/89/c0/e32c7d2a35dc9aef57cc73b0911a",
"build/prefab/full/linux_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/5e/57/faba903f766084e7e4e5b6eebb73",
"build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/05/95/792c416c8a4a399f4ad8a90cda06",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a1/68/606372da26157d45e396eda4a6fc",
"build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/12/00/87f70c8158a37abbbfb6e9226aa4",
"build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f3/52/700948881e3ebcacebc842eb8e25",
"build/prefab/full/linux_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/11/f1/e4eb196828af3b9b53bfbc8c1b14",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6d/75/b8a6efdc2a5a8d0aa45a151c133c",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5b/9e/b4f1b05d0af9389501057b52141b",
"build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e7/bf/7ce1b7cb02b9589a3d3aa24fb309",
"build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/fa/39/3affaf5911a076b45d51d33b9068",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/03/72/5bd95cc26e648c9a53ded3e7c3f7",
"build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/cd/a4/4bc45cda2a7777e7f9738895e4bb",
"build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/01/1c/a1973631978d7b7a7d7f85ed6e7c",
"build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/e0/1c/c1f316bb1334145f691686c804b6",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7f/81/6543391def25718bf9ed0da8b9f3",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9b/06/5e1bd19506b1806f793637b73325",
"build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/1c/9b/994c9aff7a533da605d3c90bb93f",
"build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/dd/41/fd523388e077ca84d37a4fd912ad",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/4b/9f/2f280864e003e275a4f7f324c4ee",
"build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/0b/a7/9c93f87f6e2430e1af483b2269ef",
"build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f9/81/e339e45d6c650df8217acbfb5f29",
"build/prefab/lib/linux_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/de/d8/ce0ae67d8fa1bc4afb931c2e8a0f",
"build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/7b/0a/4907ea64f8492164a84ab9503aaf",
"build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/48/b4/8ed406ae6ff13da64c7ec97b6f56",
"build/prefab/lib/linux_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/63/60/190e42f26c0f1224c2ffa69e3992",
"build/prefab/lib/linux_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d0/61/a4936fb9455dcd014a1eb5e570f1",
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/29/75/b61dae6070661f68ddb54cf14ee4",
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/2f/31/1373c730b4e06c515a439b2e15d9",
"build/prefab/lib/mac_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/7e/f2/567e3019d15c23424bd9c8562679",
"build/prefab/lib/mac_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b2/43/4c8e335e4771c9bbc01737ca8ca8",
"build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/0b/4c/6d68b4f4b2e10597ca74dff0b0cb",
"build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/1d/c1/f566397ffc7d5c943b32c6508479",
"build/prefab/lib/mac_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4d/07/d0ed02b5363672e0e1039567ce60",
"build/prefab/lib/mac_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/8f/fc/e9c87d067c8511b8183f09dcd05d",
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f7/e0/94da6e5b577853226c1ca81978de",
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/1b/06/983ab3446f2bf0b31a0d8c93322b",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/1c/dd/cf46a040f49e72b0693f10f72ca6",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/1b/f9/c5b6eeb4493d4a8acba006bc4293",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/cc/d1/e7965899f642259e45adc059b629",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/09/67/573507643fe3790b9f19ec707be0",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/1a/d0/a33a7402cdf38076ac726f155fcf",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/81/fb/68aaa7cb8fad0a49c6a9b47590b5",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/7f/83/62496b38a9828d6ed21d41a636ea",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/89/1a/9d4b19c0c6fa33db78e75376c7e8",
"build/prefab/full/linux_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/38/10/0a2c34f84442f87a9b3f156c827e",
"build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/56/ab/886a1d0b8f056a9475bce24bef78",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/75/7c/3ac039f3e2bc3863a79190df0a20",
"build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9e/53/f2a2a34c718cd879fbcba208990b",
"build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/5d/f1/fbba8e0f2409c8337f9650f97d4b",
"build/prefab/full/linux_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ff/79/3b604eb27337dd6dea930e18a8e9",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/18/53/b23f80dcaf61590a6e0be83e5def",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9a/e8/2869a6771945356753256489edd4",
"build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/73/31/215a9ea8602c9eedfc3b0ec86968",
"build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d9/41/bca103eecac94211a3b0bd37c791",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/41/c2/7d827e1feed6f024265b5da625f5",
"build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/38/8d/dca73da1629d31852bc56f198100",
"build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/19/60/e2624ed2ec3d3caf843dfd9a48d3",
"build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9b/2f/69481fe386808d71ce83aa3c4bb9",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/71/31/52d11e57daf0eaba4f56ddf2231b",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0b/a7/72e7b8c1e96d3b6d0781bfdab15c",
"build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/54/39/49c6542bebb875c879cef5b8ca34",
"build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/81/d2/be60a229ae04a7f23f602ccb0b7f",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/28/c2/bb75bdc44b391da37ead4336da35",
"build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/92/1e/30720a710e81e534d5d8b31e3ad5",
"build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e9/bc/b9747bc5a17617dac9755df078a4",
"build/prefab/lib/linux_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/89/36/71f0e9e7ea3936f65b910f556f92",
"build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ac/b7/5d62ae450fdad94b86cad99c9745",
"build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/67/8f/aa0f8d5773f89f12cffa96880246",
"build/prefab/lib/linux_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/9c/f8/ac8ef9466a16d69f173e2850f16e",
"build/prefab/lib/linux_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/82/cc/4ff76cd6bdea37b7c963c2cca10b",
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c9/fd/4d68490a8241e63902c91b15570b",
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/24/f0/7c60c093c7bf5395a9b7852a5cfb",
"build/prefab/lib/mac_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/0a/09/13882a2f77a2d541b2c7a88150ca",
"build/prefab/lib/mac_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e1/34/c31c62a060131eb5e595168bc790",
"build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/cd/42/0c7e1d35dff80532970383caa071",
"build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/5f/0a/87ddb51c6d5c1aec2c3dc82a27e8",
"build/prefab/lib/mac_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a3/57/2199e4ba33a04c7348a2f5b8dc82",
"build/prefab/lib/mac_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/6c/c6/57362d1d7178320bf9dac5fe0285",
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c5/18/1d172d359e0d33136e09a80b9a4a",
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e5/2b/64feae0cdcda08fbc1609e5c0e62",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/33/73/bb77f2b20ce21a6dd10cca09854f",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/e1/34/aed137660c10c32d83e76f80da89",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/7d/52/26420283884baedbb01a27b7b047",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/ba/0b/3f781295ba0edd23ab3b7de864e0",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/58/64/3ea3064c4fca680739849870da7f",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/6e/4d/edf21d0067ac2e3dda570c5d0bd9",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/f5/4d/aca2657fecc50d43b1bc2982228d",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/00/26/3c127d5291013970420d11056931",
"src/ballistica/generated/python_embedded/binding.inc": "https://files.ballistica.net/cache/ba1/b3/15/7c6d580b3482870b5b058858624c",
"src/ballistica/generated/python_embedded/bootstrap.inc": "https://files.ballistica.net/cache/ba1/d3/db/e73d4dcf1280d5f677c3cf8b47c3"
}

View File

@ -1,4 +1,4 @@
### 1.6.12 (20563, 2022-04-21)
### 1.6.12 (20565, 2022-04-21)
- More internal work on V2 master-server communication
### 1.6.11 (20539, 2022-03-23)

View File

@ -21,7 +21,7 @@
namespace ballistica {
// These are set automatically via script; don't modify them here.
const int kAppBuildNumber = 20563;
const int kAppBuildNumber = 20565;
const char* kAppVersion = "1.6.12";
// Our standalone globals.

View File

@ -879,6 +879,7 @@ def test_extended_data() -> None:
def test_soft_default() -> None:
"""Test soft_default IOAttr value."""
# pylint: disable=too-many-locals
# pylint: disable=too-many-statements
# Try both of these with and without storage_name to make sure
# soft_default interacts correctly with both cases.
@ -971,6 +972,7 @@ def test_soft_default() -> None:
@ioprepped
@dataclass
class _TestClassD2:
# noinspection PyTypeHints
lval: Annotated[set, IOAttrs(soft_default=set())]
with pytest.raises(TypeError):
@ -1035,3 +1037,29 @@ def test_soft_default() -> None:
with pytest.raises(TypeError):
dataclass_from_dict(_TestClassE7, {})
# If both a soft_default and regular field default are present,
# make sure soft_default takes precedence (it applies before
# data even hits the dataclass constructor).
@ioprepped
@dataclass
class _TestClassE8:
ival: Annotated[int, IOAttrs(soft_default=1, store_default=False)] = 2
assert dataclass_from_dict(_TestClassE8, {}).ival == 1
# Make sure soft_default gets used both when determining when
# to omit values from output and what to recreate missing values as.
orig = _TestClassE8(ival=1)
todict = dataclass_to_dict(orig)
assert todict == {}
assert dataclass_from_dict(_TestClassE8, todict) == orig
# Instantiate with the dataclass default and it should still get
# explicitly despite the store_default=False because soft_default
# takes precedence.
orig = _TestClassE8()
todict = dataclass_to_dict(orig)
assert todict == {'ival': 2}
assert dataclass_from_dict(_TestClassE8, todict) == orig

View File

@ -107,14 +107,18 @@ class IOAttrs:
boundaries (see efro.util.utc_today()).
'whole_hours', if True, requires datetime values to lie exactly on hour
boundaries (see efro.util.utc_this_hour()).
'soft_default', if passed, is used as a default for loading and storing
purposes, but leaves the dataclass itself expecting a value to
be passed in all constructor calls/etc. This is useful when fields
are added that should not be considered optional in new code but for
which there may exist old data that does not contain those values.
'soft_default_factory' should be given instead of 'soft_default' for
mutable types such as lists (to prevent the default from changing
over time).
'soft_default', if passed, injects a default value into dataclass
instantiation when the field is not present in the input data.
This allows dataclasses to add new non-optional fields while
gracefully 'upgrading' old data. Note that when a soft_default is
present it will take precedence over field defaults when determining
whether to store a value for a field with store_default=False
(since the soft_default value is what we'll get when reading that
same data back in when the field is omitted).
'soft_default_factory' is similar to 'default_factory' in dataclass
fields; it should be used instead of 'soft_default' for mutable types
such as lists to prevent a single default object from unintentionally
changing over time.
"""
# A sentinel object to detect if a parameter is supplied or not. Use

View File

@ -78,20 +78,24 @@ class _Outputter:
# If we're not storing default values for this fella,
# we can skip all output processing if we've got a default value.
if ioattrs is not None and not ioattrs.store_default:
# If both soft_defaults and regular field defaults
# are present we want to go with soft_defaults since
# those same values would be re-injected when reading
# the same data back in if we've omitted the field.
default_factory: Any = field.default_factory
if field.default is not dataclasses.MISSING:
if field.default == value:
continue
elif default_factory is not dataclasses.MISSING:
if default_factory() == value:
continue
elif ioattrs.soft_default is not ioattrs.MISSING:
if ioattrs.soft_default is not ioattrs.MISSING:
if ioattrs.soft_default == value:
continue
elif ioattrs.soft_default_factory is not ioattrs.MISSING:
assert callable(ioattrs.soft_default_factory)
if ioattrs.soft_default_factory() == value:
continue
elif field.default is not dataclasses.MISSING:
if field.default == value:
continue
elif default_factory is not dataclasses.MISSING:
if default_factory() == value:
continue
else:
raise RuntimeError(
f'Field {fieldname} of {cls.__name__} has'