rune-runtime 2.2.2__tar.gz → 3.0.0__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 (105) hide show
  1. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/.gitignore +3 -0
  2. {rune_runtime-2.2.2/src/rune_runtime.egg-info → rune_runtime-3.0.0}/PKG-INFO +1 -1
  3. rune_runtime-3.0.0/benchmarks/benchmark_list_references.py +93 -0
  4. rune_runtime-3.0.0/docs/object-identity.md +114 -0
  5. rune_runtime-3.0.0/src/rune/runtime/base_data_class.py +697 -0
  6. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/src/rune/runtime/cow.py +69 -9
  7. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/src/rune/runtime/extensions/cached_json_rune_object_deserializer.py +20 -16
  8. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/src/rune/runtime/metadata.py +176 -71
  9. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/src/rune/runtime/object_builder.py +3 -0
  10. rune_runtime-3.0.0/src/rune/runtime/reference_list.py +199 -0
  11. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/src/rune/runtime/utils.py +74 -26
  12. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/src/rune/runtime/version.py +3 -3
  13. {rune_runtime-2.2.2 → rune_runtime-3.0.0/src/rune_runtime.egg-info}/PKG-INFO +1 -1
  14. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/src/rune_runtime.egg-info/SOURCES.txt +10 -0
  15. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/src/rune_runtime.egg-info/scm_file_list.json +10 -0
  16. rune_runtime-3.0.0/src/rune_runtime.egg-info/scm_version.json +8 -0
  17. rune_runtime-3.0.0/test/bugs/test_choice_serialization.py +94 -0
  18. rune_runtime-3.0.0/test/bugs/test_extra_meta.py +59 -0
  19. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/test_basic_types_with_meta.py +185 -11
  20. rune_runtime-3.0.0/test/test_complex_types_with_meta.py +190 -0
  21. rune_runtime-3.0.0/test/test_cow_metadata.py +246 -0
  22. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/test_keys_and_references.py +194 -2
  23. rune_runtime-3.0.0/test/test_list_cardinality_serialise.py +723 -0
  24. rune_runtime-3.0.0/test/test_number_precision.py +211 -0
  25. rune_runtime-3.0.0/test/test_temporal_copy.py +172 -0
  26. rune_runtime-3.0.0/test/test_top_level_metadata.py +95 -0
  27. rune_runtime-3.0.0/test/test_utils.py +257 -0
  28. rune_runtime-2.2.2/src/rune/runtime/base_data_class.py +0 -455
  29. rune_runtime-2.2.2/src/rune_runtime.egg-info/scm_version.json +0 -8
  30. rune_runtime-2.2.2/test/test_complex_types_with_meta.py +0 -69
  31. rune_runtime-2.2.2/test/test_utils.py +0 -135
  32. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/.github/CODE_OF_CONDUCT.md +0 -0
  33. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/.github/ISSUE_TEMPLATE/Bug_report.md +0 -0
  34. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/.github/ISSUE_TEMPLATE/Feature_request.md +0 -0
  35. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/.github/ISSUE_TEMPLATE/Support_question.md +0 -0
  36. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/.github/ISSUE_TEMPLATE/meeting-minutes.md +0 -0
  37. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/.github/workflows/build-python-package.yml +0 -0
  38. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/.github/workflows/check-license-headers.yml +0 -0
  39. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/.github/workflows/cve-scanning-python.yml +0 -0
  40. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/.github/workflows/license-scanning-python.yml +0 -0
  41. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/.github/workflows/release.yml +0 -0
  42. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/.github/workflows/run-tests.yml +0 -0
  43. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/.pre-commit-config.yaml +0 -0
  44. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/.vscode/settings.json +0 -0
  45. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/CONTRIBUTING.md +0 -0
  46. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/EASYCLA_CHANGEME.md +0 -0
  47. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/LICENSE +0 -0
  48. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/LICENSE.spdx +0 -0
  49. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/MAINTAINERS.md +0 -0
  50. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/NOTICE +0 -0
  51. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/README.md +0 -0
  52. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/build_wheel.sh +0 -0
  53. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/dev_clean_setup.sh +0 -0
  54. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/docs/home.md +0 -0
  55. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/netlify.toml +0 -0
  56. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/pyproject.toml +0 -0
  57. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/renovate.json +0 -0
  58. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/safety-policy.yml +0 -0
  59. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/setup.cfg +0 -0
  60. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/src/license/apply_headers.sh +0 -0
  61. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/src/license/header.txt +0 -0
  62. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/src/rune/runtime/__init__.py +0 -0
  63. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/src/rune/runtime/conditions.py +0 -0
  64. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/src/rune/runtime/extensions/__init__.py +0 -0
  65. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/src/rune/runtime/func_proxy.py +0 -0
  66. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/src/rune/runtime/native_registry.py +0 -0
  67. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/src/rune/runtime/object_registry.py +0 -0
  68. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/src/rune/runtime/py.typed +0 -0
  69. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/src/rune_runtime.egg-info/dependency_links.txt +0 -0
  70. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/src/rune_runtime.egg-info/requires.txt +0 -0
  71. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/src/rune_runtime.egg-info/top_level.txt +0 -0
  72. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/__init__.py +0 -0
  73. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/cdm/EUR-Vanilla-account.json +0 -0
  74. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/cdm/test_create_irs.py +0 -0
  75. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/cdm/test_trade_creation.py +0 -0
  76. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/cdm/test_validation.py +0 -0
  77. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/functions/specs/cdm/_bundle.py +0 -0
  78. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/functions/specs/cdm/base/math/Abs.py +0 -0
  79. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/functions/specs/cdm/base/math/RoundToNearest.py +0 -0
  80. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/functions/specs/cdm/base/math/RoundingModeEnum.py +0 -0
  81. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/functions/specs/test_native_registry.py +0 -0
  82. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/functions/specs/test_simple.py +0 -0
  83. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/local_data/ird-ex01-vanilla-swap-versioned.json +0 -0
  84. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/run_runtime_tests.sh +0 -0
  85. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/serializer-round-trip/test_basic.py +0 -0
  86. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/serializer-round-trip/test_conditions.py +0 -0
  87. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/serializer-round-trip/test_enumtype.py +0 -0
  88. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/serializer-round-trip/test_extension.py +0 -0
  89. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/serializer-round-trip/test_metakey.py +0 -0
  90. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/serializer-round-trip/test_metalocation.py +0 -0
  91. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/serializer-round-trip/test_metascheme.py +0 -0
  92. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/test_cached_json_rune_object_deserializer.py +0 -0
  93. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/test_cow.py +0 -0
  94. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/test_deep_keys_and_references.py +0 -0
  95. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/test_deferred_ref_deserialization.py +0 -0
  96. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/test_func_proxy.py +0 -0
  97. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/test_list_cardinality_with_meta.py +0 -0
  98. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/test_namespace_prefix.py +0 -0
  99. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/test_object_builder.py +0 -0
  100. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/test_operations.py +0 -0
  101. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/test_parametrized_basic_types.py +0 -0
  102. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/test_rune_parent.py +0 -0
  103. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/test_rune_str.py +0 -0
  104. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/test_subtype_identity.py +0 -0
  105. {rune_runtime-2.2.2 → rune_runtime-3.0.0}/test/test_zoned_date_time.py +0 -0
