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.
- {mm_http-0.3.0 → mm_http-0.3.1}/CLAUDE.md +1 -1
- {mm_http-0.3.0 → mm_http-0.3.1}/PKG-INFO +1 -1
- {mm_http-0.3.0 → mm_http-0.3.1}/README.md +19 -17
- {mm_http-0.3.0 → mm_http-0.3.1}/pyproject.toml +2 -2
- {mm_http-0.3.0 → mm_http-0.3.1}/src/mm_http/response.py +1 -14
- {mm_http-0.3.0 → mm_http-0.3.1}/tests/mm_http/test_request.py +3 -3
- {mm_http-0.3.0 → mm_http-0.3.1}/tests/mm_http/test_request_sync.py +3 -3
- {mm_http-0.3.0 → mm_http-0.3.1}/tests/mm_http/test_response.py +10 -28
- {mm_http-0.3.0 → mm_http-0.3.1}/uv.lock +23 -24
- {mm_http-0.3.0 → mm_http-0.3.1}/.claude/settings.local.json +0 -0
- {mm_http-0.3.0 → mm_http-0.3.1}/.env.example +0 -0
- {mm_http-0.3.0 → mm_http-0.3.1}/.gitignore +0 -0
- {mm_http-0.3.0 → mm_http-0.3.1}/.pre-commit-config.yaml +0 -0
- {mm_http-0.3.0 → mm_http-0.3.1}/justfile +0 -0
- {mm_http-0.3.0 → mm_http-0.3.1}/src/mm_http/__init__.py +0 -0
- {mm_http-0.3.0 → mm_http-0.3.1}/src/mm_http/py.typed +0 -0
- {mm_http-0.3.0 → mm_http-0.3.1}/src/mm_http/request.py +0 -0
- {mm_http-0.3.0 → mm_http-0.3.1}/src/mm_http/request_sync.py +0 -0
- {mm_http-0.3.0 → mm_http-0.3.1}/tests/__init__.py +0 -0
- {mm_http-0.3.0 → mm_http-0.3.1}/tests/conftest.py +0 -0
- {mm_http-0.3.0 → mm_http-0.3.1}/tests/helpers/__init__.py +0 -0
- {mm_http-0.3.0 → mm_http-0.3.1}/tests/helpers/proxy.py +0 -0
- {mm_http-0.3.0 → mm_http-0.3.1}/tests/mm_http/__init__.py +0 -0
|
@@ -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
|
|
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)
|
|
@@ -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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
-
#
|
|
132
|
-
|
|
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
|
-
#
|
|
135
|
-
result = response.json_body(
|
|
134
|
+
# Get full JSON
|
|
135
|
+
result = response.json_body()
|
|
136
136
|
if result.is_ok():
|
|
137
|
-
|
|
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
|
-
|
|
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
|
-
|
|
204
|
-
|
|
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.
|
|
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.
|
|
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(
|
|
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.
|
|
191
|
-
assert response.
|
|
192
|
-
assert response.
|
|
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.
|
|
191
|
-
assert response.
|
|
192
|
-
assert response.
|
|
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
|
-
|
|
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
|
|
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
|
|
122
|
-
"""
|
|
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
|
|
129
|
-
"""
|
|
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
|
|
136
|
-
"""
|
|
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.
|
|
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.
|
|
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.
|
|
981
|
-
source = { registry = "https://pypi.org/simple" }
|
|
982
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
983
|
-
wheels = [
|
|
984
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
985
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
986
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
987
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
988
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
989
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
990
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
991
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
992
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
993
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
994
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
995
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
996
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
997
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
998
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
999
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1000
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|