1
1
from typing import Any , Callable , List
2
2
from abc import ABC
3
3
4
- __all__ = ['GET' , 'SET' , 'DEL' , 'Getter' , 'Setter' , 'Deleter' , 'property_access_mod_class' ]
5
-
6
- class _PropertyAccessModifierBase (ABC ):
4
+ class _PaamBaseDescriptor (ABC ):
7
5
def __init__ (self , obj : Any ) -> None :
8
6
self .is_setter = isinstance (obj , Setter ) or isinstance (self , Setter )
9
7
self .is_getter = isinstance (obj , Getter ) or isinstance (self , Getter )
10
8
self .is_deleter = isinstance (obj , Deleter ) or isinstance (self , Deleter )
11
9
12
- if isinstance (obj , (Setter , Getter , Deleter )):
13
- self .obj = obj .obj
14
- else :
15
- self .obj = obj
10
+ self ._obj = obj
16
11
17
- def __ror__ (self , other : Any ) -> '_PropertyAccessModifierBase' :
18
- return self .__class__ (other )
19
12
20
- class Setter (_PropertyAccessModifierBase ):
21
- pass
13
+ def __get__ (self , owner_instance , owner_cls = None ):
14
+ raise ValueError (
15
+ f"{ owner_instance if owner_cls is None else owner_cls } is not gettable"
16
+ )
22
17
18
+ def __set__ (self , owner_instance , value ):
19
+ raise ValueError (
20
+ f"{ owner_instance } is not settable"
21
+ )
23
22
24
- class Getter (_PropertyAccessModifierBase ):
25
- pass
23
+ def __delete__ (self , owner_instance ):
24
+ raise ValueError (
25
+ f"{ owner_instance } is not deletable"
26
+ )
26
27
28
+ class Setter (_PaamBaseDescriptor ):
29
+ def __set__ (self , owner_instance , value ):
30
+ self ._obj = value
27
31
28
- class Deleter (_PropertyAccessModifierBase ):
29
- pass
32
+ class Getter (_PaamBaseDescriptor ):
33
+ def __get__ (self , owner_instance , owner_cls = None ):
34
+ return self ._obj
30
35
31
- class _PropertyAccessModifierFactoryBase :
36
+ class Deleter (_PaamBaseDescriptor ):
37
+ def __delete__ (self , owner_instance ):
38
+ del self ._obj
39
+
40
+ class _PropertyAccessModifierFactory :
32
41
def __init__ (self , cls : type ) -> None :
33
42
self .cls = cls
34
43
35
- def __ror__ (self , other : Any ) -> _PropertyAccessModifierBase :
44
+ def __ror__ (self , other : Any ) -> _PaamBaseDescriptor :
45
+ if issubclass (other .__class__ , _PaamBaseDescriptor ):
46
+ class Both (self .cls , other .__class__ ):
47
+ pass
48
+ return Both (other ._obj )
36
49
return self .cls (other )
37
50
38
- SET = _PropertyAccessModifierFactoryBase (Setter )
39
- GET = _PropertyAccessModifierFactoryBase (Getter )
40
- DEL = _PropertyAccessModifierFactoryBase (Deleter )
41
-
42
- def property_access_mod_class (klass : type ) -> type :
43
- old_init = klass .__init__
44
-
45
- def new_init (self , * args , ** kwargs ):
46
- old_init (self , * args , ** kwargs )
47
- for k in dir (self ):
48
- v = getattr (self , k )
49
-
50
- if issubclass (type (v ), _PropertyAccessModifierBase ):
51
- setter , getter , deleter = None , None , None
52
- setattr (self , f'_{ k } ' , v .obj )
53
- if v .is_setter :
54
- _k = k
55
- setter = lambda obj , new : setattr (obj , f'_{ _k } ' , new )
56
-
57
- if v .is_getter :
58
- _k = k
59
- getter = lambda obj : getattr (obj , f'_{ _k } ' )
60
-
61
- if v .is_deleter :
62
- _k = k
63
- deleter = lambda obj : delattr (obj , f'_{ _k } ' )
64
-
65
- setattr (klass , k , property (getter , setter , deleter , f"Autogenerated by { __package__ } for { klass } .{ k } ." ))
66
-
67
- klass .__init__ = new_init
68
- return klass
51
+ SET = _PropertyAccessModifierFactory (Setter )
52
+ GET = _PropertyAccessModifierFactory (Getter )
53
+ DEL = _PropertyAccessModifierFactory (Deleter )
54
+
55
+ # read https://dev.to/mattconway1984/python-creating-instance-properties-2ej0
56
+ # for more
57
+ class PaamBase :
58
+ def __setattr__ (self , attr_name : str , value : Any ) -> None :
59
+ try :
60
+ attr = super ().__getattribute__ (attr_name ) # avoid recursion this way
61
+ except AttributeError : # must be "normal" attribute
62
+ super ().__setattr__ (attr_name , value )
63
+ else :
64
+ if issubclass (type (attr ), _PaamBaseDescriptor ):
65
+ attr .__set__ (self , value )
66
+ else :
67
+ super ().__setattr__ (attr_name , value ) # if "normal" attribute
68
+
69
+ def __getattribute__ (self , attr_name : str ) -> Any :
70
+ attr = super ().__getattribute__ (attr_name )
71
+ if issubclass (type (attr ), _PaamBaseDescriptor ):
72
+ return attr .__get__ (self , self .__class__ )
73
+ return attr
74
+
75
+ def __delattr__ (self , attr_name : str ) -> None :
76
+ attr = super ().__getattribute__ (attr_name )
77
+ if issubclass (type (attr ), _PaamBaseDescriptor ):
78
+ attr .__delete__ (self )
79
+ del attr
0 commit comments