mm-std 0.3.29__py3-none-any.whl → 0.3.30__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.
mm_std/data_result.py CHANGED
@@ -10,41 +10,33 @@ T = TypeVar("T")
10
10
  U = TypeVar("U")
11
11
 
12
12
 
13
+ type Data = dict[str, object] | None
14
+
15
+
13
16
  class DataResult(Generic[T]):
14
17
  """
15
18
  A result wrapper that encapsulates either a successful result (`ok`) or an error message (`err`).
16
- Optionally carries auxiliary `data` field regardless of success or failure.
19
+ Optionally carries `data` field regardless of success or failure.
17
20
  """
18
21
 
19
- def __init__(
20
- self,
21
- ok: T | None = None,
22
- err: str | None = None,
23
- data: object = None,
24
- ok_is_none: bool = False, # Allow None as a valid success value
25
- ) -> None:
26
- # Sanity check: at least one of ok or err must be provided, unless explicitly allowed via `ok_is_none`
27
- if ok is None and err is None and not ok_is_none:
28
- raise ValueError("Either ok or err must be set")
29
- # You can't set both ok and err unless ok_is_none is True (used to explicitly accept None as success)
30
- if (ok_is_none or ok is not None) and err is not None:
31
- raise ValueError("Cannot set both ok and err")
32
-
33
- self.ok = ok
34
- self.err = err
35
- self.data = data
22
+ _ok: T | None
23
+ _err: str | None
24
+ data: Data | None
25
+
26
+ def __init__(self) -> None:
27
+ raise RuntimeError("DataResult is not intended to be instantiated directly. Use the static methods instead.")
36
28
 
37
29
  def is_ok(self) -> bool:
38
30
  """
39
31
  Returns True if the result represents a success.
40
32
  """
41
- return self.err is None
33
+ return self._err is None
42
34
 
43
35
  def is_err(self) -> bool:
44
36
  """
45
37
  Returns True if the result represents an error.
46
38
  """
47
- return self.err is not None
39
+ return self._err is not None
48
40
 
49
41
  def unwrap(self) -> T:
50
42
  """
@@ -52,7 +44,7 @@ class DataResult(Generic[T]):
52
44
  """
53
45
  if self.is_err():
54
46
  raise RuntimeError(f"Called `unwrap()` on an `Err` value: {self.err!r}")
55
- return cast(T, self.ok)
47
+ return cast(T, self._ok)
56
48
 
57
49
  def unwrap_ok_or(self, default: T) -> T:
58
50
  """
@@ -66,7 +58,7 @@ class DataResult(Generic[T]):
66
58
  The success value or the default value.
67
59
  """
68
60
  if self.is_ok():
69
- return cast(T, self.ok)
61
+ return cast(T, self._ok)
70
62
  return default
71
63
 
72
64
  def unwrap_err(self) -> str:
@@ -75,13 +67,13 @@ class DataResult(Generic[T]):
75
67
  """
76
68
  if self.is_ok():
77
69
  raise RuntimeError(f"Called `unwrap_err()` on an `Ok` value: {self.ok!r}")
78
- return cast(str, self.err)
70
+ return cast(str, self._err)
79
71
 
80
72
  def dict(self) -> dict[str, object]:
81
73
  """
82
74
  Returns a dictionary representation of the result.
83
75
  """
84
- return {"ok": self.ok, "err": self.err, "data": self.data}
76
+ return {"ok": self._ok, "err": self._err, "data": self.data}
85
77
 
86
78
  def map(self, fn: Callable[[T], U]) -> DataResult[U]:
87
79
  """
@@ -96,13 +88,13 @@ class DataResult(Generic[T]):
96
88
  A new DataResult with the transformed success value or an error.
97
89
  """
98
90
  if self.is_err():
99
- return DataResult[U](err=self.err, data=self.data)
91
+ return DataResult[U].err(self.unwrap_err(), self.data)
100
92
 
101
93
  try:
102
94
  mapped_ok = fn(self.unwrap())
103
- return DataResult[U](ok=mapped_ok, data=self.data)
95
+ return DataResult[U].ok(mapped_ok, self.data)
104
96
  except Exception as e:
105
- return DataResult[U](err=f"Error in map: {e!s}", data={"original_data": self.data, "original_ok": self.ok})
97
+ return DataResult[U].exception(e, data={"original_data": self.data, "original_ok": self.ok})
106
98
 
107
99
  async def map_async(self, fn: Callable[[T], Awaitable[U]]) -> DataResult[U]:
108
100
  """
@@ -117,13 +109,13 @@ class DataResult(Generic[T]):
117
109
  A new DataResult with the transformed success value or an error.
