rune-runtime 2.2.0__tar.gz → 2.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/.github/CODE_OF_CONDUCT.md +4 -0
  2. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/.github/ISSUE_TEMPLATE/Bug_report.md +4 -0
  3. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/.github/ISSUE_TEMPLATE/Feature_request.md +4 -0
  4. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/.github/ISSUE_TEMPLATE/Support_question.md +4 -0
  5. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/.github/ISSUE_TEMPLATE/meeting-minutes.md +4 -0
  6. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/.github/workflows/build-python-package.yml +4 -0
  7. rune_runtime-2.2.2/.github/workflows/check-license-headers.yml +39 -0
  8. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/.github/workflows/cve-scanning-python.yml +4 -0
  9. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/.github/workflows/license-scanning-python.yml +4 -0
  10. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/.github/workflows/release.yml +4 -0
  11. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/.github/workflows/run-tests.yml +8 -0
  12. rune_runtime-2.2.2/.pre-commit-config.yaml +25 -0
  13. {rune_runtime-2.2.0/src/rune_runtime.egg-info → rune_runtime-2.2.2}/PKG-INFO +17 -1
  14. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/README.md +14 -0
  15. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/build_wheel.sh +4 -0
  16. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/dev_clean_setup.sh +6 -0
  17. rune_runtime-2.2.2/netlify.toml +6 -0
  18. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/pyproject.toml +7 -1
  19. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/safety-policy.yml +4 -0
  20. rune_runtime-2.2.2/src/license/apply_headers.sh +6 -0
  21. rune_runtime-2.2.2/src/license/header.txt +2 -0
  22. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/src/rune/runtime/base_data_class.py +26 -8
  23. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/src/rune/runtime/metadata.py +28 -27
  24. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/src/rune/runtime/version.py +3 -3
  25. {rune_runtime-2.2.0 → rune_runtime-2.2.2/src/rune_runtime.egg-info}/PKG-INFO +17 -1
  26. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/src/rune_runtime.egg-info/SOURCES.txt +5 -0
  27. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/src/rune_runtime.egg-info/requires.txt +2 -0
  28. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/src/rune_runtime.egg-info/scm_file_list.json +5 -0
  29. rune_runtime-2.2.2/src/rune_runtime.egg-info/scm_version.json +8 -0
  30. rune_runtime-2.2.2/src/rune_runtime.egg-info/top_level.txt +2 -0
  31. rune_runtime-2.2.2/test/cdm/test_validation.py +46 -0
  32. rune_runtime-2.2.2/test/local_data/ird-ex01-vanilla-swap-versioned.json +307 -0
  33. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/test_basic_types_with_meta.py +1 -1
  34. rune_runtime-2.2.2/test/test_deep_keys_and_references.py +247 -0
  35. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/test_deferred_ref_deserialization.py +30 -3
  36. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/test_keys_and_references.py +57 -3
  37. rune_runtime-2.2.0/netlify.toml +0 -2
  38. rune_runtime-2.2.0/src/rune_runtime.egg-info/scm_version.json +0 -8
  39. rune_runtime-2.2.0/src/rune_runtime.egg-info/top_level.txt +0 -1
  40. rune_runtime-2.2.0/test/cdm/test_validation.py +0 -23
  41. rune_runtime-2.2.0/test/test_deep_keys_and_references.py +0 -124
  42. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/.gitignore +0 -0
  43. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/.vscode/settings.json +0 -0
  44. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/CONTRIBUTING.md +0 -0
  45. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/EASYCLA_CHANGEME.md +0 -0
  46. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/LICENSE +0 -0
  47. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/LICENSE.spdx +0 -0
  48. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/MAINTAINERS.md +0 -0
  49. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/NOTICE +0 -0
  50. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/docs/home.md +0 -0
  51. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/renovate.json +0 -0
  52. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/setup.cfg +0 -0
  53. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/src/rune/runtime/__init__.py +0 -0
  54. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/src/rune/runtime/conditions.py +0 -0
  55. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/src/rune/runtime/cow.py +0 -0
  56. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/src/rune/runtime/extensions/__init__.py +0 -0
  57. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/src/rune/runtime/extensions/cached_json_rune_object_deserializer.py +0 -0
  58. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/src/rune/runtime/func_proxy.py +0 -0
  59. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/src/rune/runtime/native_registry.py +0 -0
  60. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/src/rune/runtime/object_builder.py +0 -0
  61. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/src/rune/runtime/object_registry.py +0 -0
  62. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/src/rune/runtime/py.typed +0 -0
  63. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/src/rune/runtime/utils.py +0 -0
  64. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/src/rune_runtime.egg-info/dependency_links.txt +0 -0
  65. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/__init__.py +0 -0
  66. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/cdm/EUR-Vanilla-account.json +0 -0
  67. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/cdm/test_create_irs.py +0 -0
  68. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/cdm/test_trade_creation.py +0 -0
  69. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/functions/specs/cdm/_bundle.py +0 -0
  70. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/functions/specs/cdm/base/math/Abs.py +0 -0
  71. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/functions/specs/cdm/base/math/RoundToNearest.py +0 -0
  72. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/functions/specs/cdm/base/math/RoundingModeEnum.py +0 -0
  73. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/functions/specs/test_native_registry.py +0 -0
  74. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/functions/specs/test_simple.py +0 -0
  75. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/run_runtime_tests.sh +0 -0
  76. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/serializer-round-trip/test_basic.py +0 -0
  77. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/serializer-round-trip/test_conditions.py +0 -0
  78. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/serializer-round-trip/test_enumtype.py +0 -0
  79. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/serializer-round-trip/test_extension.py +0 -0
  80. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/serializer-round-trip/test_metakey.py +0 -0
  81. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/serializer-round-trip/test_metalocation.py +0 -0
  82. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/serializer-round-trip/test_metascheme.py +0 -0
  83. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/test_cached_json_rune_object_deserializer.py +0 -0
  84. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/test_complex_types_with_meta.py +0 -0
  85. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/test_cow.py +0 -0
  86. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/test_func_proxy.py +0 -0
  87. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/test_list_cardinality_with_meta.py +0 -0
  88. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/test_namespace_prefix.py +0 -0
  89. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/test_object_builder.py +0 -0
  90. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/test_operations.py +0 -0
  91. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/test_parametrized_basic_types.py +0 -0
  92. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/test_rune_parent.py +0 -0
  93. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/test_rune_str.py +0 -0
  94. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/test_subtype_identity.py +0 -0
  95. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/test_utils.py +0 -0
  96. {rune_runtime-2.2.0 → rune_runtime-2.2.2}/test/test_zoned_date_time.py +0 -0
