swizzle 0.1.4__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 CHANGED
@@ -1,80 +1,112 @@
1
- from functools import wraps
2
- import sys
3
- import types
4
-
5
- __version__ = "0.1.4"
6
-
7
- def _split(s, sep):
8
- if sep == '':
9
- return list(s)
10
- else:
11
- return s.split(sep)
12
-
13
- def _swizzle(func, sep = None):
14
- def _getattr(obj, name, default=object()):
15
- try:
16
- return func(obj, name)
17
- except AttributeError:
18
- return default
19
-
20
- @wraps(func)
21
- def _swizzle_attributes(obj, name):
22
- """Find attributes of an object that match substrings of a given name."""
23
- try:
24
- return func(obj, name)
25
- except AttributeError:
26
- pass
27
- if sep is not None:
28
- names = _split(name, sep)
29
- found_attributes = [func(obj, n) for n in names]
30
- else:
31
- found_attributes = []
32
- sentinel = object()
33
- i = 0
34
- while i < len(name):
35
- match_found = False
36
- for j in range(len(name), i, -1):
37
- substr = name[i:j]
38
- attr = _getattr(obj, substr, sentinel)
39
- if attr is not sentinel:
40
- found_attributes.append(attr)
41
- i = j # Move index to end of the matched substring
42
- match_found = True
43
- break
44
- if not match_found:
45
- raise AttributeError(f"No matching attribute found for substring: {name[i:]}")
46
- return tuple(found_attributes)
47
- return _swizzle_attributes
48
-
49
- def swizzle(cls=None, meta = False, sep = None):
50
- def decorator(cls):
51
- # Decorate the class's __getattr__ or __getattribute__
52
- cls_fn = cls.__getattr__ if hasattr(cls, '__getattr__') else cls.__getattribute__
53
- setattr(cls, cls_fn.__name__, _swizzle(cls_fn, sep))
54
-
55
- # Handle the meta class
56
- if meta:
57
- meta_cls = type(cls)
58
- if meta_cls == type:
59
- class SwizzleType(meta_cls): pass
60
- meta_cls = SwizzleType
61
- cls = meta_cls(cls.__name__, cls.__bases__, dict(cls.__dict__))
62
- meta_fn = meta_cls.__getattr__ if hasattr(meta_cls, '__getattr__') else meta_cls.__getattribute__
63
- setattr(meta_cls, meta_fn.__name__, _swizzle(meta_fn, sep))
64
- return cls
65
-
66
- if cls is None:
67
- return decorator
68
- else:
69
- return decorator(cls)
70
-
71
- class Swizzle(types.ModuleType):
72
- def __init__(self):
73
- types.ModuleType.__init__(self, __name__)
74
- self.__dict__.update(sys.modules[__name__].__dict__)
75
-
76
- def __call__(self, cls=None, meta=False, sep = None):
77
- return swizzle(cls, meta, sep)
78
-
79
- sys.modules[__name__] = Swizzle()
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.1.4
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
@@ -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
 
@@ -122,5 +122,4 @@ print(Test.xyzx) # Output: (7, 1)
122
122
  ```
123
123
 
124
124
  ## To Do
125
- - [ ] Add support for module-level swizzling
126
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,,
@@ -1,5 +0,0 @@
1
- swizzle/__init__.py,sha256=AX8PGVBeBQIy3EdF8iu3IV6H7UfoU50C8DBvuVOAgXY,2684
2
- swizzle-0.1.4.dist-info/METADATA,sha256=s3wRwoiAxpPOg2RzAbnarDSe7sIxBhjy_6M5W0_S3Sw,3010
3
- swizzle-0.1.4.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
4
- swizzle-0.1.4.dist-info/top_level.txt,sha256=XFSQti81x2zM0zAMCY1YD0lqB1eSg5my9BB03uFgCic,8
5
- swizzle-0.1.4.dist-info/RECORD,,