File tree 3 files changed +39
-1
lines changed
3 files changed +39
-1
lines changed Original file line number Diff line number Diff line change @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
12
12
- units: DataSize - return 'byte' and 'MiB' instead of '1 byte' and '1 MiB'
13
13
- units: Duration(inf) is now 'Eternity' instead of 'Never'
14
14
- timing: The Timer class now renders the duration using the Duration's repr, instead of as a float
15
+ - aliasing: Improved ` RecursionError ` for aliasing-induced infinite recursion
15
16
16
17
### Added
17
18
- CLI: expose 'colorize' and 'ziplog' as clis
Original file line number Diff line number Diff line change @@ -13,6 +13,13 @@ def super_dir(obj):
13
13
return sorted (set (chain (dir (type (obj )), obj .__dict__ )))
14
14
15
15
16
+ # Python 3.4 does not have RecursionError - it throws a RuntimeError instead
17
+ try :
18
+ _RecursionError = RecursionError
19
+ except NameError :
20
+ _RecursionError = RuntimeError
21
+
22
+
16
23
class AliasingMixin ():
17
24
@property
18
25
def _aliased (self ):
@@ -29,7 +36,16 @@ def __dir__(self):
29
36
def __getattr__ (self , attr ):
30
37
if attr .startswith ("_" ):
31
38
raise AttributeError (attr )
32
- return getattr (self ._aliased , attr )
39
+ try :
40
+ return getattr (self ._aliased , attr )
41
+ except _RecursionError as e :
42
+ if type (e ) is RuntimeError and str (e ) != 'maximum recursion depth exceeded' :
43
+ raise
44
+ raise _RecursionError ('Infinite recursion trying to access {attr!r} on {obj!r} (via {type_name}.{alias}.{attr})' .format (
45
+ attr = attr ,
46
+ obj = self ,
47
+ type_name = type (self ).__name__ ,
48
+ alias = self ._ALIAS ))
33
49
34
50
35
51
def aliases (name , static = True ):
Original file line number Diff line number Diff line change @@ -41,3 +41,24 @@ def __init__(self, x):
41
41
f = Foo ("5" )
42
42
assert f .get ("a" ) == 1
43
43
assert f == 5
44
+
45
+
46
+ def test_aliasing_infinite_recursion_exception ():
47
+ @aliases ('bar' , static = False )
48
+ class Foo :
49
+ def __init__ (self ):
50
+ self .bar = Bar (self )
51
+
52
+ def __repr__ (self ):
53
+ return 'Foo()'
54
+
55
+ class Bar :
56
+ def __init__ (self , foo ):
57
+ self .foo = foo
58
+
59
+ def baz (self ):
60
+ return self .foo .baz ()
61
+
62
+ with pytest .raises (getattr (__builtins__ , 'RecursionError' , RuntimeError )) as e :
63
+ Foo ().baz ()
64
+ assert str (e .value ) == "Infinite recursion trying to access 'baz' on Foo() (via Foo.bar.baz)"
You can’t perform that action at this time.
0 commit comments