mm-http 0.3.0__tar.gz → 0.3.1__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.
@@ -3,7 +3,7 @@
3
3
  ## Critical: Language
4
4
  RESPOND IN ENGLISH. Always. No exceptions.
5
5
  User's language does NOT determine your response language.
6
- Only switch if user EXPLICITLY requests it (e.g., "respond in Russian").
6
+ Only switch if user EXPLICITLY requests it (e.g., "respond in {language}").
7
7
  Language switching applies ONLY to chat. All code, comments, commit messages, and files must ALWAYS be in English — no exceptions.
8
8
 
9
9
  ## Mandatory Rules (external)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mm-http
3
- Version: 0.3.0
3
+ Version: 0.3.1
4
4
  Requires-Python: >=3.14
5
5
  Requires-Dist: aiohttp-socks~=0.11.0
6
6
  Requires-Dist: aiohttp~=3.13.3
@@ -6,7 +6,7 @@ A simple and convenient HTTP client library for Python with both synchronous and
6
6
 
7
7
  - **Simple API** for one-off HTTP requests
8
8
  - **Sync and Async** support with identical interfaces
9
- - **JSON path navigation** with dot notation (`response.json_body_or_none("user.profile.name")`)
9
+ - **JSON path navigation** with dot notation (`response.json_body("user.profile.name")`)
10
10
  - **Proxy support** (HTTP and SOCKS5)
11
11
  - **Unified error handling**
12
12
  - **Type-safe** with full type annotations
@@ -21,7 +21,8 @@ from mm_http import http_request
21
21
 
22
22
  # Simple GET request
23
23
  response = await http_request("https://api.github.com/users/octocat")
24
- user_name = response.json_body_or_none("name") # Navigate JSON with dot notation
24
+ result = response.json_body("name") # Navigate JSON with dot notation
25
+ user_name = result.value if result.is_ok() else None
25
26
 
26
27
  # POST with JSON data
