Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add support for callable defaultValue in BooleanBone #1274

23 changes: 21 additions & 2 deletions src/viur/core/bones/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,8 @@ def __init__(
if isinstance(required, (tuple, list)) and languages and (diff := set(required).difference(languages)):
raise ValueError(f"The language(s) {', '.join(map(repr, diff))} can not be required, "
f"because they're not defined.")
if callable(defaultValue) and len(inspect.signature(defaultValue).parameters) < 2:
raise ValueError(f"Callable default values require for two parameters (self and skel)")

self.languages = languages

Expand All @@ -272,7 +274,10 @@ def __init__(
# multiple or has languages
if self.languages:
if not isinstance(defaultValue, dict):
self.defaultValue = {lang: defaultValue for lang in self.languages}
if callable(defaultValue):
self.defaultValue = defaultValue
else:
self.defaultValue = {lang: defaultValue for lang in self.languages}
elif "__default__" in defaultValue:
self.defaultValue = {lang: defaultValue.get(lang, defaultValue["__default__"])
for lang in self.languages}
Expand Down Expand Up @@ -381,7 +386,21 @@ def getDefaultValue(self, skeletonInstance):
:return: The default value of the bone, which can be of any data type.
"""
if callable(self.defaultValue):
return self.defaultValue(skeletonInstance, self)
res = self.defaultValue(skeletonInstance, self)
if self.languages and self.multiple:
if not isinstance(res, dict):
if not isinstance(res, (list, set, tuple)):
return {lang: [res] for lang in self.languages}
else:
return {lang: res for lang in self.languages}
elif self.languages:
if not isinstance(res, dict):
return {lang: res for lang in self.languages}
elif self.multiple:
if not isinstance(res, (list, set, tuple)):
return [res]
return res

elif isinstance(self.defaultValue, list):
return self.defaultValue[:]
elif isinstance(self.defaultValue, dict):
Expand Down
9 changes: 5 additions & 4 deletions src/viur/core/bones/boolean.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import typing as t

from viur.core import conf, db, utils
from viur.core.bones.base import BaseBone


DEFAULT_VALUE_T: t.TypeAlias = bool | None | list[bool] | dict[str, list[bool] | bool]

class BooleanBone(BaseBone):
"""
Represents a boolean data type, which can have two possible values: `True` or `False`.
Expand All @@ -18,13 +19,13 @@ class BooleanBone(BaseBone):
def __init__(
self,
*,
defaultValue: bool | list[bool] | dict[str, list[bool] | bool] = None,
defaultValue: DEFAULT_VALUE_T | t.Callable[[t.Self, "SkeletonInstance"], DEFAULT_VALUE_T] = None,
**kwargs
):
if defaultValue is not None:
# We have given an explicit defaultValue and maybe a complex structure
if not (kwargs.get("multiple") or kwargs.get("languages")) and not (isinstance(defaultValue, bool)):
raise TypeError("Only 'True', 'False' or 'None' can be provided as BooleanBone defaultValue")
if not kwargs.get("languages") and not (isinstance(defaultValue, bool) or callable(defaultValue)):
raise TypeError("Only 'True', 'False' , 'None' or callable can be provided as BooleanBone defaultValue")
ArneGudermann marked this conversation as resolved.
Show resolved Hide resolved
# TODO: missing validation for complex types, but in other bones too

super().__init__(defaultValue=defaultValue, **kwargs)
Expand Down
Loading