File tree Expand file tree Collapse file tree 2 files changed +57
-5
lines changed
tests/test_components/material
tidy3d/components/material Expand file tree Collapse file tree 2 files changed +57
-5
lines changed Original file line number Diff line number Diff line change
1
+ import copy
2
+
3
+ import pytest
4
+ import tidy3d as td
5
+
6
+
7
+ @pytest .fixture
8
+ def dummy_optical ():
9
+ return td .Medium (permittivity = 1.0 )
10
+
11
+
12
+ def test_delegated_attributes_work (dummy_optical ):
13
+ mp = td .MultiPhysicsMedium (optical = dummy_optical )
14
+
15
+ # delegated names resolve
16
+ assert mp .is_pec is dummy_optical .is_pec
17
+ assert mp ._eps_plot == dummy_optical ._eps_plot
18
+ assert mp .viz_spec == dummy_optical .viz_spec
19
+
20
+ # deepcopy still succeeds because __deepcopy__ is ignored
21
+ copy .deepcopy (mp )
22
+
23
+
24
+ def test_delegated_attribute_without_optical_raises ():
25
+ mp_no_opt = td .MultiPhysicsMedium (optical = None )
26
+
27
+ with pytest .raises (AttributeError , match = r"optical medium is 'None'" ):
28
+ _ = mp_no_opt .is_pec
29
+
30
+
31
+ def test_has_cached_props (dummy_optical ):
32
+ mp = td .MultiPhysicsMedium (optical = dummy_optical )
33
+ mp ._cached_properties
34
+
35
+
36
+ def test_unknown_attribute_error (dummy_optical ):
37
+ mp = td .MultiPhysicsMedium (optical = dummy_optical )
38
+ with pytest .raises (AttributeError , match = r"Did you mean to access the attribute of one" ):
39
+ _ = mp .not_a_real_attribute
Original file line number Diff line number Diff line change @@ -128,6 +128,12 @@ def __getattr__(self, name: str):
128
128
Extend that mapping as additional cross-medium shim behaviour becomes
129
129
necessary.
130
130
"""
131
+ # first check whether the attribute is already present
132
+ try :
133
+ return super ().__getattr__ (name )
134
+ except AttributeError :
135
+ pass
136
+
131
137
IGNORED_ATTRIBUTES = ["__deepcopy__" ]
132
138
if name in IGNORED_ATTRIBUTES :
133
139
return None
@@ -139,11 +145,18 @@ def __getattr__(self, name: str):
139
145
}
140
146
141
147
if name in DELEGATED_ATTRIBUTES :
142
- return getattr (DELEGATED_ATTRIBUTES [name ], name )
143
- else :
144
- raise ValueError (
145
- f"MultiPhysicsMedium has no attribute called { name } . Did you mean to access the attribute of one of the optical, heat or charge media?"
146
- )
148
+ sub = DELEGATED_ATTRIBUTES [name ]
149
+ if sub is None :
150
+ raise AttributeError (
151
+ f"Requested attribute { name !r} , but the optical medium is 'None' "
152
+ " on this 'MultiPhysicsMedium' instance."
153
+ )
154
+ return getattr (sub , name )
155
+
156
+ raise AttributeError (
157
+ f"MultiPhysicsMedium has no attribute called { name } . "
158
+ "Did you mean to access the attribute of one of the optical, heat or charge media?"
159
+ )
147
160
148
161
@property
149
162
def heat_spec (self ):
You can’t perform that action at this time.
0 commit comments