diff --git a/src/rune/runtime/base_data_class.py b/src/rune/runtime/base_data_class.py index cbf3d3a..5e794e8 100644 --- a/src/rune/runtime/base_data_class.py +++ b/src/rune/runtime/base_data_class.py @@ -72,6 +72,7 @@ def rune_serialize( self, *, validate_model: bool = True, + check_rune_constraints: bool = True, strict: bool = True, raise_validation_errors: bool = True, indent: int | None = None, @@ -92,6 +93,10 @@ def rune_serialize( serialization. It checks also all Rune type constraints. Defaults to True. + `check_rune_constraints (bool, optional):` If `validate_model` is + set to `True`, executes all model defined Rune constraints after + deserialization. Defaults to True. + `strict (bool, optional):` Perform strict attribute validation. Defaults to True. @@ -134,8 +139,10 @@ def rune_serialize( ''' try: if validate_model: - self.validate_model(strict=strict, - raise_exc=raise_validation_errors) + self.validate_model( + check_rune_constraints=check_rune_constraints, + strict=strict, + raise_exc=raise_validation_errors) root_meta = self.__dict__.setdefault(ROOT_CONTAINER, {}) root_meta['@type'] = self._FQRTN @@ -159,6 +166,7 @@ def rune_serialize( def rune_deserialize(cls, rune_json: str, validate_model: bool = True, + check_rune_constraints: bool = True, strict: bool = True, raise_validation_errors: bool = True) -> BaseModel: # pylint: disable=line-too-long @@ -171,6 +179,10 @@ def rune_deserialize(cls, deserialization. It checks also all Rune type constraints. Defaults to True. + `check_rune_constraints (bool, optional):` If `validate_model` is + set to `True`, executes all model defined Rune constraints after + deserialization. Defaults to True. + `strict (bool, optional):` Perform strict attribute validation. Defaults to True. @@ -186,7 +198,8 @@ def rune_deserialize(cls, rune_cls = cls._type_to_cls(rune_dict) model = rune_cls.model_validate(rune_dict, strict=strict) if validate_model: - model.validate_model(strict=strict, + model.validate_model(check_rune_constraints=check_rune_constraints, + strict=strict, raise_exc=raise_validation_errors) return model @@ -212,6 +225,7 @@ def resolve_references(self): self.bind_property_to(prop_nm, ref) def validate_model(self, + check_rune_constraints=True, recursively: bool = True, raise_exc: bool = True, strict: bool = True) -> list: @@ -226,8 +240,10 @@ def validate_model(self, self.disable_meta_checks() att_errors = self.validate_attribs(raise_exc=raise_exc, strict=strict) - return att_errors + self.validate_conditions( - recursively=recursively, raise_exc=raise_exc) + if check_rune_constraints: + att_errors.extend(self.validate_conditions( + recursively=recursively, raise_exc=raise_exc)) + return att_errors finally: self.enable_meta_checks() diff --git a/src/rune/runtime/utils.py b/src/rune/runtime/utils.py index 2543f67..fd335bb 100644 --- a/src/rune/runtime/utils.py +++ b/src/rune/runtime/utils.py @@ -22,7 +22,7 @@ # return eval(expr, globals(), {'self': obj}) # pylint: disable=eval-used -def if_cond_fn(ifexpr, thenexpr: Callable, elseexpr: Callable) -> Any: +def if_cond_fn(ifexpr: bool, thenexpr: Callable, elseexpr: Callable) -> Any: ''' A helper to return the value of the ternary operator (functional version). ''' diff --git a/test/cdm/test_trade_creation.py b/test/cdm/test_trade_creation.py new file mode 100644 index 0000000..af418f7 --- /dev/null +++ b/test/cdm/test_trade_creation.py @@ -0,0 +1,58 @@ +'''test the if condition runtime functionality''' +# pylint: disable=invalid-name +from datetime import date +import pytest +try: + # pylint: disable=unused-import + # type: ignore + from cdm.event.common.Trade import Trade + from cdm.event.common.TradeIdentifier import TradeIdentifier + from cdm.product.template.TradableProduct import TradableProduct + from cdm.product.template.Product import Product + from cdm.product.template.TradeLot import TradeLot + from cdm.product.common.settlement.PriceQuantity import PriceQuantity + from cdm.base.staticdata.party.Party import Party + from cdm.base.staticdata.party.PartyIdentifier import PartyIdentifier + from cdm.base.staticdata.party.Counterparty import Counterparty + from cdm.base.staticdata.party.CounterpartyRoleEnum import CounterpartyRoleEnum + from cdm.base.staticdata.asset.common.Index import Index + from cdm.base.staticdata.identifier.AssignedIdentifier import AssignedIdentifier + NO_SER_TEST_MOD = False +except ImportError: + NO_SER_TEST_MOD = True + + +@pytest.mark.skipif(NO_SER_TEST_MOD, reason='CDM package not found') +def test_simple_trade(): + '''Constructs a simple Trade in memory and validates the model.''' + price_quantity = PriceQuantity() + trade_lot = TradeLot(priceQuantity=[price_quantity]) + product = Product(index=Index()) + counterparty = [ + Counterparty(role=CounterpartyRoleEnum.PARTY_1, + partyReference=Party( + partyId=[PartyIdentifier(identifier='Acme Corp')])), + Counterparty( + role=CounterpartyRoleEnum.PARTY_2, + partyReference=Party( + partyId=[PartyIdentifier(identifier='Wile E. Coyote')])) + ] + tradable_product = TradableProduct(product=product, + tradeLot=[trade_lot], + counterparty=counterparty) + assigned_identifier = AssignedIdentifier(identifier='BIG DEAL!') + trade_identifier = [ + TradeIdentifier(issuer='Acme Corp', + assignedIdentifier=[assigned_identifier]) + ] + + # t = Trade(tradeDate=DateWithMeta(str(date(2023, 1, 1))), + t = Trade(tradeDate=date(2023, 1, 1), + tradableProduct=tradable_product, + tradeIdentifier=trade_identifier) + with pytest.raises(NameError): + exceptions = t.validate_model(raise_exc=False) + exceptions = t.validate_model(raise_exc=False, check_rune_constraints=False) + assert not exceptions + +# EOF