swizzle 1.0.0__tar.gz → 2.1.0__tar.gz

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-2.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Jan T. Mueller
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
swizzle-2.1.0/PKG-INFO ADDED
@@ -0,0 +1,128 @@
1
+ Metadata-Version: 2.1
2
+ Name: swizzle
3
+ Version: 2.1.0
4
+ Summary: Swizzle enables the retrieval of multiple attributes, similar to swizzling in computer graphics.
5
+ Home-page: https://github.com/janthmueller/swizzle
6
+ Author: Jan T. Müller
7
+ Author-email: mail@jantmueller.com
8
+ License: MIT
9
+ Project-URL: Documentation, https://github.com/janthmueller/swizzle/blob/main/README.md
10
+ Project-URL: Source, https://github.com/janthmueller/swizzle
11
+ Project-URL: Tracker, https://github.com/janthmueller/swizzle/issues
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Requires-Python: >=3.6
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+
21
+ # Swizzle
22
+ [![PyPI version](https://badge.fury.io/py/swizzle.svg?kill_cache=1)](https://badge.fury.io/py/swizzle)
23
+ [![Downloads](https://pepy.tech/badge/swizzle?kill_cache=1)](https://pepy.tech/project/swizzle)
24
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/janthmueller/swizzle/blob/main/LICENSE)
25
+ [![GitHub Stars](https://img.shields.io/github/stars/janthmueller/swizzle.svg?kill_cache=1)](https://github.com/janthmueller/swizzle/stargazers)
26
+
27
+ **Swizzle** for Python enhances attribute lookup methods to facilitate dynamic and flexible retrieval of multiple attributes based on specified arrangements of their names.
28
+ > **Update v2:**
29
+ > Introducing `swizzledtuple` , a new function that allows you to create swizzled named tuples. This feature is inspired by the `namedtuple` function from the [collections module](https://docs.python.org/3/library/collections.html#collections.namedtuple) and provides a concise way to define swizzled tuples.
30
+ > ```python
31
+ > from swizzle import swizzledtuple
32
+ >
33
+ > Vector = swizzledtuple('Vector', 'x y z', arrange_names = "y z x x")
34
+ >
35
+ > # Test the swizzle
36
+ > v = Vector(1, 2, 3)
37
+ > print(v) # Output: Vector(y=2, z=3, x=1, x=1)
38
+ > print(v.yzx) # Output: Vector(y = 2, z = 3, x = 1)
39
+ > print(v.yzx.xxzyzz) # Output: Vector(x=1, x=1, z=3, y=2, z=3, z=3)
40
+ >```
41
+
42
+ ### Swizzle Decorator:
43
+
44
+ ```python
45
+ import swizzle
46
+
47
+ @swizzle
48
+ class Vector:
49
+ def __init__(self, x, y, z):
50
+ self.x = x
51
+ self.y = y
52
+ self.z = z
53
+
54
+ # Test the swizzle
55
+ print(Vector(1, 2, 3).yzx) # Output: Vector(y = 2, z = 3, x = 1)
56
+ ```
57
+
58
+
59
+ ## Installation
60
+ ### From PyPI
61
+ ```bash
62
+ pip install swizzle
63
+ ```
64
+ ### From GitHub
65
+ ```bash
66
+ pip install git+https://github.com/janthmueller/swizzle.git
67
+ ```
68
+
69
+ ## Further Examples
70
+
71
+ ### Using `swizzle` with `dataclass`
72
+
73
+ ```python
74
+ import swizzle
75
+ from dataclasses import dataclass
76
+
77
+ @swizzle
78
+ @dataclass
79
+ class Vector:
80
+ x: int
81
+ y: int
82
+ z: int
83
+
84
+ # Test the swizzle
85
+ print(Vector(1, 2, 3).yzx) # Output: Vector(y = 2, z = 3, x = 1)
86
+ ```
87
+
88
+ ### Using `swizzle` with `IntEnum`
89
+
90
+ ```python
91
+ import swizzle
92
+ from enum import IntEnum
93
+
94
+ @swizzle(meta=True)
95
+ class Vector(IntEnum):
96
+ X = 1
97
+ Y = 2
98
+ Z = 3
99
+
100
+ # Test the swizzle
101
+ print(Vector.YXZ) # Output: Vector(Y=<Vector.Y: 2>, X=<Vector.X: 1>, Z=<Vector.Z: 3>)
102
+ ```
103
+ 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.
104
+
105
+
106
+ ### Sequential matching
107
+ Attributes are matched from left to right, starting with the longest substring match. This behavior can be controlled by the `seperator` argument in the swizzle decorator.
108
+ ```python
109
+ import swizzle
110
+
111
+ @swizzle(meta=True)
112
+ class Vector:
113
+ x = 1
114
+ y = 2
115
+ z = 3
116
+ xy = 4
117
+ yz = 5
118
+ xz = 6
119
+ xyz = 7
120
+
121
+ # Test the swizzle
122
+ print(Vector.xz) # Output: 6
123
+ print(Vector.yz) # Output: 5
124
+ print(Vector.xyyz) # Output: Vector(xy=4, yz=5)
125
+ print(Vector.xyzx) # Output: Vector(xyz=7, x=1)
126
+ ```
127
+
128
+
@@ -0,0 +1,108 @@
1
+ # Swizzle
2
+ [![PyPI version](https://badge.fury.io/py/swizzle.svg?kill_cache=1)](https://badge.fury.io/py/swizzle)
3
+ [![Downloads](https://pepy.tech/badge/swizzle?kill_cache=1)](https://pepy.tech/project/swizzle)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/janthmueller/swizzle/blob/main/LICENSE)
5
+ [![GitHub Stars](https://img.shields.io/github/stars/janthmueller/swizzle.svg?kill_cache=1)](https://github.com/janthmueller/swizzle/stargazers)
6
+
7
+ **Swizzle** for Python enhances attribute lookup methods to facilitate dynamic and flexible retrieval of multiple attributes based on specified arrangements of their names.
8
+ > **Update v2:**
9
+ > Introducing `swizzledtuple` , a new function that allows you to create swizzled named tuples. This feature is inspired by the `namedtuple` function from the [collections module](https://docs.python.org/3/library/collections.html#collections.namedtuple) and provides a concise way to define swizzled tuples.
10
+ > ```python
11
+ > from swizzle import swizzledtuple
12
+ >
13
+ > Vector = swizzledtuple('Vector', 'x y z', arrange_names = "y z x x")
14
+ >
15
+ > # Test the swizzle
16
+ > v = Vector(1, 2, 3)
17
+ > print(v) # Output: Vector(y=2, z=3, x=1, x=1)
18
+ > print(v.yzx) # Output: Vector(y = 2, z = 3, x = 1)
19
+ > print(v.yzx.xxzyzz) # Output: Vector(x=1, x=1, z=3, y=2, z=3, z=3)
20
+ >```
21
+
22
+ ### Swizzle Decorator:
23
+
24
+ ```python
25
+ import swizzle
26
+
27
+ @swizzle
28
+ class Vector:
29
+ def __init__(self, x, y, z):
30
+ self.x = x
31
+ self.y = y
32
+ self.z = z
33
+
34
+ # Test the swizzle
35
+ print(Vector(1, 2, 3).yzx) # Output: Vector(y = 2, z = 3, x = 1)
36
+ ```
37
+
38
+
39
+ ## Installation
40
+ ### From PyPI
41
+ ```bash
42
+ pip install swizzle
43
+ ```
44
+ ### From GitHub
45
+ ```bash
46
+ pip install git+https://github.com/janthmueller/swizzle.git
47
+ ```
48
+
49
+ ## Further Examples
50
+
51
+ ### Using `swizzle` with `dataclass`
52
+
53
+ ```python
54
+ import swizzle
55
+ from dataclasses import dataclass
56
+
57
+ @swizzle
58
+ @dataclass
59
+ class Vector:
60
+ x: int
61
+ y: int
62
+ z: int
63
+
64
+ # Test the swizzle
65
+ print(Vector(1, 2, 3).yzx) # Output: Vector(y = 2, z = 3, x = 1)
66
+ ```
67
+
68
+ ### Using `swizzle` with `IntEnum`
69
+
70
+ ```python
71
+ import swizzle
72
+ from enum import IntEnum
73
+
74
+ @swizzle(meta=True)
75
+ class Vector(IntEnum):
76
+ X = 1
77
+ Y = 2
78
+ Z = 3
79
+
80
+ # Test the swizzle
81
+ print(Vector.YXZ) # Output: Vector(Y=<Vector.Y: 2>, X=<Vector.X: 1>, Z=<Vector.Z: 3>)
82
+ ```
83
+ 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.
84
+
85
+
86
+ ### Sequential matching
87
+ Attributes are matched from left to right, starting with the longest substring match. This behavior can be controlled by the `seperator` argument in the swizzle decorator.
88
+ ```python
89
+ import swizzle
90
+
91
+ @swizzle(meta=True)
92
+ class Vector:
93
+ x = 1
94
+ y = 2
95
+ z = 3
96
+ xy = 4
97
+ yz = 5
98
+ xz = 6
99
+ xyz = 7
100
+
101
+ # Test the swizzle
102
+ print(Vector.xz) # Output: 6
103
+ print(Vector.yz) # Output: 5
104
+ print(Vector.xyyz) # Output: Vector(xy=4, yz=5)
105
+ print(Vector.xyzx) # Output: Vector(xyz=7, x=1)
106
+ ```
107
+
108
+
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 Jan T. Müller <mail@jantmueller.com>
1
+ # Copyright (c) 2024 Jan T. Müller <mail@jantmueller.com>
2
2
 
3
3
  import sys
4
4
  import os
@@ -17,7 +17,7 @@ setup(
17
17
  packages=find_packages(exclude=["tests"]),
18
18
  author="Jan T. Müller",
19
19
  author_email="mail@jantmueller.com",
20
- description="The Swizzle Decorator enables the retrieval of multiple attributes, similar to swizzling in computer graphics.",
20
+ description="Swizzle enables the retrieval of multiple attributes, similar to swizzling in computer graphics.",
21
21
  long_description=long_description,
22
22
  long_description_content_type="text/markdown",
23
23
  url="https://github.com/janthmueller/swizzle",
@@ -0,0 +1,394 @@
1
+ # Copyright (c) 2024 Jan T. Müller <mail@jantmueller.com>
2
+
3
+ import warnings
4
+ from functools import wraps
5
+ import types
6
+ import builtins
7
+ import sys as _sys
8
+
9
+ from keyword import iskeyword as _iskeyword
10
+ from operator import itemgetter as _itemgetter
11
+ try:
12
+ from _collections import _tuplegetter
13
+ except ImportError:
14
+ _tuplegetter = lambda index, doc: property(_itemgetter(index), doc=doc)
15
+
16
+
17
+ __version__ = "2.1.0"
18
+
19
+ MISSING = object()
20
+
21
+ def swizzledtuple(typename, field_names, *, rename=False, defaults=None, module=None, arrange_names = None, seperator = None):
22
+ """
23
+ Create a custom named tuple class with swizzled attributes, allowing for rearranged field names
24
+ and customized attribute access.
25
+
26
+ This function generates a new subclass of `tuple` with named fields, similar to Python's
27
+ `collections.namedtuple`. However, it extends the functionality by allowing field names to be
28
+ rearranged, and attributes to be accessed with a customizable separator. The function also
29
+ provides additional safeguards for field naming and attribute access.
30
+
31
+ Args:
32
+ typename (str): The name of the new named tuple type.
33
+ field_names (sequence of str or str): A sequence of field names for the tuple. If given as
34
+ a single string, it will be split into separate field names.
35
+ rename (bool, optional): If True, invalid field names are automatically replaced with
36
+ positional names. Defaults to False.
37
+ defaults (sequence, optional): Default values for the fields. Defaults to None.
38
+ module (str, optional): The module name in which the named tuple is defined. Defaults to
39
+ the caller's module.
40
+ arrange_names (sequence of str, optional): A sequence of field names indicating the order
41
+ in which fields should be arranged in the resulting named tuple. This allows for fields
42
+ to be rearranged and, unlike standard `namedtuple`, can include duplicates. Defaults
43
+ to the order given in `field_names`.
44
+ separator (str, optional): A separator string that customizes the structure of attribute
45
+ access. If provided, this separator allows attributes to be accessed by combining field
46
+ names with the separator in between them. Defaults to no separator.
47
+
48
+ Returns:
49
+ type: A new subclass of `tuple` with named fields and customized attribute access.
50
+
51
+ Notes:
52
+ - The function is based on `collections.namedtuple` but with additional features such as
53
+ field rearrangement and swizzled attribute access.
54
+ - The `arrange_names` argument allows rearranging the field names, and it can include
55
+ duplicates, which is not possible in a standard `namedtuple`.
56
+ - The generated named tuple class includes methods like `_make`, `_replace`, `__repr__`,
57
+ `_asdict`, and `__getnewargs__`, partially customized to handle the rearranged field order.
58
+ - The `separator` argument enables a custom structure for attribute access, allowing for
59
+ combined attribute names based on the provided separator. If no separator is provided,
60
+ standard attribute access is used.
61
+
62
+ Example:
63
+ >>> Vector = swizzledtuple('Vector', 'x y z', arrange_names='y z x x')
64
+ >>> # Test the swizzle
65
+ >>> v = Vector(1, 2, 3)
66
+ >>> print(v) # Output: Vector(y=2, z=3, x=1, x=1)
67
+ >>> print(v.yzx) # Output: Vector(y=2, z=3, x=1)
68
+ >>> print(v.yzx.xxzyzz) # Output: Vector(x=1, x=1, z=3, y=2, z=3, z=3)
69
+ """
70
+
71
+ if isinstance(field_names, str):
72
+ field_names = field_names.replace(',', ' ').split()
73
+ field_names = list(map(str, field_names))
74
+ if arrange_names is not None:
75
+ if isinstance(arrange_names, str):
76
+ arrange_names = arrange_names.replace(',', ' ').split()
77
+ arrange_names = list(map(str, arrange_names))
78
+ assert set(arrange_names) == set(field_names), 'Arrangement must contain all field names'
79
+ else:
80
+ arrange_names = field_names.copy()
81
+
82
+
83
+ typename = _sys.intern(str(typename))
84
+
85
+ _dir = dir(tuple) + ['__match_args__', '__module__', '__slots__', '_asdict', '_field_defaults', '_fields', '_make', '_replace',]
86
+ if rename:
87
+ seen = set()
88
+ name_newname = {}
89
+ for index, name in enumerate(field_names):
90
+ if (not name.isidentifier()
91
+ or _iskeyword(name)
92
+ or name in _dir
93
+ or name in seen):
94
+ field_names[index] = f'_{index}'
95
+ name_newname[name] = field_names[index]
96
+ seen.add(name)
97
+ for index, name in enumerate(arrange_names):
98
+ arrange_names[index] = name_newname[name]
99
+
100
+ for name in [typename] + field_names:
101
+ if type(name) is not str:
102
+ raise TypeError('Type names and field names must be strings')
103
+ if not name.isidentifier():
104
+ raise ValueError('Type names and field names must be valid '
105
+ f'identifiers: {name!r}')
106
+ if _iskeyword(name):
107
+ raise ValueError('Type names and field names cannot be a '
108
+ f'keyword: {name!r}')
109
+ seen = set()
110
+ for name in field_names:
111
+ if name in _dir and not rename:
112
+ raise ValueError('Field names cannot be an attribute name which would shadow the namedtuple methods or attributes'
113
+ f'{name!r}')
114
+ if name in seen:
115
+ raise ValueError(f'Encountered duplicate field name: {name!r}')
116
+ seen.add(name)
117
+
118
+ arrange_indices = [field_names.index(name) for name in arrange_names]
119
+
120
+ def tuple_new(cls, iterable):
121
+ new = []
122
+ _iterable = list(iterable)
123
+ for index in arrange_indices:
124
+ new.append(_iterable[index])
125
+ return tuple.__new__(cls, new)
126
+
127
+ field_defaults = {}
128
+ if defaults is not None:
129
+ defaults = tuple(defaults)
130
+ if len(defaults) > len(field_names):
131
+ raise TypeError('Got more default values than field names')
132
+ field_defaults = dict(reversed(list(zip(reversed(field_names),
133
+ reversed(defaults)))))
134
+
135
+ field_names = tuple(map(_sys.intern, field_names))
136
+ arrange_names = tuple(map(_sys.intern, arrange_names))
137
+ num_fields = len(field_names)
138
+ num_arrange_fields = len(arrange_names)
139
+ arg_list = ', '.join(field_names)
140
+ if num_fields == 1:
141
+ arg_list += ','
142
+ repr_fmt = '(' + ', '.join(f'{name}=%r' for name in arrange_names) + ')'
143
+ _dict, _tuple, _len, _map, _zip = dict, tuple, len, map, zip
144
+
145
+ namespace = {
146
+ '_tuple_new': tuple_new,
147
+ '__builtins__': {},
148
+ '__name__': f'namedtuple_{typename}',
149
+ }
150
+ code = f'lambda _cls, {arg_list}: _tuple_new(_cls, ({arg_list}))'
151
+ __new__ = eval(code, namespace)
152
+ __new__.__name__ = '__new__'
153
+ __new__.__doc__ = f'Create new instance of {typename}({arg_list})'
154
+ if defaults is not None:
155
+ __new__.__defaults__ = defaults
156
+
157
+ @classmethod
158
+ def _make(cls, iterable):
159
+ result = tuple_new(cls, iterable)
160
+ if _len(result) != num_arrange_fields:
161
+ raise TypeError(f'Expected {num_arrange_fields} arguments, got {len(result)}')
162
+ return result
163
+
164
+ _make.__func__.__doc__ = (f'Make a new {typename} object from a sequence '
165
+ 'or iterable')
166
+
167
+ def _replace(self, /, **kwds):
168
+ def generator():
169
+ for name in field_names:
170
+ if name in kwds:
171
+ yield kwds.pop(name)
172
+ else:
173
+ yield getattr(self, name)
174
+
175
+ result = self._make(iter(generator()))
176
+ if kwds:
177
+ raise ValueError(f'Got unexpected field names: {list(kwds)!r}')
178
+ return result
179
+
180
+ _replace.__doc__ = (f'Return a new {typename} object replacing specified '
181
+ 'fields with new values')
182
+
183
+ def __repr__(self):
184
+ 'Return a nicely formatted representation string'
185
+ return self.__class__.__name__ + repr_fmt % self
186
+
187
+ def _asdict(self):
188
+ 'Return a new dict which maps field names to their values.'
189
+ return _dict(_zip(arrange_names, self))
190
+
191
+ def __getnewargs__(self):
192
+ 'Return self as a plain tuple. Used by copy and pickle.'
193
+ return _tuple(self)
194
+
195
+ @swizzle_attributes_retriever(separator=seperator, type = swizzledtuple)
196
+ def __getattribute__(self, attr_name):
197
+ return super(_tuple, self).__getattribute__(attr_name)
198
+
199
+
200
+
201
+ for method in (
202
+ __new__,
203
+ _make.__func__,
204
+ _replace,
205
+ __repr__,
206
+ _asdict,
207
+ __getnewargs__,
208
+ __getattribute__,
209
+ ):
210
+ method.__qualname__ = f'{typename}.{method.__name__}'
211
+
212
+ class_namespace = {
213
+ '__doc__': f'{typename}({arg_list})',
214
+ '__slots__': (),
215
+ '_fields': field_names,
216
+ '_field_defaults': field_defaults,
217
+ '__new__': __new__,
218
+ '_make': _make,
219
+ '_replace': _replace,
220
+ '__repr__': __repr__,
221
+ '_asdict': _asdict,
222
+ '__getnewargs__': __getnewargs__,
223
+ '__getattribute__': __getattribute__
224
+ }
225
+ seen = set()
226
+ for index, name in enumerate(arrange_names):
227
+ if name in seen:
228
+ continue
229
+ doc = _sys.intern(f'Alias for field number {index}')
230
+ class_namespace[name] = _tuplegetter(index, doc)
231
+ seen.add(name)
232
+
233
+ result = type(typename, (tuple,), class_namespace)
234
+
235
+ if module is None:
236
+ try:
237
+ module = _sys._getframemodulename(1) or '__main__'
238
+ except AttributeError:
239
+ try:
240
+ module = _sys._getframe(1).f_globals.get('__name__', '__main__')
241
+ except (AttributeError, ValueError):
242
+ pass
243
+ if module is not None:
244
+ result.__module__ = module
245
+
246
+ return result
247
+
248
+ # deprecated name
249
+ def swizzlednamedtuple(typename, field_names, *, rename=False, defaults=None, module=None, arrange_names = None, seperator = None):
250
+ warnings.warn("swizzlednamedtuple is deprecated, use swizzledtuple instead", DeprecationWarning, stacklevel=2)
251
+ return swizzledtuple(typename, field_names, rename=rename, defaults=defaults, module=module, arrange_names=arrange_names, seperator=seperator)
252
+
253
+
254
+ # Helper function to split a string based on a separator
255
+ def split_string(string, separator):
256
+ if separator == '':
257
+ return list(string)
258
+ else:
259
+ return string.split(separator)
260
+
261
+ # Helper function to collect attribute retrieval functions from a class or meta-class
262
+ def collect_attribute_functions(cls):
263
+ funcs = []
264
+ if hasattr(cls, '__getattribute__'):
265
+ funcs.append(cls.__getattribute__)
266
+ if hasattr(cls, '__getattr__'):
267
+ funcs.append(cls.__getattr__)
268
+ if not funcs:
269
+ raise AttributeError("No __getattr__ or __getattribute__ found on the class or meta-class")
270
+ return funcs
271
+
272
+ # Function to combine multiple attribute retrieval functions
273
+
274
+ def swizzle_attributes_retriever(attribute_funcs=None, separator=None, type = tuple):
275
+ def _swizzle_attributes_retriever(attribute_funcs):
276
+ if not isinstance(attribute_funcs, list):
277
+ attribute_funcs = [attribute_funcs]
278
+
279
+ def retrieve_attribute(obj, attr_name):
280
+ for func in attribute_funcs:
281
+ try:
282
+ return func(obj, attr_name)
283
+ except AttributeError:
284
+ continue
285
+ return MISSING
286
+
287
+ @wraps(attribute_funcs[-1])
288
+ def retrieve_swizzled_attributes(obj, attr_name):
289
+ # Attempt to find an exact attribute match
290
+ attribute = retrieve_attribute(obj, attr_name)
291
+ if attribute is not MISSING:
292
+ return attribute
293
+
294
+ matched_attributes = []
295
+ arranged_names = []
296
+ # If a separator is provided, split the name accordingly
297
+ if separator is not None:
298
+ attr_parts = split_string(attr_name, separator)
299
+ arranged_names = attr_parts
300
+ for part in attr_parts:
301
+ attribute = retrieve_attribute(obj, part)
302
+ if attribute is not MISSING:
303
+ matched_attributes.append(attribute)
304
+ else:
305
+ # No separator provided, attempt to match substrings
306
+ i = 0
307
+ while i < len(attr_name):
308
+ match_found = False
309
+ for j in range(len(attr_name), i, -1):
310
+ substring = attr_name[i:j]
311
+ attribute = retrieve_attribute(obj, substring)
312
+ if attribute is not MISSING:
313
+ matched_attributes.append(attribute)
314
+ arranged_names.append(substring)
315
+ i = j # Move index to end of the matched substring
316
+ match_found = True
317
+ break
318
+ if not match_found:
319
+ raise AttributeError(f"No matching attribute found for substring: {attr_name[i:]}")
320
+
321
+ if type == swizzledtuple or type == swizzlednamedtuple:
322
+ field_names = set(arranged_names)
323
+ field_values = [retrieve_attribute(obj, name) for name in field_names]
324
+ name = "swizzledtuple"
325
+ if hasattr(obj, "__name__"):
326
+ name = obj.__name__
327
+ elif hasattr(obj, "__class__"):
328
+ if hasattr(obj.__class__, "__name__"):
329
+ name = obj.__class__.__name__
330
+ result = type(name, field_names, arrange_names=arranged_names)
331
+ result = result(*field_values)
332
+ return result
333
+
334
+
335
+ return type(matched_attributes)
336
+
337
+ return retrieve_swizzled_attributes
338
+
339
+ if attribute_funcs is not None:
340
+ return _swizzle_attributes_retriever(attribute_funcs)
341
+ else:
342
+ return _swizzle_attributes_retriever
343
+
344
+ # Decorator function to enable swizzling for a class
345
+ def swizzle(cls=None, meta=False, separator=None, type = tuple, **kwargs):
346
+
347
+ if 'use_meta' in kwargs:
348
+ warnings.warn("The 'use_meta' argument is deprecated and will be removed in a future version. Use 'meta' instead.", DeprecationWarning, stacklevel=2)
349
+ meta = kwargs.pop('use_meta')
350
+ if '_type' in kwargs:
351
+ warnings.warn("The '_type' argument is deprecated and will be removed in a future version. Use 'type' instead.", DeprecationWarning, stacklevel=2)
352
+ type = kwargs.pop('_type')
353
+
354
+ _type = builtins.type
355
+
356
+ def class_decorator(cls):
357
+ # Collect attribute retrieval functions from the class
358
+ attribute_funcs = collect_attribute_functions(cls)
359
+
360
+ # Apply the swizzling to the class's attribute retrieval
361
+ setattr(cls, attribute_funcs[-1].__name__, swizzle_attributes_retriever(attribute_funcs, separator, type))
362
+
363
+ # Handle meta-class swizzling if requested
364
+ if meta:
365
+ print(cls)
366
+ meta_cls = _type(cls)
367
+ if meta_cls == _type:
368
+ class SwizzledMetaType(meta_cls):
369
+ pass
370
+ meta_cls = SwizzledMetaType
371
+ cls = meta_cls(cls.__name__, cls.__bases__, dict(cls.__dict__))
372
+ meta_cls = SwizzledMetaType
373
+ cls = meta_cls(cls.__name__, cls.__bases__, dict(cls.__dict__))
374
+
375
+ meta_funcs = collect_attribute_functions(meta_cls)
376
+ setattr(meta_cls, meta_funcs[-1].__name__, swizzle_attributes_retriever(meta_funcs, separator, type))
377
+
378
+ return cls
379
+
380
+ if cls is None:
381
+ return class_decorator
382
+ else:
383
+ return class_decorator(cls)
384
+
385
+
386
+ class Swizzle(types.ModuleType):
387
+ def __init__(self):
388
+ types.ModuleType.__init__(self, __name__)
389
+ self.__dict__.update(_sys.modules[__name__].__dict__)
390
+
391
+ def __call__(self, cls=None, meta=False, sep = None, type = swizzledtuple):
392
+ return swizzle(cls, meta, sep, type)
393
+
394
+ _sys.modules[__name__] = Swizzle()
@@ -0,0 +1,128 @@
1
+ Metadata-Version: 2.1
2
+ Name: swizzle
3
+ Version: 2.1.0
4
+ Summary: Swizzle enables the retrieval of multiple attributes, similar to swizzling in computer graphics.
5
+ Home-page: https://github.com/janthmueller/swizzle
6
+ Author: Jan T. Müller
7
+ Author-email: mail@jantmueller.com
8
+ License: MIT
9
+ Project-URL: Documentation, https://github.com/janthmueller/swizzle/blob/main/README.md
10
+ Project-URL: Source, https://github.com/janthmueller/swizzle
11
+ Project-URL: Tracker, https://github.com/janthmueller/swizzle/issues
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Requires-Python: >=3.6
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+
21
+ # Swizzle
22
+ [![PyPI version](https://badge.fury.io/py/swizzle.svg?kill_cache=1)](https://badge.fury.io/py/swizzle)
23
+ [![Downloads](https://pepy.tech/badge/swizzle?kill_cache=1)](https://pepy.tech/project/swizzle)
24
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/janthmueller/swizzle/blob/main/LICENSE)
25
+ [![GitHub Stars](https://img.shields.io/github/stars/janthmueller/swizzle.svg?kill_cache=1)](https://github.com/janthmueller/swizzle/stargazers)
26
+
27
+ **Swizzle** for Python enhances attribute lookup methods to facilitate dynamic and flexible retrieval of multiple attributes based on specified arrangements of their names.
28
+ > **Update v2:**
29
+ > Introducing `swizzledtuple` , a new function that allows you to create swizzled named tuples. This feature is inspired by the `namedtuple` function from the [collections module](https://docs.python.org/3/library/collections.html#collections.namedtuple) and provides a concise way to define swizzled tuples.
30
+ > ```python
31
+ > from swizzle import swizzledtuple
32
+ >
33
+ > Vector = swizzledtuple('Vector', 'x y z', arrange_names = "y z x x")
34
+ >
35
+ > # Test the swizzle
36
+ > v = Vector(1, 2, 3)
37
+ > print(v) # Output: Vector(y=2, z=3, x=1, x=1)
38
+ > print(v.yzx) # Output: Vector(y = 2, z = 3, x = 1)
39
+ > print(v.yzx.xxzyzz) # Output: Vector(x=1, x=1, z=3, y=2, z=3, z=3)
40
+ >```
41
+
42
+ ### Swizzle Decorator:
43
+
44
+ ```python
45
+ import swizzle
46
+
47
+ @swizzle
48
+ class Vector:
49
+ def __init__(self, x, y, z):
50
+ self.x = x
51
+ self.y = y
52
+ self.z = z
53
+
54
+ # Test the swizzle
55
+ print(Vector(1, 2, 3).yzx) # Output: Vector(y = 2, z = 3, x = 1)
56
+ ```
57
+
58
+
59
+ ## Installation
60
+ ### From PyPI
61
+ ```bash
62
+ pip install swizzle
63
+ ```
64
+ ### From GitHub
65
+ ```bash
66
+ pip install git+https://github.com/janthmueller/swizzle.git
67
+ ```
68
+
69
+ ## Further Examples
70
+
71
+ ### Using `swizzle` with `dataclass`
72
+
73
+ ```python
74
+ import swizzle
75
+ from dataclasses import dataclass
76
+
77
+ @swizzle
78
+ @dataclass
79
+ class Vector:
80
+ x: int
81
+ y: int
82
+ z: int
83
+
84
+ # Test the swizzle
85
+ print(Vector(1, 2, 3).yzx) # Output: Vector(y = 2, z = 3, x = 1)
86
+ ```
87
+
88
+ ### Using `swizzle` with `IntEnum`
89
+
90
+ ```python
91
+ import swizzle
92
+ from enum import IntEnum
93
+
94
+ @swizzle(meta=True)
95
+ class Vector(IntEnum):
96
+ X = 1
97
+ Y = 2
98
+ Z = 3
99
+
100
+ # Test the swizzle
101
+ print(Vector.YXZ) # Output: Vector(Y=<Vector.Y: 2>, X=<Vector.X: 1>, Z=<Vector.Z: 3>)
102
+ ```
103
+ 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.
104
+
105
+
106
+ ### Sequential matching
107
+ Attributes are matched from left to right, starting with the longest substring match. This behavior can be controlled by the `seperator` argument in the swizzle decorator.
108
+ ```python
109
+ import swizzle
110
+
111
+ @swizzle(meta=True)
112
+ class Vector:
113
+ x = 1
114
+ y = 2
115
+ z = 3
116
+ xy = 4
117
+ yz = 5
118
+ xz = 6
119
+ xyz = 7
120
+
121
+ # Test the swizzle
122
+ print(Vector.xz) # Output: 6
123
+ print(Vector.yz) # Output: 5
124
+ print(Vector.xyyz) # Output: Vector(xy=4, yz=5)
125
+ print(Vector.xyzx) # Output: Vector(xyz=7, x=1)
126
+ ```
127
+
128
+
@@ -1,3 +1,4 @@
1
+ LICENSE
1
2
  README.md
2
3
  setup.py
3
4
  swizzle/__init__.py
swizzle-1.0.0/PKG-INFO DELETED
@@ -1,125 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: swizzle
3
- Version: 1.0.0
4
- Summary: The Swizzle Decorator enables the retrieval of multiple attributes, similar to swizzling in computer graphics.
5
- Home-page: https://github.com/janthmueller/swizzle
6
- Author: Jan T. Müller
7
- Author-email: mail@jantmueller.com
8
- License: MIT
9
- Project-URL: Documentation, https://github.com/janthmueller/swizzle/blob/main/README.md
10
- Project-URL: Source, https://github.com/janthmueller/swizzle
11
- Project-URL: Tracker, https://github.com/janthmueller/swizzle/issues
12
- Classifier: Intended Audience :: Developers
13
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
14
- Classifier: License :: OSI Approved :: MIT License
15
- Classifier: Operating System :: OS Independent
16
- Classifier: Programming Language :: Python :: 3 :: Only
17
- Requires-Python: >=3.6
18
- Description-Content-Type: text/markdown
19
-
20
- # Swizzle Decorator
21
-
22
- The **Swizzle Decorator** for Python enhances attribute lookup methods (`__getattr__` or `__getattribute__`) to facilitate dynamic and flexible retrieval of multiple attributes based on specified arrangements of their names. This concept is reminiscent of swizzling in computer graphics, where it allows efficient access to components of vectors or coordinates in various orders:
23
-
24
- ```python
25
- import swizzle
26
-
27
- @swizzle
28
- class Vector:
29
- def __init__(self, x, y, z):
30
- self.x = x
31
- self.y = y
32
- self.z = z
33
-
34
- print(Vector(1, 2, 3).yzx) # Output: (2, 3, 1)
35
- ```
36
-
37
- ## Installation
38
- ### From PyPI
39
- ```bash
40
- pip install swizzle
41
- ```
42
- ### From GitHub
43
- ```bash
44
- pip install git+https://github.com/janthmueller/swizzle.git
45
- ```
46
-
47
- ## Further Examples
48
-
49
- ### Using `swizzle` with `dataclass`
50
-
51
- ```python
52
- import swizzle
53
- from dataclasses import dataclass
54
-
55
- @swizzle
56
- @dataclass
57
- class XYZ:
58
- x: int
59
- y: int
60
- z: int
61
-
62
- # Test the swizzle
63
- xyz = XYZ(1, 2, 3)
64
- print(xyz.yzx) # Output: (2, 3, 1)
65
- ```
66
-
67
- ### Using `swizzle` with `IntEnum`
68
-
69
- ```python
70
- import swizzle
71
- from enum import IntEnum
72
-
73
- @swizzle(meta=True)
74
- class XYZ(IntEnum):
75
- X = 1
76
- Y = 2
77
- Z = 3
78
-
79
- # Test the swizzle
80
- print(XYZ.YXZ) # Output: (<XYZ.Y: 2>, <XYZ.X: 1>, <XYZ.Z: 3>)
81
- ```
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
-
84
- ### Using `swizzle` with `NamedTuple`
85
-
86
- ```python
87
- import swizzle
88
- from typing import NamedTuple
89
-
90
- @swizzle
91
- class XYZ(NamedTuple):
92
- x: int
93
- y: int
94
- z: int
95
-
96
- # Test the swizzle
97
- xyz = XYZ(1, 2, 3)
98
- print(xyz.yzx) # Output: (2, 3, 1)
99
- ```
100
-
101
-
102
- ### Sequential matching
103
- Attributes are matched from left to right, starting with the longest substring match.
104
- ```python
105
- import swizzle
106
-
107
- @swizzle(meta=True)
108
- class Test:
109
- x = 1
110
- y = 2
111
- z = 3
112
- xy = 4
113
- yz = 5
114
- xz = 6
115
- xyz = 7
116
-
117
- # Test the swizzle
118
- print(Test.xz) # Output: 6
119
- print(Test.yz) # Output: 5
120
- print(Test.xyyz) # Output: (4, 5)
121
- print(Test.xyzx) # Output: (7, 1)
122
- ```
123
-
124
- ## To Do
125
- - [ ] Swizzle for method args (swizzle+partial)
swizzle-1.0.0/README.md DELETED
@@ -1,106 +0,0 @@
1
- # Swizzle Decorator
2
-
3
- The **Swizzle Decorator** for Python enhances attribute lookup methods (`__getattr__` or `__getattribute__`) to facilitate dynamic and flexible retrieval of multiple attributes based on specified arrangements of their names. This concept is reminiscent of swizzling in computer graphics, where it allows efficient access to components of vectors or coordinates in various orders:
4
-
5
- ```python
6
- import swizzle
7
-
8
- @swizzle
9
- class Vector:
10
- def __init__(self, x, y, z):
11
- self.x = x
12
- self.y = y
13
- self.z = z
14
-
15
- print(Vector(1, 2, 3).yzx) # Output: (2, 3, 1)
16
- ```
17
-
18
- ## Installation
19
- ### From PyPI
20
- ```bash
21
- pip install swizzle
22
- ```
23
- ### From GitHub
24
- ```bash
25
- pip install git+https://github.com/janthmueller/swizzle.git
26
- ```
27
-
28
- ## Further Examples
29
-
30
- ### Using `swizzle` with `dataclass`
31
-
32
- ```python
33
- import swizzle
34
- from dataclasses import dataclass
35
-
36
- @swizzle
37
- @dataclass
38
- class XYZ:
39
- x: int
40
- y: int
41
- z: int
42
-
43
- # Test the swizzle
44
- xyz = XYZ(1, 2, 3)
45
- print(xyz.yzx) # Output: (2, 3, 1)
46
- ```
47
-
48
- ### Using `swizzle` with `IntEnum`
49
-
50
- ```python
51
- import swizzle
52
- from enum import IntEnum
53
-
54
- @swizzle(meta=True)
55
- class XYZ(IntEnum):
56
- X = 1
57
- Y = 2
58
- Z = 3
59
-
60
- # Test the swizzle
61
- print(XYZ.YXZ) # Output: (<XYZ.Y: 2>, <XYZ.X: 1>, <XYZ.Z: 3>)
62
- ```
63
- 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.
64
-
65
- ### Using `swizzle` with `NamedTuple`
66
-
67
- ```python
68
- import swizzle
69
- from typing import NamedTuple
70
-
71
- @swizzle
72
- class XYZ(NamedTuple):
73
- x: int
74
- y: int
75
- z: int
76
-
77
- # Test the swizzle
78
- xyz = XYZ(1, 2, 3)
79
- print(xyz.yzx) # Output: (2, 3, 1)
80
- ```
81
-
82
-
83
- ### Sequential matching
84
- Attributes are matched from left to right, starting with the longest substring match.
85
- ```python
86
- import swizzle
87
-
88
- @swizzle(meta=True)
89
- class Test:
90
- x = 1
91
- y = 2
92
- z = 3
93
- xy = 4
94
- yz = 5
95
- xz = 6
96
- xyz = 7
97
-
98
- # Test the swizzle
99
- print(Test.xz) # Output: 6
100
- print(Test.yz) # Output: 5
101
- print(Test.xyyz) # Output: (4, 5)
102
- print(Test.xyzx) # Output: (7, 1)
103
- ```
104
-
105
- ## To Do
106
- - [ ] Swizzle for method args (swizzle+partial)
@@ -1,112 +0,0 @@
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,125 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: swizzle
3
- Version: 1.0.0
4
- Summary: The Swizzle Decorator enables the retrieval of multiple attributes, similar to swizzling in computer graphics.
5
- Home-page: https://github.com/janthmueller/swizzle
6
- Author: Jan T. Müller
7
- Author-email: mail@jantmueller.com
8
- License: MIT
9
- Project-URL: Documentation, https://github.com/janthmueller/swizzle/blob/main/README.md
10
- Project-URL: Source, https://github.com/janthmueller/swizzle
11
- Project-URL: Tracker, https://github.com/janthmueller/swizzle/issues
12
- Classifier: Intended Audience :: Developers
13
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
14
- Classifier: License :: OSI Approved :: MIT License
15
- Classifier: Operating System :: OS Independent
16
- Classifier: Programming Language :: Python :: 3 :: Only
17
- Requires-Python: >=3.6
18
- Description-Content-Type: text/markdown
19
-
20
- # Swizzle Decorator
21
-
22
- The **Swizzle Decorator** for Python enhances attribute lookup methods (`__getattr__` or `__getattribute__`) to facilitate dynamic and flexible retrieval of multiple attributes based on specified arrangements of their names. This concept is reminiscent of swizzling in computer graphics, where it allows efficient access to components of vectors or coordinates in various orders:
23
-
24
- ```python
25
- import swizzle
26
-
27
- @swizzle
28
- class Vector:
29
- def __init__(self, x, y, z):
30
- self.x = x
31
- self.y = y
32
- self.z = z
33
-
34
- print(Vector(1, 2, 3).yzx) # Output: (2, 3, 1)
35
- ```
36
-
37
- ## Installation
38
- ### From PyPI
39
- ```bash
40
- pip install swizzle
41
- ```
42
- ### From GitHub
43
- ```bash
44
- pip install git+https://github.com/janthmueller/swizzle.git
45
- ```
46
-
47
- ## Further Examples
48
-
49
- ### Using `swizzle` with `dataclass`
50
-
51
- ```python
52
- import swizzle
53
- from dataclasses import dataclass
54
-
55
- @swizzle
56
- @dataclass
57
- class XYZ:
58
- x: int
59
- y: int
60
- z: int
61
-
62
- # Test the swizzle
63
- xyz = XYZ(1, 2, 3)
64
- print(xyz.yzx) # Output: (2, 3, 1)
65
- ```
66
-
67
- ### Using `swizzle` with `IntEnum`
68
-
69
- ```python
70
- import swizzle
71
- from enum import IntEnum
72
-
73
- @swizzle(meta=True)
74
- class XYZ(IntEnum):
75
- X = 1
76
- Y = 2
77
- Z = 3
78
-
79
- # Test the swizzle
80
- print(XYZ.YXZ) # Output: (<XYZ.Y: 2>, <XYZ.X: 1>, <XYZ.Z: 3>)
81
- ```
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
-
84
- ### Using `swizzle` with `NamedTuple`
85
-
86
- ```python
87
- import swizzle
88
- from typing import NamedTuple
89
-
90
- @swizzle
91
- class XYZ(NamedTuple):
92
- x: int
93
- y: int
94
- z: int
95
-
96
- # Test the swizzle
97
- xyz = XYZ(1, 2, 3)
98
- print(xyz.yzx) # Output: (2, 3, 1)
99
- ```
100
-
101
-
102
- ### Sequential matching
103
- Attributes are matched from left to right, starting with the longest substring match.
104
- ```python
105
- import swizzle
106
-
107
- @swizzle(meta=True)
108
- class Test:
109
- x = 1
110
- y = 2
111
- z = 3
112
- xy = 4
113
- yz = 5
114
- xz = 6
115
- xyz = 7
116
-
117
- # Test the swizzle
118
- print(Test.xz) # Output: 6
119
- print(Test.yz) # Output: 5
120
- print(Test.xyyz) # Output: (4, 5)
121
- print(Test.xyzx) # Output: (7, 1)
122
- ```
123
-
124
- ## To Do
125
- - [ ] Swizzle for method args (swizzle+partial)
File without changes