Skip to content

Commit

Permalink
Changes to utilize the new Python code generator (v2) (finos#2869)
Browse files Browse the repository at this point in the history
* update to use the new Python Generator (v2).  Includes expanded Python unit tests

* cleanup validation test

* Python Generator Cleanup

* revert bundle usage in pom

* additional pom cleanup

* Updated to align to CDM bundle changes

* additional alignment to next version of CDM

* release.md clean up

* one more release.md update

* Update pom.xml to use correct bundle version

---------

Co-authored-by: minesh-s-patel <[email protected]>
  • Loading branch information
2 people authored and JayasriR committed Apr 19, 2024
1 parent 8edecc5 commit 9243405
Show file tree
Hide file tree
Showing 20 changed files with 323 additions and 127 deletions.
14 changes: 14 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,17 @@ In Rosetta, select the Textual Browser and inspect the changes identified above.

The changes can be reviewed in PR: [#2856](https://github.com/finos/common-domain-model/pull/2856)

# _Python Generator v2_

_What is being released?_

This release uses the new version of the Python generator (v2) which includes the following changes:

- Migration to Pydantic 2.x
- More comprehensive support for Rosetta's operators
- Resolves the defect exposed by [PR 2766](https://github.com/finos/common-domain-model/pull/2766)
- Includes an update to the Python Rosetta runtime library used to encapsulate the Pydantic support (now version 2.0.0)

_Review directions_

The changes can be reviewed in PR: [#2869](https://github.com/finos/common-domain-model/pull/2869)
7 changes: 4 additions & 3 deletions codefresh.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,15 @@ steps:
working_directory: ./rosetta-source
shell: sh
commands:
- python3 -m pip install "pydantic==1.*"
- export PYTHONDONTWRITEBYTECODE=1
- python3 -m pip install pydantic
- python3 -m pip install jsonpickle
- python3 -m pip install ./target/classes/cdm/python/runtime/rosetta_runtime-1.0.0-py3-none-any.whl
- python3 -m pip install ./target/classes/cdm/python/runtime/rosetta_runtime-2.0.0-py3-none-any.whl
- |-
python3 -m pip wheel --no-deps --only-binary :all: --wheel-dir ./target/classes/cdm/python ./target/classes/cdm/python
- python3 -m pip install ./target/classes/cdm/python/python_cdm-*-py3-none-any.whl
- python3 -m pip install pytest
- rm -rf ./src/test/python/serialization/__pycache__ ./src/test/python/semantics/__pycache__
- pytest -p no:cacheprovider ./src/test/python/

DeployDaml:
stage: 'build'
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@

<repoServerHost>oss.sonatype.org</repoServerHost>

<rosetta.bundle.version>10.15.3</rosetta.bundle.version>
<rosetta.bundle.version>10.15.8</rosetta.bundle.version>
<rosetta.code-gen.version>${rosetta.bundle.version}</rosetta.code-gen.version>
<rosetta.dsl.version>9.7.0</rosetta.dsl.version>

Expand Down
2 changes: 1 addition & 1 deletion rosetta-source/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,7 @@
<version>${rosetta.code-gen.version}</version>
<type>jar</type>
<outputDirectory>${project.build.directory}/classes/cdm/python</outputDirectory>
<includes>runtime/rosetta_runtime-1.0.0-py3-none-any.whl</includes>
<includes>runtime/rosetta_runtime-2.0.0-py3-none-any.whl</includes>
</artifactItem>
</artifactItems>
<overWriteReleases>false</overWriteReleases>
Expand Down
Empty file.
24 changes: 0 additions & 24 deletions rosetta-source/src/test/python/run_tests.sh

This file was deleted.

24 changes: 13 additions & 11 deletions rosetta-source/src/test/python/semantics/test_cardinality.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,37 @@
import pytest
'''testing cardinality enforcement'''
import datetime
import pytest
from cdm.base.datetime.DateList import DateList
from rosetta.runtime.utils import ConditionViolationError


def test_1_many_fail():
'''DateList cannot be empty'''
dl = DateList(date=[])
with pytest.raises(ConditionViolationError):
dl.validate_conditions()


def test_1_many_fail_nopar():
def test_1_many_fail_empty_constructor():
'''DateList cannot be empty'''
dl = DateList()
with pytest.raises(ConditionViolationError):
dl.validate_conditions()


def test_1_many_pass():
'''Valid DateList'''
dl = DateList(date=[datetime.date(2020, 1, 1)])
dl.validate_conditions()


if __name__ == "__main__":
print("first one")
test_1_many_pass()
print("second one")
test_1_many_fail()
print("third one")
test_1_many_fail_nopar()


# EOF
print("test_1_many_pass")
test_1_many_pass()
print("test_1_many_fail")
test_1_many_fail()
print("test_1_many_fail_empty_constructor")
test_1_many_fail_empty_constructor()


# EOF
36 changes: 23 additions & 13 deletions rosetta-source/src/test/python/semantics/test_conditions.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,50 @@
'''Full attribute validation - pydantic and constraints'''
import pytest
from pydantic import ValidationError
from rosetta.runtime.utils import ConditionViolationError
from cdm.base.math.NonNegativeQuantity import NonNegativeQuantity
from cdm.base.math.UnitType import UnitType
from cdm.base.datetime.Frequency import Frequency
from cdm.base.datetime.PeriodExtendedEnum import PeriodExtendedEnum

'''
def test_recursive_conds():
unit = UnitType(currency='EUR')
mq = NonNegativeQuantity(value=10, unit=unit)
mq.validate_model()

'''

def test_recursive_conds_base_fail():
def test_recursive_conditions_base_fail():
'''condition_0_AmountOnlyExists violation'''
unit = UnitType(currency='EUR')
mq = NonNegativeQuantity(unit=unit)
with pytest.raises(ConditionViolationError):
mq.validate_model()

def test_recursive_conds_direct_fail():

def test_recursive_conditions_direct_fail():
'''Negative quantity condition violation'''
unit = UnitType(currency='EUR')
mq = NonNegativeQuantity(value=-10, unit=unit)
with pytest.raises(ConditionViolationError):
mq.validate_model()


def test_attrib_validity():
def test_bad_attrib_validation():
'''Invalid attribute assigned'''
unit = UnitType(currency='EUR')
mq = NonNegativeQuantity(value=10, unit=unit)
mq.frequency = 'Blah'
with pytest.raises(ValidationError):
mq.validate_model()


def test_correct_attrib_validation():
'''Valid attribute assigned'''
unit = UnitType(currency='EUR')
mq = NonNegativeQuantity(value=10, unit=unit)
mq.frequency = Frequency(periodMultiplier=1, period=PeriodExtendedEnum.M)
mq.validate_model()


if __name__ == "__main__":
test_recursive_conds_base_fail()
test_recursive_conds_direct_fail()
test_attrib_validity()
test_recursive_conditions_base_fail()
test_recursive_conditions_direct_fail()
test_bad_attrib_validation()
test_correct_attrib_validation()

# EOF
39 changes: 6 additions & 33 deletions rosetta-source/src/test/python/semantics/test_if_cond.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,10 @@
import pytest
from rosetta.runtime.utils import ConditionViolationError
from rosetta.runtime.utils import if_cond
##from cdm.base.math.Measure import Measure
from cdm.base.math.QuantitySchedule import QuantitySchedule
from cdm.base.math.UnitType import UnitType
##from drr.regulation.cftc.rewrite.CFTCPart43TransactionReport import CFTCPart43TransactionReport
from rosetta.runtime.utils import _resolve_rosetta_attr


'''
def test_if_cond_pass():
unit = UnitType(currency='EUR')
multiplier = Measure(value=1)
qs = QuantitySchedule(value=1, unit=unit, multiplier=multiplier)
qs.validate_conditions()
def test_if_cond_fail():
unit = UnitType(currency='EUR')
multiplier = Measure(value=-1)
qs = QuantitySchedule(unit=unit, multiplier=multiplier)
with pytest.raises(ConditionViolationError):
qs.validate_conditions()
'''
def test_if_cond_literals():
class T:
def __init__(self):
Expand All @@ -48,18 +30,6 @@ def __init__(self):
self)
assert res

'''
def test_if_cond_any():
class T:
def __init__(self):
self.actionType = "TERM"
self.eventType = 'CORP'
self = T()
fnc = CFTCPart43TransactionReport.condition_0_EventTypeCondition
res = fnc(self)
assert res
'''
def test_if_direct():
class T:
def __init__(self):
Expand All @@ -75,7 +45,10 @@ def __init__(self):
'True', T())

if __name__ == "__main__":
test_if_cond_literals()
test_if_direct()
print('test_if_cond_literals',end='')
test_if_cond_literals()
print('...passed\ntest_if_direct', end='')
test_if_direct()
print('...passed')

# EOF
51 changes: 51 additions & 0 deletions rosetta-source/src/test/python/semantics/test_local_conditions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
'''Tests of the local registration of conditions'''
import inspect
import pytest
from rosetta.runtime.utils import rosetta_local_condition
from rosetta.runtime.utils import execute_local_conditions
from rosetta.runtime.utils import ConditionViolationError


def test_pre_post_conditions():
'''Tests the registration of functions in two different registries'''
_pre_registry = {}
_post_registry = {}
self = inspect.currentframe()

# A local PRE condition
@rosetta_local_condition(_pre_registry)
def some_local_condition():
print(f'Pre {self}')
return True

# A local POST condition
@rosetta_local_condition(_post_registry)
def some_local_post_condition():
print(f'Post {self}')
return True

# Check all PRE conditions
execute_local_conditions(_pre_registry, 'Pre-condition')

print('Some Code....')

# Check all POST conditions
execute_local_conditions(_post_registry, 'Post-condition')


def test_raise_local_cond():
'''checks if exception is raised and it is of the correct type'''
_registry = {}
@rosetta_local_condition(_registry)
def some_failing_local_post_condition():
return False

with pytest.raises(ConditionViolationError):
execute_local_conditions(_registry, 'condition')


if __name__ == '__main__':
test_pre_post_conditions()
test_raise_local_cond()

# EOF
26 changes: 26 additions & 0 deletions rosetta-source/src/test/python/semantics/test_pydantic_simple.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# pylint: disable=unused-import,missing-function-docstring,invalid-name
from datetime import date
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


def test_trade():
product = Product()
tradableProduct = TradableProduct(product=product)
tradeIdentifier=[TradeIdentifier(issuer='Acme Corp')]

t = Trade(
tradeDate=date(2023, 1, 1),
tradableProduct=tradableProduct,
tradeIdentifier=tradeIdentifier
)
print(t.model_dump())
print('Done!')


if __name__ == '__main__':
test_trade()

# EOF
Loading

0 comments on commit 9243405

Please sign in to comment.