@@ -28,3 +28,6 @@ rune.runtime-*.whl
28
28
  src/rune/runtime/version.py
29
29
  /.coverage
30
30
  src/rune_runtime.egg-info
31
+
32
+ # local scratch files
33
+ /.tmp/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rune-runtime
3
- Version: 2.2.2
3
+ Version: 3.0.0
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
@@ -0,0 +1,93 @@
1
+ # Copyright (c) 2023-2026 CLOUDRISK Limited and FT Advisory LLC
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ '''Compare reference-list overhead using the same models and installed dependencies.
5
+
6
+ Run with the project interpreter. --source selects an extracted revision's src
7
+ directory; omit it to measure the current checkout. Timings exclude model schema
8
+ construction and report the best of --repeat runs independently for each round.
9
+ '''
10
+ import argparse
11
+ import cProfile
12
+ import gc
13
+ import json
14
+ import platform
15
+ import sys
16
+ import timeit
17
+ from pathlib import Path
18
+ from typing import Annotated
19
+
20
+
21
+ def main() -> None:
22
+ '''Measure public read, write and validation operations on large model graphs.'''
23
+ parser = argparse.ArgumentParser(description=__doc__)
24
+ parser.add_argument('--source', type=Path)
25
+ parser.add_argument('--label', default='working-tree')
26
+ parser.add_argument('--size', type=int, default=2000)
27
+ parser.add_argument('--repeat', type=int, default=5)
28
+ parser.add_argument('--rounds', type=int, default=2)
29
+ parser.add_argument('--profile', type=Path)
30
+ args = parser.parse_args()
31
+ source = args.source or Path(__file__).resolve().parents[1] / 'src'
32
+ sys.path.insert(0, str(source.resolve()))
33
+
34
+ import pydantic
35
+ from rune.runtime.base_data_class import BaseDataClass
36
+ from rune.runtime.metadata import BaseReference
37
+
38
+ class Party(BaseDataClass):
39
+ _ALLOWED_METADATA = {'@key', '@key:external'}
40
+ name: str
41
+
42
+ class PlainBook(BaseDataClass):
43
+ parties: Annotated[list[Party], Party.serializer(), Party.validator(('@key:external',))]
44
+ items: Annotated[list[Party], Party.serializer(), Party.validator()]
45
+
46
+ class ReferenceBook(BaseDataClass):
47
+ parties: Annotated[list[Party], Party.serializer(), Party.validator(('@key:external',))]
48
+ items: Annotated[list[Party | BaseReference], Party.serializer(), Party.validator(('@ref:external',))]
49
+ _KEY_REF_CONSTRAINTS = {'items': {'@ref:external'}}
50
+
51
+ data = {
52
+ 'parties': [{'@key:external': f'p{i}', 'name': f'Party {i}'} for i in range(args.size)],
53
+ 'items': [{'name': f'Inline {i}'} for i in range(args.size)],
54
+ }
55
+ cases = [('no-references', PlainBook, data),
56
+ ('reference-capable-inline', ReferenceBook, data),
57
+ ('references', ReferenceBook, data | {
58
+ 'items': [{'@ref:external': f'p{i}'} for i in range(args.size)],
59
+ })]
60
+ result = {'label': args.label, 'python': platform.python_version(),
61
+ 'pydantic': pydantic.__version__, 'source': str(source.resolve()),
62
+ 'size': args.size, 'repeat': args.repeat, 'rounds': args.rounds, 'cases': {}}
63
+ for name, model_type, payload in cases:
64
+ encoded = json.dumps(payload)
65
+ model = model_type.rune_deserialize(encoded, validate_model=False)
66
+ operations = {
67
+ 'read': lambda: model_type.rune_deserialize(encoded, validate_model=False),
68
+ 'write': lambda: model.rune_serialize(validate_model=False),
69
+ 'validate': model.validate_model,
70
+ }
71
+ measurements = {}
72
+ for operation, call in operations.items():
73
+ try:
74
+ call()
75
+ except Exception as error:
76
+ measurements[operation] = {'error': f'{type(error).__name__}: {error}'}
77
+ continue
78
+ timings = []
79
+ for _ in range(args.rounds):
80
+ gc.collect()
81
+ timings.append(min(timeit.repeat(call, number=1, repeat=args.repeat)))
82
+ measurements[operation] = {'seconds': timings}
83
+ if args.profile:
84
+ args.profile.mkdir(parents=True, exist_ok=True)
85
+ profile = cProfile.Profile()
86
+ profile.runcall(call)
87
+ profile.dump_stats(str(args.profile / f'{args.label}-{name}-{operation}.prof'))
88
+ result['cases'][name] = measurements
89
+ print(json.dumps(result, indent=2))
90
+
91
+
92
+ if __name__ == '__main__':
93
+ main()
@@ -0,0 +1,114 @@
1
+ # Object identity and references
2
+
3
+ Rune objects have an identity independently of the keys used to reference them.
4
+ `as-key` requests the identity of its operand. Allocating a missing key records
5
+ that identity; ordinary data writes are governed by ownership and copy-on-write
6
+ (COW) isolation.
7
+
8
+ ## Principles
9
+
10
+ 1. Every object has an identity, even when it has no key.
11
+ 2. Distinct domain objects have distinct identities. For a given key type and
12
+ resolution scope, a key identifies at most one target.
13
+ 3. Keys represent identity. Multiple keys of different types can identify the
14
+ same object.
15
+ 4. Creating a key preserves the object's identity and ordinary data. It records
16
+ an identifier for the existing object.
17
+ 5. `as-key` requests the identity of its operand; it does not create a new target.
18
+ 6. A reference into the caller's graph grants read access and identity access.
19
+ Ordinary data writes require ownership.
20
+
21
+ ## Identity and keys
22
+
23
+ Every object has an identity, including an object with no serialized key. Multiple
24
+ keys can identify the same object, using different key types and resolution
25
+ scopes. Allocating an additional key preserves the object's identity and ordinary
26
+ data.
27
+
28
+ Key uniqueness is evaluated using both the key type and the resolution scope.
29
+ The same key text can occur under different types or in different scopes without
30
+ implying that the targets share an identity.
31
+
32
+ Key allocation can change the object's key metadata and register the key in a
33
+ lookup table. This is intentional identity bookkeeping. A serialized object can
34
+ therefore gain an `@key` without a change to its ordinary fields. Key allocation
35
+ remains subject to the model's metadata permissions; having an identity does not
36
+ make every type eligible for every kind of serialized key.
37
+
38
+ The key identifies the existing target. Creating a key must not construct a
39
+ different target solely to hold that key. A reference to a newly keyed object and
40
+ a reference to an already keyed object have the same identity semantics.
41
+
42
+ ## Key selection for as-key
43
+
44
+ Generated code implements `as-key` with `Reference(target)`. With no explicit key
45
+ or key type, selection follows this order:
46
+
47
+ 1. Use the existing external key, if present.
48
+ 2. Otherwise reuse the existing internal key.
49
+ 3. Otherwise allocate an internal key for the existing target.
50
+
51
+ | Existing keys | Serialized reference | Key allocation |
52
+ | --- | --- | --- |
53
+ | External `p1` | `{"@ref:external": "p1"}` | None |
54
+ | Internal `i1` | `{"@ref": "i1"}` | None |
55
+ | External `p1` and internal `i1` | `{"@ref:external": "p1"}` | None |
56
+ | No external or internal key | `{"@ref": "<allocated key>"}` | Internal key |
57
+
58
+ An explicit `key_type=KeyType.INTERNAL` selects an internal reference even when
59
+ an external key exists. Supplying an explicit key selects that key using the
60
+ constructor's existing key-type rules.
61
+
62
+ Local keys are represented by `@key:scoped`. They require the appropriate
63
+ resolution scope, so automatic selection currently excludes them. Creating a
64
+ scoped reference remains explicit. Automatic selection would need a rule for
65
+ checking the receiving scope.
66
+
67
+ ## Reference edges and key registries
68
+
69
+ A reference occurrence records its key and key type on the receiving field or
70
+ list entry. It exposes the target object without making that target a containment
71
+ child of the receiver. The same target can occur both inline and by reference.
72
+
73
+ The target holds its own key metadata. Key registries map keys to targets and are
74
+ normally reached through the containment parent chain, with separate handling for
75
+ scoped keys. An empty registry does not establish that the target has no key;
76
+ key selection reads the target's metadata.
77
+
78
+ Serialization writes a reference occurrence as its reference key, without
79
+ embedding the target's data. The target's containment graph or external context
80
+ provides the corresponding keyed object for resolution.
81
+
82
+ ## Ownership and COW
83
+
84
+ Allocating an identity key alone does not require COW detachment. It may extend
85
+ the existing target's key metadata and registry while leaving ordinary data
86
+ unchanged. This exception is specific to identity keys and registration; it does
87
+ not grant unrestricted access to other metadata or mutable values.
88
+
89
+ The agreed access rule for generated functions is:
90
+
91
+ > A reference into the caller's graph grants read access and identity access;
92
+ > data writes require ownership.
93
+
94
+ **Enforcing this access rule is follow-up work.** Current reference access can
95
+ expose mutable targets; the external-key selection fix does not generally prevent
96
+ data writes through borrowed references.
97
+
98
+ The follow-up must protect nested objects, mutable collections and mutating
99
+ methods reached through a borrowed reference. Replacing a reference field on an
100
+ owned receiver is distinct from modifying the referenced target. References to
101
+ contained targets within a graph managed by COW must retain the supported
102
+ behavior of editing the detached graph while preserving its internal references.
103
+
104
+ ## Code and regression coverage
105
+
106
+ Key selection and registration are implemented in
107
+ [metadata.py](../src/rune/runtime/metadata.py). COW wrappers are implemented in
108
+ [cow.py](../src/rune/runtime/cow.py).
109
+
110
+ [test_keys_and_references.py](../test/test_keys_and_references.py) includes both
111
+ generated-function reproductions from [issue #73](https://github.com/finos/rune-python-runtime/issues/73),
112
+ along with coverage for existing keys and explicit internal selection.
113
+ [test_list_cardinality_serialise.py](../test/test_list_cardinality_serialise.py)
114
+ covers reference occurrences and the list form of `as-key`.