python-dictattr 0.0.4__tar.gz → 0.0.5__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.
@@ -1,26 +1,28 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: python-dictattr
3
- Version: 0.0.4
3
+ Version: 0.0.5
4
4
  Summary: Python dictattr.
5
- Home-page: https://github.com/ChenyangGao/web-mount-packs/tree/main/python-module/python-dictattr
6
5
  License: MIT
6
+ License-File: LICENSE
7
7
  Keywords: dictattr,attrdict
8
8
  Author: ChenyangGao
9
9
  Author-email: wosiwujm@gmail.com
10
- Requires-Python: >=3.11,<4.0
10
+ Requires-Python: >=3.12,<4.0
11
11
  Classifier: Development Status :: 5 - Production/Stable
12
12
  Classifier: Intended Audience :: Developers
13
13
  Classifier: License :: OSI Approved :: MIT License
14
14
  Classifier: Operating System :: OS Independent
15
15
  Classifier: Programming Language :: Python
16
16
  Classifier: Programming Language :: Python :: 3
17
- Classifier: Programming Language :: Python :: 3.11
18
17
  Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
19
20
  Classifier: Programming Language :: Python :: 3 :: Only
20
21
  Classifier: Topic :: Software Development
21
22
  Classifier: Topic :: Software Development :: Libraries
22
23
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
- Project-URL: Repository, https://github.com/ChenyangGao/web-mount-packs/tree/main/python-module/python-dictattr
24
+ Project-URL: Homepage, https://github.com/ChenyangGao/python-modules/tree/main/python-dictattr
25
+ Project-URL: Repository, https://github.com/ChenyangGao/python-modules/tree/main/python-dictattr
24
26
  Description-Content-Type: text/markdown
25
27
 
26
28
  # Python dictattr.