@@ -1,3 +1,7 @@
1
+ <!--
2
+ Copyright (c) 2023-2026 CLOUDRISK Limited and FT Advisory LLC
3
+ SPDX-License-Identifier: Apache-2.0
4
+ -->
1
5
  # Code of Conduct for {project name}
2
6
 
3
7
  Please see the [Community Code of Conduct](https://www.finos.org/code-of-conduct).
@@ -1,3 +1,7 @@
1
+ <!--
2
+ Copyright (c) 2023-2026 CLOUDRISK Limited and FT Advisory LLC
3
+ SPDX-License-Identifier: Apache-2.0
4
+ -->
1
5
  ---
2
6
  name: 🐛 Bug Report
3
7
  about: If something isn't working as expected 🤔.
@@ -1,3 +1,7 @@
1
+ <!--
2
+ Copyright (c) 2023-2026 CLOUDRISK Limited and FT Advisory LLC
3
+ SPDX-License-Identifier: Apache-2.0
4
+ -->
1
5
  ---
2
6
  name: 🚀 Feature Request
3
7
  about: I have a suggestion (and may want to implement it 🙂)!
@@ -1,3 +1,7 @@
1
+ <!--
2
+ Copyright (c) 2023-2026 CLOUDRISK Limited and FT Advisory LLC
3
+ SPDX-License-Identifier: Apache-2.0
4
+ -->
1
5
  ---
2
6
  name: 🤗 Support Question
3
7
  about: If you have a question about configuration, usage, etc. 💬
@@ -1,3 +1,7 @@
1
+ <!--
2
+ Copyright (c) 2023-2026 CLOUDRISK Limited and FT Advisory LLC
3
+ SPDX-License-Identifier: Apache-2.0
4
+ -->
1
5
  ---
2
6
  name: "\U0001F91D {project name} Meeting Minutes"
3
7
  about: To track {project name} meeting agenda and attendance
@@ -1,3 +1,7 @@
1
+ ##
2
+ ## Copyright (c) 2023-2026 CLOUDRISK Limited and FT Advisory LLC
3
+ ## SPDX-License-Identifier: Apache-2.0
4
+ ##
1
5
  name: Build and Release Wheel
2
6
 
3
7
  on:
@@ -0,0 +1,39 @@
1
+ ##
2
+ ## Copyright (c) 2023-2026 CLOUDRISK Limited and FT Advisory LLC
3
+ ## SPDX-License-Identifier: Apache-2.0
4
+ ##
5
+ name: Check License Headers
6
+
7
+ on:
8
+ push:
9
+ branches:
10
+ - main
11
+ - develop
12
+ pull_request:
13
+ branches:
14
+ - main
15
+ - develop
16
+
17
+ jobs:
18
+ license-headers:
19
+ name: Verify license headers
20
+ runs-on: ubuntu-latest
21
+
22
+ steps:
23
+ - name: Checkout repository
24
+ uses: actions/checkout@v4
25
+
26
+ - name: Set up Python 3.11
27
+ uses: actions/setup-python@v5
28
+ with:
29
+ python-version: '3.11'
30
+
31
+ - name: Install licenseheaders
32
+ run: pip install licenseheaders
33
+
34
+ - name: Check license headers
35
+ run: |
36
+ src/license/apply_headers.sh
37
+ git diff --exit-code || \
38
+ (echo "One or more files are missing a license header. Run 'src/license/apply_headers.sh' locally to fix." && \
39
+ exit 1)
@@ -1,3 +1,7 @@
1
+ ##
2
+ ## Copyright (c) 2023-2026 CLOUDRISK Limited and FT Advisory LLC
3
+ ## SPDX-License-Identifier: Apache-2.0
4
+ ##
1
5
  name: CVE Scanning for Python
2
6
 
3
7
  on:
@@ -1,3 +1,7 @@
1
+ ##
2
+ ## Copyright (c) 2023-2026 CLOUDRISK Limited and FT Advisory LLC
3
+ ## SPDX-License-Identifier: Apache-2.0
4
+ ##
1
5
  name: License Scanning for Python
2
6
 
3
7
  on:
@@ -1,3 +1,7 @@
1
+ ##
2
+ ## Copyright (c) 2023-2026 CLOUDRISK Limited and FT Advisory LLC
3
+ ## SPDX-License-Identifier: Apache-2.0
4
+ ##
1
5
  name: Publish to PyPi
2
6
 
3
7
  on:
@@ -1,3 +1,7 @@
1
+ ##
2
+ ## Copyright (c) 2023-2026 CLOUDRISK Limited and FT Advisory LLC
3
+ ## SPDX-License-Identifier: Apache-2.0
4
+ ##
1
5
  name: Run Unit Tests
2
6
 
3
7
  on:
@@ -5,6 +9,10 @@ on:
5
9
  branches:
6
10
  - main
7
11
  - develop
12
+ pull_request:
13
+ branches:
14
+ - main
15
+ - develop
8
16
 
9
17
  jobs:
10
18
  test:
@@ -0,0 +1,25 @@
1
+ ##
2
+ ## Copyright (c) 2023-2026 CLOUDRISK Limited and FT Advisory LLC
3
+ ## SPDX-License-Identifier: Apache-2.0
4
+ ##
5
+ repos:
6
+ - repo: local
7
+ hooks:
8
+ - id: license-headers-dirs
9
+ name: Add/check license headers (src, test, .github)
10
+ entry: licenseheaders
11
+ args: [-t, src/license/header.txt, --dir, src, --dir, test, --dir, .github]
12
+ language: python
13
+ additional_dependencies: [licenseheaders>=0.8.8]
14
+ types_or: [python, yaml, shell, toml]
15
+ pass_filenames: false
16
+ - id: license-headers-files
17
+ name: Add/check license headers (root files)
18
+ entry: licenseheaders
19
+ args: [-t, src/license/header.txt, --additional-extensions, python=.toml,
20
+ -f, build_wheel.sh, dev_clean_setup.sh, netlify.toml, pyproject.toml,
21
+ safety-policy.yml, .pre-commit-config.yaml]
22
+ language: python
23
+ additional_dependencies: [licenseheaders>=0.8.8]
24
+ types_or: [python, yaml, shell, toml]
25
+ pass_filenames: false
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rune-runtime
3
- Version: 2.2.0
3
+ Version: 2.2.2
4
4
  Summary: rune-runtime: the Rune DSL runtime for Python
5
5
  Author: Daniel Schwartz, Plamen Neykov, Others (See AUTHORS)
6
6
  License-Expression: Apache-2.0
@@ -30,6 +30,8 @@ Requires-Dist: pytest>=9.0.2; extra == "dev"
30
30
  Requires-Dist: pytest-cov>=7.0.0; extra == "dev"
31
31
  Requires-Dist: pytest-mock>=3.14.1; extra == "dev"
32
32
  Requires-Dist: types-python-dateutil>=2.9.0.20250809; extra == "dev"
33
+ Requires-Dist: licenseheaders>=0.8.8; extra == "dev"
34
+ Requires-Dist: pre-commit>=3.0.0; extra == "dev"
33
35
  Dynamic: license-file
34
36
 
35
37
  [![FINOS - Incubating](https://cdn.jsdelivr.net/gh/finos/contrib-toolbox@master/images/badge-incubating.svg)](https://community.finos.org/docs/governance/Software-Projects/stages/incubating)
@@ -59,6 +61,20 @@ Use [dev_clean_setup.sh](https://github.com/Cloudrisk/rune-python-runtime/blob/m
59
61
  ```sh
60
62
  ./dev_clean_setup.sh
61
63
  ```
64
+
65
+ This script installs all dev dependencies and registers the pre-commit hooks, including the license-header check. Every `.py` file under `src/` and `test/` must carry the Apache 2.0 SPDX header:
66
+
67
+ ```python
68
+ # Copyright (c) 2023-2026 CLOUDRISK Limited and FT Advisory LLC
69
+ # SPDX-License-Identifier: Apache-2.0
70
+ ```
71
+
72
+ To add missing headers to all files at any time, run:
73
+
74
+ ```sh
75
+ src/license/apply_headers.sh
76
+ ```
77
+
62
78
  ### 3. Build
63
79
  Use [build_wheel.sh](https://github.com/Cloudrisk/rune-python-runtime/blob/main/build_wheel.sh) to build the package
64
80
  ```sh
@@ -25,6 +25,20 @@ Use [dev_clean_setup.sh](https://github.com/Cloudrisk/rune-python-runtime/blob/m
25
25
  ```sh
26
26
  ./dev_clean_setup.sh
27
27
  ```
28
+
29
+ This script installs all dev dependencies and registers the pre-commit hooks, including the license-header check. Every `.py` file under `src/` and `test/` must carry the Apache 2.0 SPDX header:
30
+
31
+ ```python
32
+ # Copyright (c) 2023-2026 CLOUDRISK Limited and FT Advisory LLC
33
+ # SPDX-License-Identifier: Apache-2.0
34
+ ```
35
+
36
+ To add missing headers to all files at any time, run:
37
+
38
+ ```sh
39
+ src/license/apply_headers.sh
40
+ ```
41
+
28
42
  ### 3. Build
29
43
  Use [build_wheel.sh](https://github.com/Cloudrisk/rune-python-runtime/blob/main/build_wheel.sh) to build the package
30
44
  ```sh
@@ -1,4 +1,8 @@
1
1
  #!/bin/bash
2
+ ##
3
+ ## Copyright (c) 2023-2026 CLOUDRISK Limited and FT Advisory LLC
4
+ ## SPDX-License-Identifier: Apache-2.0
5
+ ##
2
6
 
3
7
  function error
4
8
  {
@@ -1,4 +1,8 @@
1
1
  #!/bin/bash
2
+ ##
3
+ ## Copyright (c) 2023-2026 CLOUDRISK Limited and FT Advisory LLC
4
+ ## SPDX-License-Identifier: Apache-2.0
5
+ ##
2
6
 
3
7
  function error
4
8
  {
@@ -34,3 +38,5 @@ ${PY_EXE} -m venv --clear .pydevenv || error
34
38
 
35
39
 
36
40
  python -m pip install -e .[dev] --config-settings editable_mode=compat || error
41
+
42
+ pre-commit install || error
@@ -0,0 +1,6 @@
1
+ #
2
+ # Copyright (c) 2023-2026 CLOUDRISK Limited and FT Advisory LLC
3
+ # SPDX-License-Identifier: Apache-2.0
4
+ #
5
+ [build]
6
+ ignore = "/bin/false"
@@ -1,3 +1,7 @@
1
+ #
2
+ # Copyright (c) 2023-2026 CLOUDRISK Limited and FT Advisory LLC
3
+ # SPDX-License-Identifier: Apache-2.0
4
+ #
1
5
  [build-system]
2
6
  requires = ["setuptools>=64", "setuptools_scm>=8", "wheel>=0.45.1", "pytest-runner>=6.0.1"]
3
7
  build-backend = "setuptools.build_meta"
@@ -15,7 +19,9 @@ optional-dependencies.dev = [
15
19
  "pytest>=9.0.2",
16
20
  "pytest-cov>=7.0.0",
17
21
  "pytest-mock>=3.14.1",
18
- "types-python-dateutil>=2.9.0.20250809"
22
+ "types-python-dateutil>=2.9.0.20250809",
23
+ "licenseheaders>=0.8.8",
24
+ "pre-commit>=3.0.0"
19
25
  ]
20
26
  description = "rune-runtime: the Rune DSL runtime for Python"
21
27
  readme = "README.md"
@@ -1,3 +1,7 @@
1
+ ##
2
+ ## Copyright (c) 2023-2026 CLOUDRISK Limited and FT Advisory LLC
3
+ ## SPDX-License-Identifier: Apache-2.0
4
+ ##
1
5
  security:
2
6
  ignore-cvss-severity-below: 6
3
7
  ignore-cvss-unknown-severity: False
@@ -0,0 +1,6 @@
1
+ #!/bin/bash
2
+ # Applies the Apache 2.0 SPDX license header to all tracked source files.
3
+ set -e
4
+ TMPL="$(dirname "$0")/header.txt"
5
+ licenseheaders -t "$TMPL" --dir src --dir test --dir .github
6
+ licenseheaders -t "$TMPL" --additional-extensions python=.toml -f build_wheel.sh dev_clean_setup.sh netlify.toml pyproject.toml safety-policy.yml .pre-commit-config.yaml
@@ -0,0 +1,2 @@
1
+ Copyright (c) 2023-2026 CLOUDRISK Limited and FT Advisory LLC
2
+ SPDX-License-Identifier: Apache-2.0
@@ -107,7 +107,7 @@ class BaseDataClass(BaseModel, ComplexTypeMetaDataMixin):
107
107
  @model_serializer(mode='wrap')
108
108
  def _serialize_refs(self, serializer, info):
109
109
  '''should replace objects with refs while serializing'''
110
- res = serializer(self, info)
110
+ res = serializer(self)
111
111
  refs = self._get_rune_refs_container()
112
112
  for property_nm, (key, ref_type) in refs.items():
113
113
  res[property_nm] = {ref_type.rune_ref_tag: key}
@@ -125,6 +125,15 @@ class BaseDataClass(BaseModel, ComplexTypeMetaDataMixin):
125
125
  return aux
126
126
  obj = handler(data)
127
127
  obj._init_rune_parent() # pylint: disable=protected-access
128
+ if isinstance(data, dict):
129
+ # Deferred annotations can bypass the field metadata validator.
130
+ # Retain target keys before resolving references to this model.
131
+ keys = {k: v for k, v in metadata.items() if k.startswith('@key')}
132
+ if keys:
133
+ # Field-level validators handle allowed metadata, including
134
+ # scoped keys that are not declared on the target class.
135
+ obj.set_meta(check_allowed=False, **keys)
136
+ obj._register_keys(keys) # pylint: disable=protected-access
128
137
  obj.resolve_references(ignore_dangling=True, recurse=False)
129
138
  # transfer refs that were established on the original before
130
139
  # re-validation wiped them
@@ -140,9 +149,12 @@ class BaseDataClass(BaseModel, ComplexTypeMetaDataMixin):
140
149
  self.__dict__[RUNE_OBJ_MAPS] = {}
141
150
 
142
151
  for prop_nm, obj in self.__dict__.items():
143
- if (isinstance(obj, BaseMetaDataMixin)
144
- and not prop_nm.startswith('__') and prop_nm not in refs):
145
- obj._set_rune_parent(self) # pylint: disable=protected-access
152
+ if prop_nm.startswith('__') or prop_nm in refs:
153
+ continue
154
+ children = obj if isinstance(obj, (MutableSequence, tuple)) else (obj,)
155
+ for child in children:
156
+ if isinstance(child, BaseMetaDataMixin):
157
+ child._set_rune_parent(self) # pylint: disable=protected-access
146
158
 
147
159
  def rune_serialize(
148
160
  self,
@@ -306,11 +318,17 @@ class BaseDataClass(BaseModel, ComplexTypeMetaDataMixin):
306
318
  def resolve_references(self, ignore_dangling=False, recurse=True):
307
319
  '''resolves all attributes which are references'''
308
320
  if recurse:
321
+ resolved_refs = self._get_rune_refs_container()
309
322
  for prop_nm, obj in self.__dict__.items():
310
- if (isinstance(obj, BaseDataClass)
311
- and not prop_nm.startswith('__')):
312
- obj.resolve_references(ignore_dangling=ignore_dangling,
313
- recurse=recurse)
323
+ # Follow containment only; resolved references can point back
324
+ # to an ancestor and must not be traversed again.
325
+ if prop_nm.startswith('__') or prop_nm in resolved_refs:
326
+ continue
327
+ children = obj if isinstance(obj, (MutableSequence, tuple)) else (obj,)
328
+ for child in children:
329
+ if isinstance(child, BaseDataClass):
330
+ child.resolve_references(ignore_dangling=ignore_dangling,
331
+ recurse=recurse)
314
332
 
315
333
  refs = []
316
334
  for prop_nm, obj in self.__dict__.items():
@@ -1,15 +1,16 @@
1
1
  '''Classes representing annotated basic Rune types'''
2
- import uuid
3
2
  import datetime
4
3
  import importlib
5
- from enum import Enum
6
- from functools import partial, lru_cache
4
+ import uuid
5
+ from collections.abc import Iterable
7
6
  from decimal import Decimal
8
- from typing import Any, Never, get_args, Iterable
9
- from typing_extensions import Self, Tuple
10
- from pydantic import (PlainSerializer, PlainValidator, WrapValidator,
11
- WrapSerializer)
7
+ from enum import Enum
8
+ from functools import lru_cache, partial
9
+ from typing import Any, Never, Self, get_args
10
+
11
+ from pydantic import PlainSerializer, PlainValidator, WrapSerializer, WrapValidator
12
12
  from pydantic_core import PydanticCustomError
13
+
13
14
  # from rune.runtime.object_registry import get_object
14
15
 
15
16
  DEFAULT_META = '_ALLOWED_METADATA'
@@ -135,7 +136,7 @@ class Reference(BaseReference):
135
136
  class UnresolvedReference(BaseReference):
136
137
  '''used by the deserialization to hold temporarily unresolved references'''
137
138
  def __init__(self, key):
138
- rune_type, self.key = list(key.items())[0]
139
+ rune_type, self.key = next(iter(key.items()))
139
140
  self.key_type = KeyType.from_rune(rune_type)
140
141
 
141
142
  def get_reference(self, parent):
@@ -219,7 +220,7 @@ class BaseMetaDataMixin:
219
220
  self.set_meta(key=key)
220
221
  try:
221
222
  self._get_object_map(KeyType.INTERNAL)[key] = self
222
- except: # noqa
223
+ except:
223
224
  self.set_meta(key=None)
224
225
  raise
225
226
  return key
@@ -238,7 +239,7 @@ class BaseMetaDataMixin:
238
239
  self.set_meta(check_allowed=True, **{key_type.key_tag: key})
239
240
  try:
240
241
  self._get_object_map(key_type)[key] = self
241
- except: # noqa
242
+ except:
242
243
  self.set_meta(check_allowed=True, **{key_type.key_tag: None})
243
244
  raise
244
245
  return self
@@ -298,13 +299,14 @@ class BaseMetaDataMixin:
298
299
  f'not allowed for {property_nm}. Allowed types '
299
300
  f'are: {allowed_ref_types.get(property_nm, {})}')
300
301
 
301
- field_type = self.__class__.__annotations__.get(property_nm)
302
+ # Pydantic includes inherited fields and resolves their annotations.
303
+ field_type = type(self).model_fields[property_nm].annotation # type: ignore
302
304
  allowed_type = _get_basic_type(field_type)
303
305
  if not (isinstance(allowed_type, str)
304
306
  or isinstance(ref.target, allowed_type)):
305
- raise ValueError("Can't set reference. Incompatible types: "
306
- f"expected {allowed_type}, "
307
- f"got {ref.target.__class__}")
307
+ raise TypeError("Can't set reference. Incompatible types: "
308
+ f"expected {allowed_type}, "
309
+ f"got {ref.target.__class__}")
308
310
 
309
311
  refs = self.__dict__.setdefault(REFS_CONTAINER, {})
310
312
  if property_nm not in refs:
@@ -416,9 +418,8 @@ class ComplexTypeMetaDataMixin(BaseMetaDataMixin):
416
418
  prefix = namespace_prefix
417
419
  if prefix is None:
418
420
  prefix = cls._get_rune_namespace_prefix()
419
- if prefix:
420
- if not rune_type.startswith(prefix + '.'):
421
- import_path = prefix + '.' + rune_type
421
+ if prefix and not rune_type.startswith(prefix + '.'):
422
+ import_path = prefix + '.' + rune_type
422
423
  rune_module = importlib.import_module(import_path)
423
424
  return getattr(rune_module, rune_class_name)
424
425
  return cls # support for legacy json
@@ -453,14 +454,14 @@ class ComplexTypeMetaDataMixin(BaseMetaDataMixin):
453
454
  'Expected either {my_type} or dict but '
454
455
  'got {type}.',
455
456
  {'type': type(obj), 'my_type': cls})
456
- metadata = {k: obj[k] for k in obj.keys() if k.startswith('@')}
457
+ metadata = {k: obj[k] for k in obj if k.startswith('@')}
457
458
 
458
459
  # References deserialization treatment
459
460
  if aux := cls._create_unresolved_ref(metadata):
460
461
  return aux
461
462
 
462
463
  # Model creation
463
- for k in metadata.keys():
464
+ for k in metadata:
464
465
  obj.pop(k)
465
466
 
466
467
  rune_cls = cls._type_to_cls(metadata)
@@ -483,7 +484,7 @@ class ComplexTypeMetaDataMixin(BaseMetaDataMixin):
483
484
 
484
485
  @classmethod
485
486
  @lru_cache
486
- def validator(cls, allowed_meta: tuple[str] | tuple[Never, ...] = tuple()):
487
+ def validator(cls, allowed_meta: tuple[str] | tuple[Never, ...] = ()):
487
488
  '''default validator for the specific class'''
488
489
  allowed = set(allowed_meta)
489
490
  return PlainValidator(partial(cls.deserialize, allowed_meta=allowed),
@@ -492,16 +493,16 @@ class ComplexTypeMetaDataMixin(BaseMetaDataMixin):
492
493
 
493
494
  class BasicTypeMetaDataMixin(BaseMetaDataMixin):
494
495
  '''holds the metadata associated with an instance'''
495
- _INPUT_TYPES: Any | Tuple[Any, ...] = str # to be overridden by subclasses
496
+ _INPUT_TYPES: Any | tuple[Any, ...] = str # to be overridden by subclasses
496
497
  _OUTPUT_TYPE: Any = str # to be overridden by subclasses
497
498
  _JSON_OUTPUT = str | dict
498
499
 
499
500
  @classmethod
500
501
  def _check_type(cls, value):
501
502
  if not isinstance(value, cls._INPUT_TYPES):
502
- raise ValueError(f'{cls.__name__} can be instantiated only with '
503
- f'one of the following type(s): {cls._INPUT_TYPES},'
504
- f' however the value is of type {type(value)}')
503
+ raise TypeError(f'{cls.__name__} can be instantiated only with '
504
+ f'one of the following type(s): {cls._INPUT_TYPES},'
505
+ f' however the value is of type {type(value)}')
505
506
 
506
507
  @classmethod
507
508
  def serialise(cls, obj, base_type) -> dict:
@@ -514,7 +515,7 @@ class BasicTypeMetaDataMixin(BaseMetaDataMixin):
514
515
  def deserialize(cls, obj, handler, base_types, allowed_meta: set[str]):
515
516
  '''method used as pydantic `validator`'''
516
517
  if isinstance(obj, list):
517
- identity = lambda x: x # noqa: E731
518
+ identity = lambda x: x
518
519
  processed = [cls.deserialize(item, identity, base_types, allowed_meta) for item in obj]
519
520
  return handler(processed)
520
521
  model = obj
@@ -649,7 +650,7 @@ class _EnumWrapper(BaseMetaDataMixin):
649
650
  '''wrapper for enums with metadata'''
650
651
  def __init__(self, enum_instance=_EnumWrapperDefaultVal.NOT_SET):
651
652
  if not isinstance(enum_instance, Enum):
652
- raise ValueError("enum_instance must be an instance of an Enum")
653
+ raise TypeError("enum_instance must be an instance of an Enum")
653
654
  self._enum_instance = enum_instance
654
655
 
655
656
  @property
@@ -723,7 +724,7 @@ class EnumWithMetaMixin:
723
724
 
724
725
  @classmethod
725
726
  @lru_cache
726
- def validator(cls, allowed_meta: tuple[str] | tuple[Never, ...] = tuple()):
727
+ def validator(cls, allowed_meta: tuple[str] | tuple[Never, ...] = ()):
727
728
  '''default validator for the specific class'''
728
729
  allowed = set(allowed_meta)
729
730
  return PlainValidator(partial(cls.deserialize, allowed_meta=allowed),
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '2.2.0'
22
- __version_tuple__ = version_tuple = (2, 2, 0)
21
+ __version__ = version = '2.2.2'
22
+ __version_tuple__ = version_tuple = (2, 2, 2)
23
23
 
24
- __commit_id__ = commit_id = 'g58791175d'
24
+ __commit_id__ = commit_id = 'g951f0332c'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rune-runtime
3
- Version: 2.2.0
3
+ Version: 2.2.2
4
4
  Summary: rune-runtime: the Rune DSL runtime for Python
5
5
  Author: Daniel Schwartz, Plamen Neykov, Others (See AUTHORS)
6
6
  License-Expression: Apache-2.0
@@ -30,6 +30,8 @@ Requires-Dist: pytest>=9.0.2; extra == "dev"
30
30
  Requires-Dist: pytest-cov>=7.0.0; extra == "dev"
31
31
  Requires-Dist: pytest-mock>=3.14.1; extra == "dev"
32
32
  Requires-Dist: types-python-dateutil>=2.9.0.20250809; extra == "dev"
33
+ Requires-Dist: licenseheaders>=0.8.8; extra == "dev"
34
+ Requires-Dist: pre-commit>=3.0.0; extra == "dev"
33
35
  Dynamic: license-file
34
36
 
35
37
  [![FINOS - Incubating](https://cdn.jsdelivr.net/gh/finos/contrib-toolbox@master/images/badge-incubating.svg)](https://community.finos.org/docs/governance/Software-Projects/stages/incubating)
@@ -59,6 +61,20 @@ Use [dev_clean_setup.sh](https://github.com/Cloudrisk/rune-python-runtime/blob/m
59
61
  ```sh
60
62
  ./dev_clean_setup.sh
61
63
  ```
64
+
65
+ This script installs all dev dependencies and registers the pre-commit hooks, including the license-header check. Every `.py` file under `src/` and `test/` must carry the Apache 2.0 SPDX header:
66
+
67
+ ```python
68
+ # Copyright (c) 2023-2026 CLOUDRISK Limited and FT Advisory LLC
69
+ # SPDX-License-Identifier: Apache-2.0
70
+ ```
71
+
72
+ To add missing headers to all files at any time, run:
73
+
74
+ ```sh
75
+ src/license/apply_headers.sh
76
+ ```
77
+
62
78
  ### 3. Build
63
79
  Use [build_wheel.sh](https://github.com/Cloudrisk/rune-python-runtime/blob/main/build_wheel.sh) to build the package
64
80
  ```sh
@@ -1,4 +1,5 @@
1
1
  .gitignore
2
+ .pre-commit-config.yaml
2
3
  CONTRIBUTING.md
3
4
  EASYCLA_CHANGEME.md
4
5
  LICENSE
@@ -18,12 +19,15 @@ safety-policy.yml
18
19
  .github/ISSUE_TEMPLATE/Support_question.md
19
20
  .github/ISSUE_TEMPLATE/meeting-minutes.md
20
21
  .github/workflows/build-python-package.yml
22
+ .github/workflows/check-license-headers.yml
21
23
  .github/workflows/cve-scanning-python.yml
22
24
  .github/workflows/license-scanning-python.yml
23
25
  .github/workflows/release.yml
24
26
  .github/workflows/run-tests.yml
25
27
  .vscode/settings.json
26
28
  docs/home.md
29
+ src/license/apply_headers.sh
30
+ src/license/header.txt
27
31
  src/rune/runtime/__init__.py
28
32
  src/rune/runtime/base_data_class.py
29
33
  src/rune/runtime/conditions.py
@@ -75,6 +79,7 @@ test/functions/specs/cdm/_bundle.py
75
79
  test/functions/specs/cdm/base/math/Abs.py
76
80
  test/functions/specs/cdm/base/math/RoundToNearest.py
77
81
  test/functions/specs/cdm/base/math/RoundingModeEnum.py
82
+ test/local_data/ird-ex01-vanilla-swap-versioned.json
78
83
  test/serializer-round-trip/test_basic.py
79
84
  test/serializer-round-trip/test_conditions.py
80
85
  test/serializer-round-trip/test_enumtype.py
@@ -7,3 +7,5 @@ pytest>=9.0.2
7
7
  pytest-cov>=7.0.0
8
8
  pytest-mock>=3.14.1
9
9
  types-python-dateutil>=2.9.0.20250809
10
+ licenseheaders>=0.8.8
11
+ pre-commit>=3.0.0
@@ -6,11 +6,13 @@
6
6
  ".github/ISSUE_TEMPLATE/Support_question.md",
7
7
  ".github/ISSUE_TEMPLATE/meeting-minutes.md",
8
8
  ".github/workflows/build-python-package.yml",
9
+ ".github/workflows/check-license-headers.yml",
9
10
  ".github/workflows/cve-scanning-python.yml",
10
11
  ".github/workflows/license-scanning-python.yml",
11
12
  ".github/workflows/release.yml",
12
13
  ".github/workflows/run-tests.yml",
13
14
  ".gitignore",
15
+ ".pre-commit-config.yaml",
14
16
  ".vscode/settings.json",
15
17
  "CONTRIBUTING.md",
16
18
  "EASYCLA_CHANGEME.md",
@@ -26,6 +28,8 @@
26
28
  "pyproject.toml",
27
29
  "renovate.json",
28
30
  "safety-policy.yml",
31
+ "src/license/apply_headers.sh",
32
+ "src/license/header.txt",
29
33
  "src/rune/runtime/__init__.py",
30
34
  "src/rune/runtime/base_data_class.py",
31
35
  "src/rune/runtime/conditions.py",
@@ -50,6 +54,7 @@
50
54
  "test/functions/specs/cdm/base/math/RoundingModeEnum.py",
51
55
  "test/functions/specs/test_native_registry.py",
52
56
  "test/functions/specs/test_simple.py",
57
+ "test/local_data/ird-ex01-vanilla-swap-versioned.json",
53
58
  "test/run_runtime_tests.sh",
54
59
  "test/serializer-round-trip/test_basic.py",
55
60
  "test/serializer-round-trip/test_conditions.py",
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "2.2.2",
3
+ "distance": 0,
4
+ "node": "g951f0332ce7c55a8a5e4d1b6bf932f809d83c5be",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-10-15"
8
+ }
@@ -0,0 +1,2 @@
1
+ license
2
+ rune