swizzle 0.1.3__py3-none-any.whl → 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- swizzle/__init__.py +112 -80
- {swizzle-0.1.3.dist-info → swizzle-1.0.0.dist-info}/METADATA +6 -4
- swizzle-1.0.0.dist-info/RECORD +5 -0
- {swizzle-0.1.3.dist-info → swizzle-1.0.0.dist-info}/WHEEL +1 -1
- swizzle-0.1.3.dist-info/RECORD +0 -5
- {swizzle-0.1.3.dist-info → swizzle-1.0.0.dist-info}/top_level.txt +0 -0
swizzle/__init__.py
CHANGED
@@ -1,80 +1,112 @@
|
|
1
|
-
from functools import wraps
|
2
|
-
import sys
|
3
|
-
import types
|
4
|
-
|
5
|
-
__version__ = "0.
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
return
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
1
|
+
from functools import wraps
|
2
|
+
import sys
|
3
|
+
import types
|
4
|
+
|
5
|
+
__version__ = "1.0.0"
|
6
|
+
MISSING = object()
|
7
|
+
|
8
|
+
|
9
|
+
# Helper function to split a string based on a separator
|
10
|
+
def split_string(string, separator):
|
11
|
+
if separator == '':
|
12
|
+
return list(string)
|
13
|
+
else:
|
14
|
+
return string.split(separator)
|
15
|
+
|
16
|
+
# Helper function to collect attribute retrieval functions from a class or meta-class
|
17
|
+
def collect_attribute_functions(cls):
|
18
|
+
funcs = []
|
19
|
+
if hasattr(cls, '__getattribute__'):
|
20
|
+
funcs.append(cls.__getattribute__)
|
21
|
+
if hasattr(cls, '__getattr__'):
|
22
|
+
funcs.append(cls.__getattr__)
|
23
|
+
if not funcs:
|
24
|
+
raise AttributeError("No __getattr__ or __getattribute__ found on the class or meta-class")
|
25
|
+
return funcs
|
26
|
+
|
27
|
+
# Function to combine multiple attribute retrieval functions
|
28
|
+
def swizzle_attributes_retriever(attribute_funcs, separator=None):
|
29
|
+
def retrieve_attribute(obj, attr_name):
|
30
|
+
for func in attribute_funcs:
|
31
|
+
try:
|
32
|
+
return func(obj, attr_name)
|
33
|
+
except AttributeError:
|
34
|
+
continue
|
35
|
+
return MISSING
|
36
|
+
|
37
|
+
@wraps(attribute_funcs[-1])
|
38
|
+
def retrieve_swizzled_attributes(obj, attr_name):
|
39
|
+
# Attempt to find an exact attribute match
|
40
|
+
attribute = retrieve_attribute(obj, attr_name)
|
41
|
+
if attribute is not MISSING:
|
42
|
+
return attribute
|
43
|
+
|
44
|
+
matched_attributes = []
|
45
|
+
|
46
|
+
# If a separator is provided, split the name accordingly
|
47
|
+
if separator is not None:
|
48
|
+
attr_parts = split_string(attr_name, separator)
|
49
|
+
for part in attr_parts:
|
50
|
+
attribute = retrieve_attribute(obj, part)
|
51
|
+
if attribute is not MISSING:
|
52
|
+
matched_attributes.append(attribute)
|
53
|
+
else:
|
54
|
+
# No separator provided, attempt to match substrings
|
55
|
+
i = 0
|
56
|
+
while i < len(attr_name):
|
57
|
+
match_found = False
|
58
|
+
for j in range(len(attr_name), i, -1):
|
59
|
+
substring = attr_name[i:j]
|
60
|
+
attribute = retrieve_attribute(obj, substring)
|
61
|
+
if attribute is not MISSING:
|
62
|
+
matched_attributes.append(attribute)
|
63
|
+
i = j # Move index to end of the matched substring
|
64
|
+
match_found = True
|
65
|
+
break
|
66
|
+
if not match_found:
|
67
|
+
raise AttributeError(f"No matching attribute found for substring: {attr_name[i:]}")
|
68
|
+
|
69
|
+
return tuple(matched_attributes)
|
70
|
+
|
71
|
+
return retrieve_swizzled_attributes
|
72
|
+
|
73
|
+
# Decorator function to enable swizzling for a class
|
74
|
+
def swizzle(cls=None, use_meta=False, separator=None):
|
75
|
+
def class_decorator(cls):
|
76
|
+
# Collect attribute retrieval functions from the class
|
77
|
+
attribute_funcs = collect_attribute_functions(cls)
|
78
|
+
|
79
|
+
# Apply the swizzling to the class's attribute retrieval
|
80
|
+
setattr(cls, attribute_funcs[-1].__name__, swizzle_attributes_retriever(attribute_funcs, separator))
|
81
|
+
|
82
|
+
# Handle meta-class swizzling if requested
|
83
|
+
if use_meta:
|
84
|
+
meta_cls = type(cls)
|
85
|
+
if meta_cls == type:
|
86
|
+
class SwizzledMetaType(meta_cls):
|
87
|
+
pass
|
88
|
+
meta_cls = SwizzledMetaType
|
89
|
+
cls = meta_cls(cls.__name__, cls.__bases__, dict(cls.__dict__))
|
90
|
+
meta_cls = SwizzledMetaType
|
91
|
+
cls = meta_cls(cls.__name__, cls.__bases__, dict(cls.__dict__))
|
92
|
+
|
93
|
+
meta_funcs = collect_attribute_functions(meta_cls)
|
94
|
+
setattr(meta_cls, meta_funcs[-1].__name__, swizzle_attributes_retriever(meta_funcs, separator))
|
95
|
+
|
96
|
+
return cls
|
97
|
+
|
98
|
+
if cls is None:
|
99
|
+
return class_decorator
|
100
|
+
else:
|
101
|
+
return class_decorator(cls)
|
102
|
+
|
103
|
+
|
104
|
+
class Swizzle(types.ModuleType):
|
105
|
+
def __init__(self):
|
106
|
+
types.ModuleType.__init__(self, __name__)
|
107
|
+
self.__dict__.update(sys.modules[__name__].__dict__)
|
108
|
+
|
109
|
+
def __call__(self, cls=None, meta=False, sep = None):
|
110
|
+
return swizzle(cls, meta, sep)
|
111
|
+
|
112
|
+
sys.modules[__name__] = Swizzle()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: swizzle
|
3
|
-
Version: 0.
|
3
|
+
Version: 1.0.0
|
4
4
|
Summary: The Swizzle Decorator enables the retrieval of multiple attributes, similar to swizzling in computer graphics.
|
5
5
|
Home-page: https://github.com/janthmueller/swizzle
|
6
6
|
Author: Jan T. Müller
|
@@ -77,7 +77,7 @@ class XYZ(IntEnum):
|
|
77
77
|
Z = 3
|
78
78
|
|
79
79
|
# Test the swizzle
|
80
|
-
print(XYZ.
|
80
|
+
print(XYZ.YXZ) # Output: (<XYZ.Y: 2>, <XYZ.X: 1>, <XYZ.Z: 3>)
|
81
81
|
```
|
82
82
|
Setting the `meta` argument to `True` in the swizzle decorator extends the `getattr` behavior of the metaclass, enabling attribute swizzling directly on the class itself.
|
83
83
|
|
@@ -99,8 +99,8 @@ print(xyz.yzx) # Output: (2, 3, 1)
|
|
99
99
|
```
|
100
100
|
|
101
101
|
|
102
|
-
### Sequential matching
|
103
|
-
Attributes are matched from left to right, starting with the longest substring match.
|
102
|
+
### Sequential matching
|
103
|
+
Attributes are matched from left to right, starting with the longest substring match.
|
104
104
|
```python
|
105
105
|
import swizzle
|
106
106
|
|
@@ -121,3 +121,5 @@ print(Test.xyyz) # Output: (4, 5)
|
|
121
121
|
print(Test.xyzx) # Output: (7, 1)
|
122
122
|
```
|
123
123
|
|
124
|
+
## To Do
|
125
|
+
- [ ] Swizzle for method args (swizzle+partial)
|
@@ -0,0 +1,5 @@
|
|
1
|
+
swizzle/__init__.py,sha256=9LHl0nK4LB9aEm4264zzhCLL_yF6_2k3-hHdORzapVU,4151
|
2
|
+
swizzle-1.0.0.dist-info/METADATA,sha256=B8VrYh-Lm_Ixg_J-GrVdNAbpOP3oR6ouRVUSLii8izI,2963
|
3
|
+
swizzle-1.0.0.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
|
4
|
+
swizzle-1.0.0.dist-info/top_level.txt,sha256=XFSQti81x2zM0zAMCY1YD0lqB1eSg5my9BB03uFgCic,8
|
5
|
+
swizzle-1.0.0.dist-info/RECORD,,
|
swizzle-0.1.3.dist-info/RECORD
DELETED
@@ -1,5 +0,0 @@
|
|
1
|
-
swizzle/__init__.py,sha256=Y3Z1mQdZbcjFE612dzwlqMby_qtJtSf68NgmylPPHGw,2684
|
2
|
-
swizzle-0.1.3.dist-info/METADATA,sha256=ueORk9NK-YFClvH7EvL7nTFwmXUaaNHkFUZfafMPw6c,2908
|
3
|
-
swizzle-0.1.3.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
|
4
|
-
swizzle-0.1.3.dist-info/top_level.txt,sha256=XFSQti81x2zM0zAMCY1YD0lqB1eSg5my9BB03uFgCic,8
|
5
|
-
swizzle-0.1.3.dist-info/RECORD,,
|
File without changes
|