118
110
  """
119
111
  if self.is_err():
120
- return DataResult[U](err=self.err, data=self.data)
112
+ return DataResult[U].err(self.unwrap_err(), self.data)
121
113
 
122
114
  try:
123
115
  mapped_ok = await fn(self.unwrap())
124
- return DataResult[U](ok=mapped_ok, data=self.data)
116
+ return DataResult[U].ok(mapped_ok, self.data)
125
117
  except Exception as e:
126
- return DataResult[U](err=f"Error in map_async: {e!s}", data={"original_data": self.data, "original_ok": self.ok})
118
+ return DataResult[U].exception(e, data={"original_data": self.data, "original_ok": self.ok})
127
119
 
128
120
  def and_then(self, fn: Callable[[T], DataResult[U]]) -> DataResult[U]:
129
121
  """
@@ -139,12 +131,12 @@ class DataResult(Generic[T]):
139
131
  The result of the function application or the original error.
140
132
  """
141
133
  if self.is_err():
142
- return DataResult[U](err=self.err, data=self.data)
134
+ return DataResult[U].err(self.unwrap_err(), self.data)
143
135
 
144
136
  try:
145
137
  return fn(self.unwrap())
146
138
  except Exception as e:
147
- return DataResult[U](err=f"Error in and_then: {e!s}", data={"original_data": self.data, "original_ok": self.ok})
139
+ return DataResult[U].exception(e, data={"original_data": self.data, "original_ok": self.ok})
148
140
 
149
141
  async def and_then_async(self, fn: Callable[[T], Awaitable[DataResult[U]]]) -> DataResult[U]:
150
142
  """
@@ -160,18 +152,18 @@ class DataResult(Generic[T]):
160
152
  The result of the function application or the original error.
161
153
  """
162
154
  if self.is_err():
163
- return DataResult[U](err=self.err, data=self.data)
155
+ return DataResult[U].err(self.unwrap_err(), self.data)
164
156
 
165
157
  try:
166
158
  return await fn(self.unwrap())
167
159
  except Exception as e:
168
- return DataResult[U](err=f"Error in and_then_async: {e!s}", data={"original_data": self.data, "original_ok": self.ok})
160
+ return DataResult[U].exception(e, {"original_data": self.data, "original_ok": self.ok})
169
161
 
170
162
  def __repr__(self) -> str:
171
163
  """
172
164
  Returns the debug representation of the result.
173
165
  """
174
- result = f"DataResult(ok={self.ok!r}" if self.is_ok() else f"DataResult(err={self.err!r}"
166
+ result = f"DataResult(ok={self._ok!r}" if self.is_ok() else f"DataResult(err={self._err!r}"
175
167
  if self.data is not None:
176
168
  result += f", data={self.data!r}"
177
169
  return result + ")"
@@ -188,7 +180,7 @@ class DataResult(Generic[T]):
188
180
  """
189
181
  if not isinstance(other, DataResult):
190
182
  return NotImplemented
191
- return self.ok == other.ok and self.err == other.err and self.data == other.data
183
+ return self._ok == other._ok and self._err == other._err and self.data == other.data
192
184
 
193
185
  @classmethod
194
186
  def __get_pydantic_core_schema__(cls, _source_type: type[Any], _handler: GetCoreSchemaHandler) -> CoreSchema:
@@ -210,9 +202,48 @@ class DataResult(Generic[T]):
210
202
  if isinstance(v, cls):
211
203
  return v
212
204
  if isinstance(v, dict):
