From 0ed74b5078a53c450ffc59bdade604ced902c36c Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Thu, 4 Jul 2024 04:58:07 +0800 Subject: [PATCH 1/3] feat: Add support for instantiating union types The code changes in `quam_instantiation.py` and `test_instantiation.py` introduce support for instantiating union types. This allows the `instantiate_attr` function to handle union types correctly when creating instances of classes. The changes include importing the `types` module and checking for `types.UnionType` in addition to `typing.Union` when determining if a type is a union type. This commit message follows the established convention of using a prefix to indicate the type of change (`feat` for feature). --- quam/core/quam_instantiation.py | 3 ++- tests/instantiation/test_instantiation.py | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/quam/core/quam_instantiation.py b/quam/core/quam_instantiation.py index 57680cf4..eee55f36 100644 --- a/quam/core/quam_instantiation.py +++ b/quam/core/quam_instantiation.py @@ -1,4 +1,5 @@ from __future__ import annotations +import types import typing from typing import TYPE_CHECKING, Dict, Any from inspect import isclass @@ -224,7 +225,7 @@ def instantiate_attr( ) if typing.get_origin(expected_type) == dict: expected_type = dict - elif typing.get_origin(expected_type) == typing.Union: + elif typing.get_origin(expected_type) in [typing.Union, types.UnionType]: for union_type in typing.get_args(expected_type): try: instantiated_attr = instantiate_attr( diff --git a/tests/instantiation/test_instantiation.py b/tests/instantiation/test_instantiation.py index 7aa293ff..eca643cb 100644 --- a/tests/instantiation/test_instantiation.py +++ b/tests/instantiation/test_instantiation.py @@ -357,3 +357,18 @@ class TestQuamUnion(QuamComponent): with pytest.raises(TypeError): instantiate_quam_class(TestQuamUnion, {"union_val": {"a": "42"}}) + + +def test_instantiation_pipe_union_type(): + @quam_dataclass + class TestQuamUnion(QuamComponent): + union_val: int | TestQuamComponent + + obj = instantiate_quam_class(TestQuamUnion, {"union_val": 42}) + assert obj.union_val == 42 + + obj = instantiate_quam_class(TestQuamUnion, {"union_val": {"a": 42}}) + assert obj.union_val.a == 42 + + with pytest.raises(TypeError): + instantiate_quam_class(TestQuamUnion, {"union_val": {"a": "42"}}) \ No newline at end of file From 075416de2669e829a5fd52f2b2754d1f9400ce89 Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Thu, 4 Jul 2024 05:02:07 +0800 Subject: [PATCH 2/3] add conditional to test --- CHANGELOG.md | 4 ++++ tests/instantiation/test_instantiation.py | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99f46e16..c873f676 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ ### Changed - Allow `QuamBase.get_reference(attr)` to return a reference of one of its attributes +### Fixed +- Fix quam object instantiation error when a parameter type uses pipe operator + + ## [0.3.3] ### Added - Added the following parameters to `IQChannel`: `RF_frequency`, `LO_frequency`, `intermediate_frequency` diff --git a/tests/instantiation/test_instantiation.py b/tests/instantiation/test_instantiation.py index eca643cb..f6c0da63 100644 --- a/tests/instantiation/test_instantiation.py +++ b/tests/instantiation/test_instantiation.py @@ -1,6 +1,8 @@ import pytest from typing import List, Literal, Optional, Tuple, Union +from pytest_cov.engine import sys + from quam.core import QuamRoot, QuamComponent, quam_dataclass from quam.core.quam_classes import QuamDict from quam.examples.superconducting_qubits.components import Transmon @@ -339,6 +341,7 @@ def test_instantiate_dict_referenced(): assert attrs == {"test_attr": "#./reference"} + @quam_dataclass class TestQuamComponent(QuamComponent): a: int @@ -359,6 +362,7 @@ class TestQuamUnion(QuamComponent): instantiate_quam_class(TestQuamUnion, {"union_val": {"a": "42"}}) +@pytest.mark.skipif(sys.version_info < (3, 10), reason="requires python3.10 or higher") def test_instantiation_pipe_union_type(): @quam_dataclass class TestQuamUnion(QuamComponent): @@ -371,4 +375,4 @@ class TestQuamUnion(QuamComponent): assert obj.union_val.a == 42 with pytest.raises(TypeError): - instantiate_quam_class(TestQuamUnion, {"union_val": {"a": "42"}}) \ No newline at end of file + instantiate_quam_class(TestQuamUnion, {"union_val": {"a": "42"}}) From 099359e0f2827a56d21498405323eb46e1505050 Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Thu, 4 Jul 2024 06:26:37 +0800 Subject: [PATCH 3/3] remove types.uniontype for python < 3.10 --- quam/core/quam_instantiation.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/quam/core/quam_instantiation.py b/quam/core/quam_instantiation.py index eee55f36..e1bd0720 100644 --- a/quam/core/quam_instantiation.py +++ b/quam/core/quam_instantiation.py @@ -1,4 +1,5 @@ from __future__ import annotations +import sys import types import typing from typing import TYPE_CHECKING, Dict, Any @@ -17,6 +18,12 @@ from quam.core import QuamBase +if sys.version_info < (3, 10): + union_types = (typing.Union,) +else: + union_types = [typing.Union, types.UnionType] + + def instantiate_attrs_from_dict( attr_dict: dict, required_type: type, @@ -225,7 +232,7 @@ def instantiate_attr( ) if typing.get_origin(expected_type) == dict: expected_type = dict - elif typing.get_origin(expected_type) in [typing.Union, types.UnionType]: + elif typing.get_origin(expected_type) in union_types: for union_type in typing.get_args(expected_type): try: instantiated_attr = instantiate_attr(