27
28
  response = await http_request(
@@ -45,7 +46,8 @@ from mm_http import http_request_sync
45
46
 
46
47
  # Same API, but synchronous
47
48
  response = http_request_sync("https://api.github.com/users/octocat")
48
- user_name = response.json_body_or_none("name")
49
+ result = response.json_body("name")
50
+ user_name = result.value if result.is_ok() else None
49
51
  ```
50
52
 
51
53
  ## API Reference
@@ -81,7 +83,6 @@ class HttpResponse(BaseModel):
81
83
 
82
84
  # JSON parsing
83
85
  def json_body(self, path: str | None = None) -> Result[Any]
84
- def json_body_or_none(self, path: str | None = None) -> Any
85
86
 
86
87
  # Header access
87
88
  def get_header(self, name: str) -> str | None
@@ -122,19 +123,18 @@ class TransportErrorType(str, Enum):
122
123
  response = await http_request("https://api.github.com/users/octocat")
123
124
 
124
125
  # Instead of: json.loads(response.body)["plan"]["name"]
125
- plan_name = response.json_body_or_none("plan.name")
126
-
127
- # Safe navigation - returns None if path doesn't exist
128
- followers = response.json_body_or_none("followers_count")
129
- nonexistent = response.json_body_or_none("does.not.exist") # Returns None
126
+ result = response.json_body("plan.name")
127
+ if result.is_ok():
128
+ plan_name = result.value
130
129
 
131
- # Or get full JSON
132
- data = response.json_body_or_none()
130
+ # Navigate with dot notation
131
+ followers = response.json_body("followers_count")
132
+ nonexistent = response.json_body("does.not.exist") # Result with error
133
133
 
134
- # When None is a valid value, use json_body() for explicit error handling
135
- result = response.json_body("optional_field")
134
+ # Get full JSON
135
+ result = response.json_body()
136
136
  if result.is_ok():
137
- value = result.value # Could be None if field is null in JSON
137
+ data = result.value
138
138
  else:
139
139
  print(f"Error: {result.error}") # "body is None", "JSON decode error", or "path not found: ..."
140
140
  ```
@@ -146,7 +146,7 @@ response = await http_request("https://example.com", timeout=5.0)
146
146
 
147
147
  # Simple check
148
148
  if response.is_success():
149
- data = response.json_body_or_none()
149
+ result = response.json_body()
150
150
 
151
151
  # Detailed error handling
152
152
  if response.is_err():
@@ -200,8 +200,10 @@ async def get_user_id() -> Result[int]:
200
200
  if response.is_err():
201
201
  return response.to_result_err() # Returns "HTTP 404" or TransportErrorType.TIMEOUT
202
202
 
203
- user_id = response.json_body_or_none("id")
204
- return response.to_result_ok(user_id)
203
+ result = response.json_body("id")
204
+ if result.is_err():
205
+ return response.to_result_err("invalid_json")
206
+ return response.to_result_ok(result.value)
205
207
 
206
208
  # Usage
207
209
  result = await get_user_id()
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mm-http"
3
- version = "0.3.0"
3
+ version = "0.3.1"
4
4
  description = ""
5
5
  requires-python = ">=3.14"
6
6
  dependencies = [
@@ -22,7 +22,7 @@ dev = [
22
22
  "pytest-asyncio~=1.3.0",
23
23
  "pytest-xdist~=3.8.0",
24
24
  "pytest-httpserver~=1.1.3",
25
- "ruff~=0.14.14",
25
+ "ruff~=0.15.0",
26
26
  "mypy~=1.19.1",
27
27
  "pip-audit~=2.10.0",
28
28
  "bandit~=1.9.3",
@@ -10,7 +10,7 @@ from pydantic import BaseModel, model_validator
10
10
 
11
11
 
12
12
  @enum.unique
13
- class TransportErrorType(str, enum.Enum):
13
+ class TransportErrorType(enum.StrEnum):
14
14
  """Transport-level error types."""
15
15
 
16
16
  TIMEOUT = "timeout"
@@ -71,19 +71,6 @@ class HttpResponse(BaseModel):
71
71
  return Result.ok(pydash.get(data, path))
72
72
  return Result.ok(data)
73
73
 
74
- def json_body_or_none(self, path: str | None = None) -> Any: # noqa: ANN401 - JSON returns dynamic types
75
- """Parse body as JSON. Returns None if body is None, JSON invalid, or path not found.
76
-
77
- Warning: Do not use if None is a valid expected value — use json_body() instead.
78
- """
79
- if self.body is None:
80
- return None
81
- try:
82
- res = json.loads(self.body)
83
- return pydash.get(res, path, None) if path else res
84
- except json.JSONDecodeError:
85
- return None
86
-
87
74
  def get_header(self, name: str) -> str | None:
88
75
  """Get header value (case-insensitive)."""
89
76
  if self.headers is None:
@@ -187,9 +187,9 @@ class TestAsyncHttpRequestJson:
187
187
  """Parse JSON response body."""
188
188
  url = setup_json_endpoint()
189
189
  response = await http_request(url)
190
- assert response.json_body_or_none() == json_response_data
191
- assert response.json_body_or_none("user.id") == 123
192
- assert response.json_body_or_none("user.profile.name") == "John Doe"
190
+ assert response.json_body().value == json_response_data
191
+ assert response.json_body("user.id").value == 123
192
+ assert response.json_body("user.profile.name").value == "John Doe"
193
193
 
194
194
 
195
195
  class TestAsyncHttpRequestRedirects:
@@ -187,9 +187,9 @@ class TestSyncHttpRequestJson:
187
187
  """Parse JSON response body."""
188
188
  url = setup_json_endpoint()
189
189
  response = http_request_sync(url)
190
- assert response.json_body_or_none() == json_response_data
191
- assert response.json_body_or_none("user.id") == 123
192
- assert response.json_body_or_none("user.profile.name") == "John Doe"
190
+ assert response.json_body().value == json_response_data
191
+ assert response.json_body("user.id").value == 123
192
+ assert response.json_body("user.profile.name").value == "John Doe"
193
193
 
194
194
 
195
195
  class TestSyncHttpRequestRedirects:
@@ -89,51 +89,33 @@ class TestHttpResponseJsonParsing:
89
89
  def test_path_navigation(self, body: str, path: str | None, expected):
90
90
  """Navigate JSON with dot notation paths."""
91
91
  response = HttpResponse(status_code=200, body=body)
92
- assert response.json_body_or_none(path) == expected
92
+ result = response.json_body(path)
93
+ assert result.is_ok()
94
+ assert result.value == expected
93
95
 
94
96
  def test_none_body(self):
95
- """Return None when body is None."""
96
- response = HttpResponse(status_code=204, body=None)
97
- assert response.json_body_or_none("any.path") is None
98
-
99
- def test_invalid_json(self):
100
- """Return None for invalid JSON."""
101
- response = HttpResponse(status_code=200, body="not json")
102
- assert response.json_body_or_none() is None
103
-
104
- def test_missing_path(self):
105
- """Return None for non-existent path."""
106
- response = HttpResponse(status_code=200, body='{"a": 1}')
107
- assert response.json_body_or_none("b.c.d") is None
108
-
109
- def test_null_value_in_json(self):
110
- """Return None for null JSON value."""
111
- response = HttpResponse(status_code=200, body='{"nullable": null}')
112
- assert response.json_body_or_none("nullable") is None
113
-
114
- def test_json_body_explicit_error_none_body(self):
115
- """json_body returns error for None body."""
97
+ """Return error for None body."""
116
98
  response = HttpResponse(status_code=204, body=None)
117
99
  result = response.json_body("field")
118
100
  assert result.is_err()
119
101
  assert result.error == "body is None"
120
102
 
121
- def test_json_body_explicit_error_invalid_json(self):
122
- """json_body returns error for invalid JSON."""
103
+ def test_invalid_json(self):
104
+ """Return error for invalid JSON."""
123
105
  response = HttpResponse(status_code=200, body="not json")
124
106
  result = response.json_body()
125
107
  assert result.is_err()
126
108
  assert "JSON decode error" in str(result.error)
127
109
 
128
- def test_json_body_explicit_error_missing_path(self):
129
- """json_body returns error for missing path."""
110
+ def test_missing_path(self):
111
+ """Return error for missing path."""
130
112
  response = HttpResponse(status_code=200, body='{"a": 1}')
131
113
  result = response.json_body("b.c")
132
114
  assert result.is_err()
133
115
  assert "path not found" in str(result.error)
134
116
 
135
- def test_json_body_returns_null_value(self):
136
- """json_body returns None for null JSON value (not error)."""
117
+ def test_null_value(self):
118
+ """Return None for null JSON value (not error)."""
137
119
  response = HttpResponse(status_code=200, body='{"nullable": null}')
138
120
  result = response.json_body("nullable")
139
121
  assert result.is_ok()
@@ -413,7 +413,7 @@ wheels = [
413
413
 
414
414
  [[package]]
415
415
  name = "mm-http"
416
- version = "0.3.0"
416
+ version = "0.3.1"
417
417
  source = { editable = "." }
418
418
  dependencies = [
419
419
  { name = "aiohttp" },
@@ -461,7 +461,7 @@ dev = [
461
461
  { name = "pytest-httpserver", specifier = "~=1.1.3" },
462
462
  { name = "pytest-xdist", specifier = "~=3.8.0" },
463
463
  { name = "python-dotenv", specifier = "~=1.2.1" },
464
- { name = "ruff", specifier = "~=0.14.14" },
464
+ { name = "ruff", specifier = "~=0.15.0" },
465
465
  { name = "ty", specifier = "~=0.0.14" },
466
466
  { name = "types-requests", specifier = "~=2.32.4.20260107" },
467
467
  ]
@@ -977,28 +977,27 @@ wheels = [
977
977
 
978
978
  [[package]]
979
979
  name = "ruff"
980
- version = "0.14.14"
981
- source = { registry = "https://pypi.org/simple" }
982
- sdist = { url = "https://files.pythonhosted.org/packages/2e/06/f71e3a86b2df0dfa2d2f72195941cd09b44f87711cb7fa5193732cb9a5fc/ruff-0.14.14.tar.gz", hash = "sha256:2d0f819c9a90205f3a867dbbd0be083bee9912e170fd7d9704cc8ae45824896b", size = 4515732, upload-time = "2026-01-22T22:30:17.527Z" }
983
- wheels = [
984
- { url = "https://files.pythonhosted.org/packages/d2/89/20a12e97bc6b9f9f68343952da08a8099c57237aef953a56b82711d55edd/ruff-0.14.14-py3-none-linux_armv6l.whl", hash = "sha256:7cfe36b56e8489dee8fbc777c61959f60ec0f1f11817e8f2415f429552846aed", size = 10467650, upload-time = "2026-01-22T22:30:08.578Z" },
985
- { url = "https://files.pythonhosted.org/packages/a3/b1/c5de3fd2d5a831fcae21beda5e3589c0ba67eec8202e992388e4b17a6040/ruff-0.14.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6006a0082336e7920b9573ef8a7f52eec837add1265cc74e04ea8a4368cd704c", size = 10883245, upload-time = "2026-01-22T22:30:04.155Z" },
986
- { url = "https://files.pythonhosted.org/packages/b8/7c/3c1db59a10e7490f8f6f8559d1db8636cbb13dccebf18686f4e3c9d7c772/ruff-0.14.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:026c1d25996818f0bf498636686199d9bd0d9d6341c9c2c3b62e2a0198b758de", size = 10231273, upload-time = "2026-01-22T22:30:34.642Z" },
987
- { url = "https://files.pythonhosted.org/packages/a1/6e/5e0e0d9674be0f8581d1f5e0f0a04761203affce3232c1a1189d0e3b4dad/ruff-0.14.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f666445819d31210b71e0a6d1c01e24447a20b85458eea25a25fe8142210ae0e", size = 10585753, upload-time = "2026-01-22T22:30:31.781Z" },
988
- { url = "https://files.pythonhosted.org/packages/23/09/754ab09f46ff1884d422dc26d59ba18b4e5d355be147721bb2518aa2a014/ruff-0.14.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c0f18b922c6d2ff9a5e6c3ee16259adc513ca775bcf82c67ebab7cbd9da5bc8", size = 10286052, upload-time = "2026-01-22T22:30:24.827Z" },
989
- { url = "https://files.pythonhosted.org/packages/c8/cc/e71f88dd2a12afb5f50733851729d6b571a7c3a35bfdb16c3035132675a0/ruff-0.14.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1629e67489c2dea43e8658c3dba659edbfd87361624b4040d1df04c9740ae906", size = 11043637, upload-time = "2026-01-22T22:30:13.239Z" },
990
- { url = "https://files.pythonhosted.org/packages/67/b2/397245026352494497dac935d7f00f1468c03a23a0c5db6ad8fc49ca3fb2/ruff-0.14.14-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:27493a2131ea0f899057d49d303e4292b2cae2bb57253c1ed1f256fbcd1da480", size = 12194761, upload-time = "2026-01-22T22:30:22.542Z" },
991
- { url = "https://files.pythonhosted.org/packages/5b/06/06ef271459f778323112c51b7587ce85230785cd64e91772034ddb88f200/ruff-0.14.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ff589aab3f5b539e35db38425da31a57521efd1e4ad1ae08fc34dbe30bd7df", size = 12005701, upload-time = "2026-01-22T22:30:20.499Z" },
992
- { url = "https://files.pythonhosted.org/packages/41/d6/99364514541cf811ccc5ac44362f88df66373e9fec1b9d1c4cc830593fe7/ruff-0.14.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc12d74eef0f29f51775f5b755913eb523546b88e2d733e1d701fe65144e89b", size = 11282455, upload-time = "2026-01-22T22:29:59.679Z" },
993
- { url = "https://files.pythonhosted.org/packages/ca/71/37daa46f89475f8582b7762ecd2722492df26421714a33e72ccc9a84d7a5/ruff-0.14.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb8481604b7a9e75eff53772496201690ce2687067e038b3cc31aaf16aa0b974", size = 11215882, upload-time = "2026-01-22T22:29:57.032Z" },
994
- { url = "https://files.pythonhosted.org/packages/2c/10/a31f86169ec91c0705e618443ee74ede0bdd94da0a57b28e72db68b2dbac/ruff-0.14.14-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:14649acb1cf7b5d2d283ebd2f58d56b75836ed8c6f329664fa91cdea19e76e66", size = 11180549, upload-time = "2026-01-22T22:30:27.175Z" },
995
- { url = "https://files.pythonhosted.org/packages/fd/1e/c723f20536b5163adf79bdd10c5f093414293cdf567eed9bdb7b83940f3f/ruff-0.14.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8058d2145566510790eab4e2fad186002e288dec5e0d343a92fe7b0bc1b3e13", size = 10543416, upload-time = "2026-01-22T22:30:01.964Z" },
996
- { url = "https://files.pythonhosted.org/packages/3e/34/8a84cea7e42c2d94ba5bde1d7a4fae164d6318f13f933d92da6d7c2041ff/ruff-0.14.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e651e977a79e4c758eb807f0481d673a67ffe53cfa92209781dfa3a996cf8412", size = 10285491, upload-time = "2026-01-22T22:30:29.51Z" },
997
- { url = "https://files.pythonhosted.org/packages/55/ef/b7c5ea0be82518906c978e365e56a77f8de7678c8bb6651ccfbdc178c29f/ruff-0.14.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cc8b22da8d9d6fdd844a68ae937e2a0adf9b16514e9a97cc60355e2d4b219fc3", size = 10733525, upload-time = "2026-01-22T22:30:06.499Z" },
998
- { url = "https://files.pythonhosted.org/packages/6a/5b/aaf1dfbcc53a2811f6cc0a1759de24e4b03e02ba8762daabd9b6bd8c59e3/ruff-0.14.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:16bc890fb4cc9781bb05beb5ab4cd51be9e7cb376bf1dd3580512b24eb3fda2b", size = 11315626, upload-time = "2026-01-22T22:30:36.848Z" },
999
- { url = "https://files.pythonhosted.org/packages/2c/aa/9f89c719c467dfaf8ad799b9bae0df494513fb21d31a6059cb5870e57e74/ruff-0.14.14-py3-none-win32.whl", hash = "sha256:b530c191970b143375b6a68e6f743800b2b786bbcf03a7965b06c4bf04568167", size = 10502442, upload-time = "2026-01-22T22:30:38.93Z" },
1000
- { url = "https://files.pythonhosted.org/packages/87/44/90fa543014c45560cae1fffc63ea059fb3575ee6e1cb654562197e5d16fb/ruff-0.14.14-py3-none-win_amd64.whl", hash = "sha256:3dde1435e6b6fe5b66506c1dff67a421d0b7f6488d466f651c07f4cab3bf20fd", size = 11630486, upload-time = "2026-01-22T22:30:10.852Z" },
1001
- { url = "https://files.pythonhosted.org/packages/9e/6a/40fee331a52339926a92e17ae748827270b288a35ef4a15c9c8f2ec54715/ruff-0.14.14-py3-none-win_arm64.whl", hash = "sha256:56e6981a98b13a32236a72a8da421d7839221fa308b223b9283312312e5ac76c", size = 10920448, upload-time = "2026-01-22T22:30:15.417Z" },
980
+ version = "0.15.0"
981
+ source = { registry = "https://pypi.org/simple" }
982
+ sdist = { url = "https://files.pythonhosted.org/packages/c8/39/5cee96809fbca590abea6b46c6d1c586b49663d1d2830a751cc8fc42c666/ruff-0.15.0.tar.gz", hash = "sha256:6bdea47cdbea30d40f8f8d7d69c0854ba7c15420ec75a26f463290949d7f7e9a", size = 4524893, upload-time = "2026-02-03T17:53:35.357Z" }
983
+ wheels = [
984
+ { url = "https://files.pythonhosted.org/packages/bc/88/3fd1b0aa4b6330d6aaa63a285bc96c9f71970351579152d231ed90914586/ruff-0.15.0-py3-none-linux_armv6l.whl", hash = "sha256:aac4ebaa612a82b23d45964586f24ae9bc23ca101919f5590bdb368d74ad5455", size = 10354332, upload-time = "2026-02-03T17:52:54.892Z" },
985
+ { url = "https://files.pythonhosted.org/packages/72/f6/62e173fbb7eb75cc29fe2576a1e20f0a46f671a2587b5f604bfb0eaf5f6f/ruff-0.15.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:dcd4be7cc75cfbbca24a98d04d0b9b36a270d0833241f776b788d59f4142b14d", size = 10767189, upload-time = "2026-02-03T17:53:19.778Z" },
986
+ { url = "https://files.pythonhosted.org/packages/99/e4/968ae17b676d1d2ff101d56dc69cf333e3a4c985e1ec23803df84fc7bf9e/ruff-0.15.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d747e3319b2bce179c7c1eaad3d884dc0a199b5f4d5187620530adf9105268ce", size = 10075384, upload-time = "2026-02-03T17:53:29.241Z" },
987
+ { url = "https://files.pythonhosted.org/packages/a2/bf/9843c6044ab9e20af879c751487e61333ca79a2c8c3058b15722386b8cae/ruff-0.15.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:650bd9c56ae03102c51a5e4b554d74d825ff3abe4db22b90fd32d816c2e90621", size = 10481363, upload-time = "2026-02-03T17:52:43.332Z" },
988
+ { url = "https://files.pythonhosted.org/packages/55/d9/4ada5ccf4cd1f532db1c8d44b6f664f2208d3d93acbeec18f82315e15193/ruff-0.15.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a6664b7eac559e3048223a2da77769c2f92b43a6dfd4720cef42654299a599c9", size = 10187736, upload-time = "2026-02-03T17:53:00.522Z" },
989
+ { url = "https://files.pythonhosted.org/packages/86/e2/f25eaecd446af7bb132af0a1d5b135a62971a41f5366ff41d06d25e77a91/ruff-0.15.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f811f97b0f092b35320d1556f3353bf238763420ade5d9e62ebd2b73f2ff179", size = 10968415, upload-time = "2026-02-03T17:53:15.705Z" },
990
+ { url = "https://files.pythonhosted.org/packages/e7/dc/f06a8558d06333bf79b497d29a50c3a673d9251214e0d7ec78f90b30aa79/ruff-0.15.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:761ec0a66680fab6454236635a39abaf14198818c8cdf691e036f4bc0f406b2d", size = 11809643, upload-time = "2026-02-03T17:53:23.031Z" },
991
+ { url = "https://files.pythonhosted.org/packages/dd/45/0ece8db2c474ad7df13af3a6d50f76e22a09d078af63078f005057ca59eb/ruff-0.15.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:940f11c2604d317e797b289f4f9f3fa5555ffe4fb574b55ed006c3d9b6f0eb78", size = 11234787, upload-time = "2026-02-03T17:52:46.432Z" },
992
+ { url = "https://files.pythonhosted.org/packages/8a/d9/0e3a81467a120fd265658d127db648e4d3acfe3e4f6f5d4ea79fac47e587/ruff-0.15.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcbca3d40558789126da91d7ef9a7c87772ee107033db7191edefa34e2c7f1b4", size = 11112797, upload-time = "2026-02-03T17:52:49.274Z" },
993
+ { url = "https://files.pythonhosted.org/packages/b2/cb/8c0b3b0c692683f8ff31351dfb6241047fa873a4481a76df4335a8bff716/ruff-0.15.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:9a121a96db1d75fa3eb39c4539e607f628920dd72ff1f7c5ee4f1b768ac62d6e", size = 11033133, upload-time = "2026-02-03T17:53:33.105Z" },
994
+ { url = "https://files.pythonhosted.org/packages/f8/5e/23b87370cf0f9081a8c89a753e69a4e8778805b8802ccfe175cc410e50b9/ruff-0.15.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:5298d518e493061f2eabd4abd067c7e4fb89e2f63291c94332e35631c07c3662", size = 10442646, upload-time = "2026-02-03T17:53:06.278Z" },
995
+ { url = "https://files.pythonhosted.org/packages/e1/9a/3c94de5ce642830167e6d00b5c75aacd73e6347b4c7fc6828699b150a5ee/ruff-0.15.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:afb6e603d6375ff0d6b0cee563fa21ab570fd15e65c852cb24922cef25050cf1", size = 10195750, upload-time = "2026-02-03T17:53:26.084Z" },
996
+ { url = "https://files.pythonhosted.org/packages/30/15/e396325080d600b436acc970848d69df9c13977942fb62bb8722d729bee8/ruff-0.15.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:77e515f6b15f828b94dc17d2b4ace334c9ddb7d9468c54b2f9ed2b9c1593ef16", size = 10676120, upload-time = "2026-02-03T17:53:09.363Z" },
997
+ { url = "https://files.pythonhosted.org/packages/8d/c9/229a23d52a2983de1ad0fb0ee37d36e0257e6f28bfd6b498ee2c76361874/ruff-0.15.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6f6e80850a01eb13b3e42ee0ebdf6e4497151b48c35051aab51c101266d187a3", size = 11201636, upload-time = "2026-02-03T17:52:57.281Z" },
998
+ { url = "https://files.pythonhosted.org/packages/6f/b0/69adf22f4e24f3677208adb715c578266842e6e6a3cc77483f48dd999ede/ruff-0.15.0-py3-none-win32.whl", hash = "sha256:238a717ef803e501b6d51e0bdd0d2c6e8513fe9eec14002445134d3907cd46c3", size = 10465945, upload-time = "2026-02-03T17:53:12.591Z" },
999
+ { url = "https://files.pythonhosted.org/packages/51/ad/f813b6e2c97e9b4598be25e94a9147b9af7e60523b0cb5d94d307c15229d/ruff-0.15.0-py3-none-win_amd64.whl", hash = "sha256:dd5e4d3301dc01de614da3cdffc33d4b1b96fb89e45721f1598e5532ccf78b18", size = 11564657, upload-time = "2026-02-03T17:52:51.893Z" },
1000
+ { url = "https://files.pythonhosted.org/packages/f6/b0/2d823f6e77ebe560f4e397d078487e8d52c1516b331e3521bc75db4272ca/ruff-0.15.0-py3-none-win_arm64.whl", hash = "sha256:c480d632cc0ca3f0727acac8b7d053542d9e114a462a145d0b00e7cd658c515a", size = 10865753, upload-time = "2026-02-03T17:53:03.014Z" },
1002
1001
  ]
1003
1002
 
1004
1003
  [[package]]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes