From aa01b953d6568c6ae0bd67a7ee6570df14085c05 Mon Sep 17 00:00:00 2001 From: David Feltell Date: Mon, 19 Aug 2024 14:06:21 +0100 Subject: [PATCH] [Core] Use frozenset for Python kTraitSet Closes #55. Define the Python Specifications trait set using a `frozenset` so it can be hashed. Simplifies switching on trait set in manager implementations in Python, where a handler map is a nice way to structure code. I.e. a `frozenset` can be used as a dictionary key. Signed-off-by: David Feltell --- RELEASE_NOTES.md | 7 ++++++- .../templates/python/specifications.py.in | 4 ++-- tests/generators/test_python.py | 16 ++++++++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 9415b0e..5d3d9e9 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -11,7 +11,12 @@ v1.0.0-alpha.x tested or published, whereas Python 3.11 is now published. [OpenAssetIO#1351](https://github.com/OpenAssetIO/OpenAssetIO/issues/1351) -v1.0.0-alpha.9 +- Changed the `kTraitSet` member of Specification classes in Python to + use the `frozenset` type, rather than standard `set`. This allows + the `kTraitSet` to be used as a dictionary key. + [#55](https://github.com/OpenAssetIO/OpenAssetIO-TraitGen/issues/55)` + +`v1.0.0-alpha.9 -------------- ### Breaking Changes diff --git a/python/openassetio_traitgen/templates/python/specifications.py.in b/python/openassetio_traitgen/templates/python/specifications.py.in index 5fac579..b3defba 100644 --- a/python/openassetio_traitgen/templates/python/specifications.py.in +++ b/python/openassetio_traitgen/templates/python/specifications.py.in @@ -31,7 +31,7 @@ class {{ specification.id | to_py_class_name }}Specification: Usage: {{ specification.usage | join(', ') }} {% endif -%} """ - kTraitSet = { + kTraitSet = frozenset({ {% for trait in specification.trait_set -%} # '{{ trait.id }}' {% if trait.package == package.id -%} @@ -40,7 +40,7 @@ class {{ specification.id | to_py_class_name }}Specification: {{ trait.package | to_py_module_name }}.traits.{{ trait.namespace | to_py_module_name }}.{{ trait.name | to_py_class_name }}Trait.kId, {% endif -%} {% endfor %} - } + }) def __init__(self, traitsData): """ diff --git a/tests/generators/test_python.py b/tests/generators/test_python.py index bec9c7a..58f29cd 100644 --- a/tests/generators/test_python.py +++ b/tests/generators/test_python.py @@ -216,6 +216,12 @@ def test_trait_set_composes_target_trait_kIds(self, module_all): } assert module_all.specifications.test.TwoLocalTraitsSpecification.kTraitSet == expected + # Ensure we can use the trait set as a dict key, i.e. it is a + # `frozenset`. + assert {module_all.specifications.test.TwoLocalTraitsSpecification.kTraitSet: True}[ + module_all.specifications.test.TwoLocalTraitsSpecification.kTraitSet + ] is True + def test_has_trait_getters_with_expected_docstring(self, module_all): trait_one = module_all.traits.aNamespace.NoPropertiesTrait trait_two = module_all.traits.anotherNamespace.NoPropertiesTrait @@ -260,6 +266,11 @@ def test_trait_set_composes_target_trait_kIds(self, module_all, module_traits_on module_traits_only.traits.test.AnotherTrait.kId, } assert module_all.specifications.test.OneExternalTraitSpecification.kTraitSet == expected + # Ensure we can use the trait set as a dict key, i.e. it is a + # `frozenset`. + assert {module_all.specifications.test.OneExternalTraitSpecification.kTraitSet: True}[ + module_all.specifications.test.OneExternalTraitSpecification.kTraitSet + ] is True def test_has_trait_getters_with_expected_docstring(self, module_all, module_traits_only): trait = module_traits_only.traits.test.AnotherTrait @@ -294,6 +305,11 @@ def test_trait_set_composes_target_trait_kIds(self, module_all, module_traits_on assert ( module_all.specifications.test.LocalAndExternalTraitSpecification.kTraitSet == expected ) + # Ensure we can use the trait set as a dict key, i.e. it is a + # `frozenset`. + assert {module_all.specifications.test.LocalAndExternalTraitSpecification.kTraitSet: True}[ + module_all.specifications.test.LocalAndExternalTraitSpecification.kTraitSet + ] is True def test_has_trait_getters_with_expected_docstring(self, module_all, module_traits_only): trait_one = module_all.traits.aNamespace.NoPropertiesTrait