File tree Expand file tree Collapse file tree
tests/test_components/material
tidy3d/components/material Expand file tree Collapse file tree 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):
128128 Extend that mapping as additional cross-medium shim behaviour becomes
129129 necessary.
130130 """
131+ # first check whether the attribute is already present
132+ try :
133+ return super ().__getattr__ (name )
134+ except AttributeError :
135+ pass
136+
131137 IGNORED_ATTRIBUTES = ["__deepcopy__" ]
132138 if name in IGNORED_ATTRIBUTES :
133139 return None
@@ -139,11 +145,18 @@ def __getattr__(self, name: str):
139145 }
140146
141147 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+ )
147160
148161 @property
149162 def heat_spec (self ):
You can’t perform that action at this time.
0 commit comments