hdl.ast: improve interaction of ValueCastable with custom __getattr__.
Avoid calling `__getattr__("_ValueCastable__lowered_to")` when
a ValueCastable has custom `__getattr__` implementation; this avoids
the need for downstream code to be aware of this implementataion
detail.
			
			
This commit is contained in:
		
							parent
							
								
									fac1b4b2d1
								
							
						
					
					
						commit
						11914a1e67
					
				|  | @ -1305,16 +1305,18 @@ class ValueCastable: | |||
|     def lowermethod(func): | ||||
|         """Decorator to memoize lowering methods. | ||||
| 
 | ||||
|         Ensures the decorated method is called only once, with subsequent method calls returning the | ||||
|         object returned by the first first method call. | ||||
|         Ensures the decorated method is called only once, with subsequent method calls returning | ||||
|         the object returned by the first first method call. | ||||
| 
 | ||||
|         This decorator is required to decorate the ``as_value`` method of ``ValueCastable`` subclasses. | ||||
|         This is to ensure that nMigen's view of representation of all values stays internally | ||||
|         consistent. | ||||
|         This decorator is required to decorate the ``as_value`` method of ``ValueCastable`` | ||||
|         subclasses. This is to ensure that nMigen's view of representation of all values stays | ||||
|         internally consistent. | ||||
|         """ | ||||
|         @functools.wraps(func) | ||||
|         def wrapper_memoized(self, *args, **kwargs): | ||||
|             if not hasattr(self, "_ValueCastable__lowered_to"): | ||||
|             # Use `in self.__dict__` instead of `hasattr` to avoid interfering with custom | ||||
|             # `__getattr__` implementations. | ||||
|             if not "_ValueCastable__lowered_to" in self.__dict__: | ||||
|                 self.__lowered_to = func(self, *args, **kwargs) | ||||
|             return self.__lowered_to | ||||
|         wrapper_memoized.__memoized = True | ||||
|  |  | |||
|  | @ -1060,6 +1060,18 @@ class MockValueCastableNoOverride(ValueCastable): | |||
|         pass | ||||
| 
 | ||||
| 
 | ||||
| class MockValueCastableCustomGetattr(ValueCastable): | ||||
|     def __init__(self): | ||||
|         pass | ||||
| 
 | ||||
|     @ValueCastable.lowermethod | ||||
|     def as_value(self): | ||||
|         return Const(0) | ||||
| 
 | ||||
|     def __getattr__(self, attr): | ||||
|         assert False | ||||
| 
 | ||||
| 
 | ||||
| class ValueCastableTestCase(FHDLTestCase): | ||||
|     def test_not_decorated(self): | ||||
|         with self.assertRaisesRegex(TypeError, | ||||
|  | @ -1083,6 +1095,10 @@ class ValueCastableTestCase(FHDLTestCase): | |||
|         sig3 = Value.cast(vc) | ||||
|         self.assertIs(sig1, sig3) | ||||
| 
 | ||||
|     def test_custom_getattr(self): | ||||
|         vc = MockValueCastableCustomGetattr() | ||||
|         vc.as_value() # shouldn't call __getattr__ | ||||
| 
 | ||||
| 
 | ||||
| class SampleTestCase(FHDLTestCase): | ||||
|     def test_const(self): | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 whitequark
						whitequark