mm-std 0.3.27__py3-none-any.whl → 0.3.29__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
@@ -87,35 +87,85 @@ class DataResult(Generic[T]):
87
87
  """
88
88
  Transforms the success value using the provided function if this is a success result.
89
89
  If this is an error result, returns a new error result with the same error message.
90
+ If the function raises an exception, returns a new error result with the exception message.
90
91
 
91
92
  Args:
92
93
  fn: A function that transforms the success value from type T to type U.
93
94
 
94
95
  Returns:
95
- A new DataResult with the transformed success value or the original error.
96
+ A new DataResult with the transformed success value or an error.
96
97
  """
97
98
  if self.is_err():
98
99
  return DataResult[U](err=self.err, data=self.data)
99
100
 
100
- mapped_ok = fn(self.unwrap())
101
- return DataResult[U](ok=mapped_ok, data=self.data)
101
+ try:
102
+ mapped_ok = fn(self.unwrap())
103
+ return DataResult[U](ok=mapped_ok, data=self.data)
104
+ except Exception as e:
105
+ return DataResult[U](err=f"Error in map: {e!s}", data={"original_data": self.data, "original_ok": self.ok})
102
106
 
103
107
  async def map_async(self, fn: Callable[[T], Awaitable[U]]) -> DataResult[U]:
104
108
  """
105
109
  Asynchronously transforms the success value using the provided async function if this is a success result.
106
110
  If this is an error result, returns a new error result with the same error message.
111
+ If the function raises an exception, returns a new error result with the exception message.
107
112
 
108
113
  Args:
109
114
  fn: An async function that transforms the success value from type T to type U.
110
115
 
111
116
  Returns:
112
- A new DataResult with the transformed success value or the original error.
117
+ A new DataResult with the transformed success value or an error.
113
118
  """
114
119
  if self.is_err():
115
120
  return DataResult[U](err=self.err, data=self.data)
116
121
 
117
- mapped_ok = await fn(self.unwrap())
118
- return DataResult[U](ok=mapped_ok, data=self.data)
122
+ try:
123
+ mapped_ok = await fn(self.unwrap())
124
+ return DataResult[U](ok=mapped_ok, data=self.data)
125
+ 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})
127
+
128
+ def and_then(self, fn: Callable[[T], DataResult[U]]) -> DataResult[U]:
129
+ """
130
+ Applies the function to the success value if this is a success result.
131
+ If this is an error result, returns a new error result with the same error message.
132
+
133
+ Unlike map, the function must return a DataResult.
134
+
135
+ Args:
136
+ fn: A function that takes the success value and returns a new DataResult.
137
+
138
+ Returns:
139
+ The result of the function application or the original error.
140
+ """
141
+ if self.is_err():
142
+ return DataResult[U](err=self.err, data=self.data)
143
+
144
+ try:
145
+ return fn(self.unwrap())
146
+ 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})
148
+
149
+ async def and_then_async(self, fn: Callable[[T], Awaitable[DataResult[U]]]) -> DataResult[U]:
150
+ """
151
+ Asynchronously applies the function to the success value if this is a success result.
152
+ If this is an error result, returns a new error result with the same error message.
153
+
154
+ Unlike map_async, the function must return a DataResult.
155
+
156
+ Args:
157
+ fn: An async function that takes the success value and returns a new DataResult.
158
+
159
+ Returns:
160
+ The result of the function application or the original error.
161
+ """
162
+ if self.is_err():
163
+ return DataResult[U](err=self.err, data=self.data)
164
+
165
+ try:
166
+ return await fn(self.unwrap())
167
+ 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})
119
169
 
120
170
  def __repr__(self) -> str:
121
171
  """
@@ -74,7 +74,7 @@ async def _request_with_http_or_none_proxy(
74
74
  method, url, params=params, data=data, json=json, headers=headers, cookies=cookies, proxy=proxy, timeout=timeout
75
75
  ) as res:
76
76
  return HttpResponse(
77
- status=res.status,
77
+ status_code=res.status,
78
78
  error=None,
79
79
  error_message=None,
80
80
  body=(await res.read()).decode(),
@@ -102,7 +102,7 @@ async def _request_with_socks_proxy(
102
102
  ) as res,
103
103
  ):
104
104
  return HttpResponse(
105
- status=res.status,
105
+ status_code=res.status,
106
106
  error=None,
107
107
  error_message=None,
108
108
  body=(await res.read()).decode(),
mm_std/http/response.py CHANGED
@@ -3,8 +3,9 @@ import json
3
3
  from typing import Any
4
4
 
5
5
  import pydash
6
- from pydantic import GetCoreSchemaHandler
7
- from pydantic_core import CoreSchema, core_schema
6
+ from pydantic import BaseModel
7
+
8
+ from mm_std.data_result import DataResult
8
9
 
9
10
 
10
11
  @enum.unique
@@ -15,79 +16,32 @@ class HttpError(str, enum.Enum):
15
16
  ERROR = "error"
16
17
 
17
18
 
18
- class HttpResponse:
19
- def __init__(
20
- self,
21
- status: int | None = None,
22
- error: HttpError | None = None,
23
- error_message: str | None = None,
24
- body: str | None = None,
25
- headers: dict[str, str] | None = None,
26
- ) -> None:
27
- self.status = status
28
- self.error = error
29
- self.error_message = error_message
30
- self.body = body
31
- self.headers = headers
32
-
33
- self._json_data: Any = None
34
- self._json_parsed = False
35
- self._json_parsed_error = False
19
+ class HttpResponse(BaseModel):
20
+ status_code: int | None = None
21
+ error: HttpError | None = None
22
+ error_message: str | None = None
23
+ body: str | None = None
24
+ headers: dict[str, str] | None = None
36
25
 
37
- def _parse_json(self) -> None:
26
+ def parse_json_body(self, path: str | None = None, none_on_error: bool = False) -> Any: # noqa: ANN401
38
27
  if self.body is None:
39
- self._json_parsed_error = True
40
- return
28
+ if none_on_error:
29
+ return None
30
+ raise ValueError("Body is None")
31
+
41
32
  try:
42
- self._json_data = None
43
- self._json_data = json.loads(self.body)
44
- self._json_parsed_error = False
33
+ res = json.loads(self.body)
34
+ return pydash.get(res, path, None) if path else res
45
35
  except json.JSONDecodeError:
46
- self._json_parsed_error = True
47
- self._json_parsed = True
48
-
49
- def json(self, path: str | None = None) -> Any: # noqa: ANN401
50
- if not self._json_parsed:
51
- self._parse_json()
52
- if path:
53
- return pydash.get(self._json_data, path, None)
54
- return self._json_data
55
-
56
- def dict(self) -> dict[str, object]:
57
- return {
58
- "status": self.status,
59
- "error": self.error,
60
- "error_message": self.error_message,
61
- "body": self.body,
62
- "headers": self.headers,
63
- }
64
-
65
- def is_json_parse_error(self) -> bool:
66
- if not self._json_parsed:
67
- self._parse_json()
68
- return self._json_parsed_error
36
+ if none_on_error:
37
+ return None
38
+ raise
69
39
 
70
- def __repr__(self) -> str:
71
- return f"HttpResponse(status={self.status}, error={self.error}, error_message={self.error_message}, body={self.body}, headers={self.headers})" # noqa: E501
40
+ def is_error(self) -> bool:
41
+ return self.error is not None or (self.status_code is not None and self.status_code >= 400)
72
42
 
73
- @classmethod
74
- def __get_pydantic_core_schema__(cls, source_type: type[Any], handler: GetCoreSchemaHandler) -> CoreSchema:
75
- return core_schema.no_info_after_validator_function(
76
- cls._validate,
77
- core_schema.any_schema(),
78
- serialization=core_schema.plain_serializer_function_ser_schema(lambda x: x.dict()),
79
- )
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())
80
45
 
81
- @classmethod
82
- def _validate(cls, v: object) -> "HttpResponse":
83
- if isinstance(v, cls):
84
- return v
85
- if isinstance(v, dict):
86
- return cls(
87
- status=v.get("status"),
88
- error=HttpError(v["error"]) if v.get("error") else None,
89
- error_message=v.get("error_message"),
90
- body=v.get("body"),
91
- headers=v.get("headers"),
92
- )
93
- raise TypeError(f"Cannot parse value as {cls.__name__}: {v}")
46
+ def to_data_result_ok[T](self, result: T) -> DataResult[T]:
47
+ return DataResult(ok=result, data=self.model_dump())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mm-std
3
- Version: 0.3.27
3
+ Version: 0.3.29
4
4
  Requires-Python: >=3.12
5
5
  Requires-Dist: aiohttp-socks~=0.10.1
6
6
  Requires-Dist: aiohttp~=3.11.16
@@ -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=--rg0YPaJkszCmbt9TO-BthdGdYrCRARA8iII9LVocE,5871
5
+ mm_std/data_result.py,sha256=AMG6ttFTa9wxOS2U3kgPI2Z1shntdhF-7KxvfYYILoo,8104
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
@@ -27,8 +27,8 @@ mm_std/concurrency/sync_decorators.py,sha256=syCQBOmN7qPO55yzgJB2rbkh10CVww376hm
27
27
  mm_std/concurrency/sync_scheduler.py,sha256=j4tBL_cBI1spr0cZplTA7N2CoYsznuORMeRN8rpR6gY,2407
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
- mm_std/http/http_request.py,sha256=mJak332gv9NvY0JLO3hNrBxroQGS1HlNBzd1yq4Dy24,3694
31
- mm_std/http/response.py,sha256=vvv5COTjJula9t33mFyrruhrFC4dr_Uy0jDKj6t1JxM,2923
32
- mm_std-0.3.27.dist-info/METADATA,sha256=H30ViZKdZolKRVDR9PxBk7OoQZWofyy-EqjrUpT2NkQ,415
33
- mm_std-0.3.27.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
34
- mm_std-0.3.27.dist-info/RECORD,,
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,,