213
- return cls(
205
+ return cls._create(
214
206
  ok=v.get("ok"),
215
207
  err=v.get("err"),
216
208
  data=v.get("data"),
217
209
  )
218
210
  raise TypeError(f"Cannot parse value as {cls.__name__}: {v}")
211
+
212
+ @classmethod
213
+ def _create(cls, ok: T | None, err: str | None, data: Data) -> DataResult[T]:
214
+ """
215
+ Internal method to create a DataResult instance.
216
+ """
217
+ obj = object.__new__(cls)
218
+ obj._ok = ok # noqa: SLF001
219
+ obj._err = err # noqa: SLF001
220
+ obj.data = data
221
+ return obj
222
+
223
+ @staticmethod
224
+ def ok(value: T, data: Data = None) -> DataResult[T]:
225
+ """
226
+ Static method to create a successful DataResult.
227
+ """
228
+ return DataResult._create(ok=value, err=None, data=data)
229
+
230
+ @staticmethod
231
+ def err(error: str, data: Data = None) -> DataResult[T]:
232
+ """
233
+ Static method to create an error DataResult.
234
+ """
235
+ return DataResult._create(ok=None, err=error, data=data)
236
+
237
+ @staticmethod
238
+ def exception(err: Exception, data: Data = None) -> DataResult[T]:
239
+ """
240
+ Static method to create an error DataResult from an exception.
241
+ """
242
+ if data is None:
243
+ data = {}
244
+ key = "exception_message"
245
+ while key in data:
246
+ key += "_"
247
+ data[key] = str(err)
248
+
249
+ return DataResult._create(ok=None, err="exception", data=data)
mm_std/http/response.py CHANGED
@@ -41,7 +41,7 @@ class HttpResponse(BaseModel):
41
41
  return self.error is not None or (self.status_code is not None and self.status_code >= 400)
42
42
 
43
43
  def to_data_result_err[T](self, error: str | None = None) -> DataResult[T]:
44
- return DataResult(err=error or self.error or "error", data=self.model_dump())
44
+ return DataResult.err(error or self.error or "error", self.model_dump())
45
45
 
46
46
  def to_data_result_ok[T](self, result: T) -> DataResult[T]:
47
- return DataResult(ok=result, data=self.model_dump())
47
+ return DataResult.ok(result, self.model_dump())
@@ -1,10 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mm-std
3
- Version: 0.3.29
3
+ Version: 0.3.30
4
4
  Requires-Python: >=3.12
5
5
  Requires-Dist: aiohttp-socks~=0.10.1
6
6
  Requires-Dist: aiohttp~=3.11.16
7
7
  Requires-Dist: cryptography~=44.0.2
8
+ Requires-Dist: multidict~=6.4.3
8
9
  Requires-Dist: pydantic-settings>=2.8.1
9
10
  Requires-Dist: pydantic~=2.11.3
10
11
  Requires-Dist: pydash~=8.0.5
@@ -2,7 +2,7 @@ mm_std/__init__.py,sha256=ePkjykjImp2Wu10lFzK3Fl1HpGqqXFb_HZK_BSiU3MM,3316
2
2
  mm_std/command.py,sha256=ze286wjUjg0QSTgIu-2WZks53_Vclg69UaYYgPpQvCU,1283
3
3
  mm_std/config.py,sha256=4ox4D2CgGR76bvZ2n2vGQOYUDagFnlKEDb87to5zpxE,1871
4
4
  mm_std/crypto.py,sha256=jdk0_TCmeU0pPXMyz9xH6kQHSjjZ9GcGClBwQps5vBo,340
5
- mm_std/data_result.py,sha256=AMG6ttFTa9wxOS2U3kgPI2Z1shntdhF-7KxvfYYILoo,8104
5
+ mm_std/data_result.py,sha256=aUDhnxp5EagYFkCiOGKYReQshDrK_3zXfGYla5mJ8Yk,8739
6
6
  mm_std/date.py,sha256=976eEkSONuNqHQBgSRu8hrtH23tJqztbmHFHLdbP2TY,1879
7
7
  mm_std/dict.py,sha256=6GkhJPXD0LiJDxPcYe6jPdEDw-MN7P7mKu6U5XxwYDk,675
8
8
  mm_std/env.py,sha256=5zaR9VeIfObN-4yfgxoFeU5IM1GDeZZj9SuYf7t9sOA,125
@@ -28,7 +28,7 @@ mm_std/concurrency/sync_scheduler.py,sha256=j4tBL_cBI1spr0cZplTA7N2CoYsznuORMeRN
28
28
  mm_std/concurrency/sync_task_runner.py,sha256=s5JPlLYLGQGHIxy4oDS-PN7O9gcy-yPZFoNm8RQwzcw,1780
29
29
  mm_std/http/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
30
  mm_std/http/http_request.py,sha256=h74_ZjACwdbeINjzhuEwNUpvnaHZvyGl7TExjlBwMGg,3704
31
- mm_std/http/response.py,sha256=qEQYV_TkwttS9fVuQwNmyB9QtrwUsuLAcC7juVbyCAg,1387
32
- mm_std-0.3.29.dist-info/METADATA,sha256=ZZrqphz0r5EALNmkV3ysuqLCt8h5X_MxD3MSVSkLzLM,415
33
- mm_std-0.3.29.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
34
- mm_std-0.3.29.dist-info/RECORD,,
31
+ mm_std/http/response.py,sha256=WNQWd1HC134WvjEOSvikHCmujbsvs2332VzUPp9DnyM,1377
32
+ mm_std-0.3.30.dist-info/METADATA,sha256=wv2Gs6_yVnt-f58T01_Dt6-cP8btIij1MFm91G04xYM,447
33
+ mm_std-0.3.30.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
34
+ mm_std-0.3.30.dist-info/RECORD,,