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/__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", "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", "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/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/05/95/792c416c8a4a399f4ad8a90cda06", "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/a1/68/606372da26157d45e396eda4a6fc", "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/12/00/87f70c8158a37abbbfb6e9226aa4", "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/f3/52/700948881e3ebcacebc842eb8e25", "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/11/f1/e4eb196828af3b9b53bfbc8c1b14", "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/6d/75/b8a6efdc2a5a8d0aa45a151c133c", "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/5b/9e/b4f1b05d0af9389501057b52141b", "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/e7/bf/7ce1b7cb02b9589a3d3aa24fb309", "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/fa/39/3affaf5911a076b45d51d33b9068", "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/03/72/5bd95cc26e648c9a53ded3e7c3f7", "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/cd/a4/4bc45cda2a7777e7f9738895e4bb", "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/01/1c/a1973631978d7b7a7d7f85ed6e7c", "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/e0/1c/c1f316bb1334145f691686c804b6", "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/7f/81/6543391def25718bf9ed0da8b9f3", "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/9b/06/5e1bd19506b1806f793637b73325", "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/1c/9b/994c9aff7a533da605d3c90bb93f", "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/dd/41/fd523388e077ca84d37a4fd912ad", "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/4b/9f/2f280864e003e275a4f7f324c4ee", "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/0b/a7/9c93f87f6e2430e1af483b2269ef", "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/f9/81/e339e45d6c650df8217acbfb5f29", "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/de/d8/ce0ae67d8fa1bc4afb931c2e8a0f", "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/7b/0a/4907ea64f8492164a84ab9503aaf", "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/48/b4/8ed406ae6ff13da64c7ec97b6f56", "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/63/60/190e42f26c0f1224c2ffa69e3992", "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/d0/61/a4936fb9455dcd014a1eb5e570f1", "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/29/75/b61dae6070661f68ddb54cf14ee4", "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/2f/31/1373c730b4e06c515a439b2e15d9", "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/7e/f2/567e3019d15c23424bd9c8562679", "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/b2/43/4c8e335e4771c9bbc01737ca8ca8", "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/0b/4c/6d68b4f4b2e10597ca74dff0b0cb", "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/1d/c1/f566397ffc7d5c943b32c6508479", "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/4d/07/d0ed02b5363672e0e1039567ce60", "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/8f/fc/e9c87d067c8511b8183f09dcd05d", "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/f7/e0/94da6e5b577853226c1ca81978de", "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/1b/06/983ab3446f2bf0b31a0d8c93322b", "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/1c/dd/cf46a040f49e72b0693f10f72ca6", "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/1b/f9/c5b6eeb4493d4a8acba006bc4293", "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/cc/d1/e7965899f642259e45adc059b629", "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/09/67/573507643fe3790b9f19ec707be0", "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/1a/d0/a33a7402cdf38076ac726f155fcf", "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/81/fb/68aaa7cb8fad0a49c6a9b47590b5", "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/7f/83/62496b38a9828d6ed21d41a636ea", "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/89/1a/9d4b19c0c6fa33db78e75376c7e8", "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/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" "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 - More internal work on V2 master-server communication
### 1.6.11 (20539, 2022-03-23) ### 1.6.11 (20539, 2022-03-23)

View File

@ -21,7 +21,7 @@
namespace ballistica { namespace ballistica {
// These are set automatically via script; don't modify them here. // 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"; const char* kAppVersion = "1.6.12";
// Our standalone globals. // Our standalone globals.

View File

@ -879,6 +879,7 @@ def test_extended_data() -> None:
def test_soft_default() -> None: def test_soft_default() -> None:
"""Test soft_default IOAttr value.""" """Test soft_default IOAttr value."""
# pylint: disable=too-many-locals # pylint: disable=too-many-locals
# pylint: disable=too-many-statements
# Try both of these with and without storage_name to make sure # Try both of these with and without storage_name to make sure
# soft_default interacts correctly with both cases. # soft_default interacts correctly with both cases.
@ -971,6 +972,7 @@ def test_soft_default() -> None:
@ioprepped @ioprepped
@dataclass @dataclass
class _TestClassD2: class _TestClassD2:
# noinspection PyTypeHints
lval: Annotated[set, IOAttrs(soft_default=set())] lval: Annotated[set, IOAttrs(soft_default=set())]
with pytest.raises(TypeError): with pytest.raises(TypeError):
@ -1035,3 +1037,29 @@ def test_soft_default() -> None:
with pytest.raises(TypeError): with pytest.raises(TypeError):
dataclass_from_dict(_TestClassE7, {}) 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()). boundaries (see efro.util.utc_today()).
'whole_hours', if True, requires datetime values to lie exactly on hour 'whole_hours', if True, requires datetime values to lie exactly on hour
boundaries (see efro.util.utc_this_hour()). boundaries (see efro.util.utc_this_hour()).
'soft_default', if passed, is used as a default for loading and storing 'soft_default', if passed, injects a default value into dataclass
purposes, but leaves the dataclass itself expecting a value to instantiation when the field is not present in the input data.
be passed in all constructor calls/etc. This is useful when fields This allows dataclasses to add new non-optional fields while
are added that should not be considered optional in new code but for gracefully 'upgrading' old data. Note that when a soft_default is
which there may exist old data that does not contain those values. present it will take precedence over field defaults when determining
'soft_default_factory' should be given instead of 'soft_default' for whether to store a value for a field with store_default=False
mutable types such as lists (to prevent the default from changing (since the soft_default value is what we'll get when reading that
over time). 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 # 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, # If we're not storing default values for this fella,
# we can skip all output processing if we've got a default value. # we can skip all output processing if we've got a default value.
if ioattrs is not None and not ioattrs.store_default: 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 default_factory: Any = field.default_factory
if field.default is not dataclasses.MISSING: if ioattrs.soft_default is not ioattrs.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 == value: if ioattrs.soft_default == value:
continue continue
elif ioattrs.soft_default_factory is not ioattrs.MISSING: elif ioattrs.soft_default_factory is not ioattrs.MISSING:
assert callable(ioattrs.soft_default_factory) assert callable(ioattrs.soft_default_factory)
if ioattrs.soft_default_factory() == value: if ioattrs.soft_default_factory() == value:
continue 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: else:
raise RuntimeError( raise RuntimeError(
f'Field {fieldname} of {cls.__name__} has' f'Field {fieldname} of {cls.__name__} has'