@@ -0,0 +1,190 @@
1
+ #!/usr/bin/env python3
2
+ # encoding: utf-8
3
+
4
+ from __future__ import annotations
5
+
6
+ __author__ = "ChenyangGao <https://chenyanggao.github.io>"
7
+ __version__ = (0, 0, 5)
8
+ __all__ = [
9
+ "AttrDict", "MapAttr", "MuMapAttr", "DictAttr", "UserDictAttr", "ChainUserDictAttr",
10
+ "IntMapAttr", "IntMuMapAttr", "StrMapAttr", "StrMuMapAttr",
11
+ ]
12
+
13
+ from collections import UserDict
14
+ from collections.abc import Iterator, Mapping, MutableMapping
15
+ from typing import overload, Any, Self, Generic
16
+ from typing import _GenericAlias # type: ignore
17
+
18
+
19
+ class DictAttrMixin[K, V](MutableMapping[K, V]):
20
+
21
+ def __delattr__(self, name: K, /): # type: ignore
22
+ try:
23
+ del self[name]
24
+ except KeyError as e:
25
+ raise AttributeError(name) from e
26
+
27
+ def __getattr__(self, name: K, /) -> V: # type: ignore
28
+ try:
29
+ return self[name]
30
+ except KeyError as e:
31
+ raise AttributeError(name) from e
32
+
33
+ def __setattr__(self, name: K, value: V, /): # type: ignore
34
+ try:
35
+ self[name] = value
36
+ except KeyError as e:
37
+ raise AttributeError(name) from e
38
+
39
+
40
+ class MapAttrMixin[K, V](Mapping[K, V]):
41
+ __dict__: dict[K, V] # type: ignore
42
+
43
+ def __contains__(self, key, /) -> bool:
44
+ return key in self.__dict__
45
+
46
+ def __getitem__(self, key: K, /) -> V:
47
+ return self.__dict__[key]
48
+
49
+ def __iter__(self, /) -> Iterator[K]:
50
+ return iter(self.__dict__)
51
+
52
+ def __len__(self, /) -> int:
53
+ return len(self.__dict__)
54
+
55
+
56
+ class MuMapAttrMixin[K, V](MapAttrMixin[K, V], MutableMapping[K, V]):
57
+
58
+ def __delitem__(self, key: K, /):
59
+ del self.__dict__[key]
60
+
61
+ def __setitem__(self, key: K, val: V, /):
62
+ self.__dict__[key] = val
63
+
64
+
65
+ class ValueMapAttrMixin[K, V](MapAttrMixin[K, V]):
66
+
67
+ def __new__(cls, value=None, /, *args, **kwds):
68
+ if isinstance(value, (tuple, list, Mapping)):
69
+ args = value, *args
70
+ value = None
71
+ for a in args:
72
+ kwds.update(a)
73
+ if value is None:
74
+ value = kwds.get("id")
75
+ base: Any
76
+ for base in reversed(cls.__bases__):
77
+ if not (base is Generic or isinstance(base, _GenericAlias)):
78
+ break
79
+ self = base.__new__(cls, value or 0)
80
+ if kwds:
81
+ self.__dict__.update(kwds)
82
+ return self
83
+
84
+ def __repr__(self, /) -> str:
85
+ cls = type(self)
86
+ return f"{cls.__module__}.{cls.__qualname__}({super().__repr__()}, {self.__dict__!r})"
87
+
88
+
89
+ class ValueMuMapAttrMixin[K, V](ValueMapAttrMixin[K, V], MuMapAttrMixin[K, V]):
90
+ pass
91
+
92
+
93
+ class AttrDict[K, V](dict[K, V]):
94
+
95
+ def __init__(self, /, *args, **kwds):
96
+ super().__init__(*args, **kwds)
97
+ self.__dict__ = self # type: ignore
98
+
99
+
100
+ class MapAttr[K, V](MapAttrMixin[K, V]):
101
+
102
+ def __init__(self, /, *args, **kwds):
103
+ self.__dict__: dict[K, V] # type: ignore
104
+ self.__dict__.update(*args, **kwds)
105
+
106
+ def __repr__(self, /) -> str:
107
+ cls = type(self)
108
+ return f"{cls.__module__}.{cls.__qualname__}({self.__dict__})"
109
+
110
+ @classmethod
111
+ def of(
112
+ cls,
113
+ d: None | dict[K, V] = None,
114
+ /,
115
+ ) -> Self:
116
+ self = cls.__new__(cls)
117
+ if d is not None:
118
+ self.__dict__ = d
119
+ return self
120
+
121
+
122
+ class MuMapAttr[K, V](MapAttr[K, V], MuMapAttrMixin[K, V]):
123
+ pass
124
+
125
+
126
+ class DictAttr[K, V](DictAttrMixin[K, V], dict[K, V]):
127
+ pass
128
+
129
+
130
+ class UserDictAttr[K, V](DictAttrMixin[K, V], UserDict[K, V]):
131
+
132
+ def __getitem__(self, key, /):
133
+ d = super().__getitem__(key)
134
+ if isinstance(d, Mapping) and not isinstance(d, __class__): # type: ignore
135
+ return type(self)(d)
136
+ return d
137
+
138
+ def __repr__(self, /) -> str:
139
+ cls = type(self)
140
+ return f"{cls.__module__}.{cls.__qualname__}.of({self.data!r})"
141
+
142
+ @classmethod
143
+ def of(cls, m: Mapping, /) -> Self:
144
+ self = cls()
145
+ self.__dict__["data"] = m
146
+ return self
147
+
148
+
149
+ class ChainDictAttr[K, V](UserDictAttr[K, V | "ChainDictAttr"]):
150
+
151
+ def __getitem__(self, key, /) -> V | ChainDictAttr:
152
+ try:
153
+ return super().__getitem__(key)
154
+ except KeyError:
155
+ d = self.__dict__[key] = type(self)()
156
+ return d
157
+
158
+
159
+ class IntMapAttr[K, V](ValueMapAttrMixin[K, V], int):
160
+ pass
161
+
162
+
163
+ class IntMuMapAttr[K, V](ValueMuMapAttrMixin[K, V], int):
164
+ pass
165
+
166
+
167
+ class StrMapAttr[K, V](ValueMapAttrMixin[K, V], str):
168
+
169
+ @overload # type: ignore
170
+ def __getitem__(self, key: int | slice, /) -> str:
171
+ ...
172
+ @overload
173
+ def __getitem__(self, key: K, /) -> V:
174
+ ...
175
+ def __getitem__(self, key: int | slice | K, /) -> str | V:
176
+ if isinstance(key, (int, slice)):
177
+ return str.__getitem__(self, key)
178
+ else:
179
+ return self.__dict__[key]
180
+
181
+ def __iter__(self, /):
182
+ return str.__iter__(self)
183
+
184
+ def __len__(self, /):
185
+ return str.__len__(self)
186
+
187
+
188
+ class StrMuMapAttr[K, V](ValueMuMapAttrMixin[K, V], StrMapAttr[K, V], str):
189
+ pass
190
+
@@ -1,12 +1,12 @@
1
1
  [tool.poetry]
2
2
  name = "python-dictattr"
3
- version = "0.0.4"
3
+ version = "0.0.5"
4
4
  description = "Python dictattr."
5
5
  authors = ["ChenyangGao <wosiwujm@gmail.com>"]
6
6
  license = "MIT"
7
7
  readme = "readme.md"
8
- homepage = "https://github.com/ChenyangGao/web-mount-packs/tree/main/python-module/python-dictattr"
9
- repository = "https://github.com/ChenyangGao/web-mount-packs/tree/main/python-module/python-dictattr"
8
+ homepage = "https://github.com/ChenyangGao/python-modules/tree/main/python-dictattr"
9
+ repository = "https://github.com/ChenyangGao/python-modules/tree/main/python-dictattr"
10
10
  keywords = ["dictattr", "attrdict"]
11
11
  classifiers = [
12
12
  "License :: OSI Approved :: MIT License",
@@ -25,7 +25,7 @@ include = [
25
25
  ]
26
26
 
27
27
  [tool.poetry.dependencies]
28
- python = "^3.11"
28
+ python = "^3.12"
29
29
 
30
30
  [build-system]
31
31
  requires = ["poetry-core"]
@@ -1,179 +0,0 @@
1
- #!/usr/bin/env python3
2
- # encoding: utf-8
3
-
4
- from __future__ import annotations
5
-
6
- __author__ = "ChenyangGao <https://chenyanggao.github.io>"
7
- __version__ = (0, 0, 4)
8
- __all__ = [
9
- "odict", "AttrDict", "MapAttr", "MuMapAttr", "DictAttr",
10
- "ChainDictAttr", "UserDictAttr", "PriorityUserDictAttr",
11
- ]
12
-
13
- from collections import UserDict
14
- from collections.abc import Iterator, Mapping, MutableMapping
15
- from typing import Generic, Self, TypeVar
16
-
17
-
18
- K = TypeVar("K")
19
- V = TypeVar("V")
20
-
21
-
22
- class odict(dict[K, V]):
23
-
24
- __getattr__ = dict.__getitem__
25
- __setattr__ = dict.__setitem__ # type: ignore
26
- __delattr__ = dict.__delitem__ # type: ignore
27
-
28
- def __hash__(self, /) -> int: # type: ignore
29
- return id(self)
30
-
31
- def __eq__(self, value, /) -> bool:
32
- return self is value or super().__eq__(value)
33
-
34
-
35
- class AttrDict(dict[K, V]):
36
-
37
- def __init__(self, /, *args, **kwds):
38
- super().__init__(*args, **kwds)
39
- self.__dict__ = self # type: ignore
40
-
41
- def __hash__(self, /) -> int: # type: ignore
42
- return id(self)
43
-
44
- def __eq__(self, value, /) -> bool:
45
- return self is value or super().__eq__(value)
46
-
47
-
48
- @Mapping.register
49
- class MapAttr(Generic[K, V]):
50
-
51
- def __init__(self, /, *args, **kwds):
52
- self.__dict__: dict[K, V] # type: ignore
53
- self.__dict__.update(*args, **kwds)
54
-
55
- def __contains__(self, key, /) -> bool:
56
- return key in self.__dict__
57
-
58
- def __getitem__(self, key, /) -> V:
59
- return self.__dict__[key]
60
-
61
- def __iter__(self, /) -> Iterator[K]:
62
- return iter(self.__dict__)
63
-
64
- def __len__(self, /) -> int:
65
- return len(self.__dict__)
66
-
67
- def __repr__(self, /) -> str:
68
- cls = type(self)
69
- if (mod := cls.__module__) == "__main__":
70
- return f"{cls.__qualname__}({self.__dict__})"
71
- else:
72
- return f"{mod}.{cls.__qualname__}({self.__dict__})"
73
-
74
- @classmethod
75
- def of(
76
- cls,
77
- d: None | dict[K, V] = None,
78
- /,
79
- ) -> Self:
80
- if d is None:
81
- return cls()
82
- self = __class__.__new__(cls) # type: ignore
83
- self.__dict__ = d
84
- return self
85
-
86
-
87
- @MutableMapping.register
88
- class MuMapAttr(MapAttr[K, V]):
89
-
90
- def __delitem__(self, key, /):
91
- del self.__dict__[key]
92
-
93
- def __setitem__(self, key: K, val: V, /):
94
- self.__dict__[key] = val
95
-
96
-
97
- class DictAttr(MuMapAttr[K, V]):
98
-
99
- def __getattr__(self, attr, /):
100
- return getattr(self.__dict__, attr)
101
-
102
- def __getattribute__(self, attr, /):
103
- if attr == "__dict__":
104
- return super().__getattribute__(attr)
105
- try:
106
- return self[attr]
107
- except KeyError:
108
- return super().__getattribute__(attr)
109
-
110
- def __getitem__(self, key, /) -> V | Self: # type: ignore
111
- d = self.__dict__[key]
112
- if type(d) is dict:
113
- return type(self)(d)
114
- return d
115
-
116
-
117
- class ChainDictAttr(DictAttr[K, V | "ChainDictAttr"]):
118
-
119
- def __getitem__(self, key, /) -> V | ChainDictAttr:
120
- try:
121
- return super().__getitem__(key)
122
- except KeyError:
123
- d = self.__dict__[key] = type(self)()
124
- return d
125
-
126
-
127
- class UserDictAttr(UserDict):
128
-
129
- def __getattr__(self, attr, /):
130
- try:
131
- return self[attr]
132
- except KeyError as e:
133
- raise AttributeError(attr) from e
134
-
135
- def __getitem__(self, key, /):
136
- d = super().__getitem__(key)
137
- if isinstance(d, Mapping) and not isinstance(d, __class__): # type: ignore
138
- return type(self)(d)
139
- return d
140
-
141
- def __repr__(self, /) -> str:
142
- cls = type(self)
143
- name = cls.__qualname__
144
- if (module := cls.__module__) != "__main__":
145
- name = f"{module}.{name}"
146
- return f"{name}.of({self.data!r})"
147
-
148
- @classmethod
149
- def of(cls, m: Mapping, /) -> Self:
150
- self = cls()
151
- self.__dict__["data"] = m
152
- return self
153
-
154
-
155
- class PriorityUserDictAttr(UserDictAttr):
156
-
157
- def __delattr__(self, attr, /):
158
- try:
159
- del self[attr]
160
- except KeyError:
161
- super().__delattr__(attr)
162
-
163
- def __getattribute__(self, attr, /):
164
- if attr in ("__dict__", "data") or attr == f"__{attr.strip('_')}__":
165
- return super().__getattribute__(attr)
166
- try:
167
- return self[attr]
168
- except KeyError:
169
- return super().__getattribute__(attr)
170
-
171
- def __getattr__(self, attr, /):
172
- raise AttributeError(attr)
173
-
174
- def __setattr__(self, attr, val, /):
175
- if attr == "data" and "data" not in self.__dict__:
176
- self.__dict__["data"] = val
177
- else:
178
- self[attr] = val
179
-
File without changes