SunsetLog 0.0.1__tar.gz → 0.0.2__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.
- sunsetlog-0.0.2/PKG-INFO +137 -0
- sunsetlog-0.0.2/README.md +129 -0
- {sunsetlog-0.0.1 → sunsetlog-0.0.2}/SunsetLog/__init__.py +10 -1
- {sunsetlog-0.0.1 → sunsetlog-0.0.2}/SunsetLog/client.py +29 -4
- {sunsetlog-0.0.1 → sunsetlog-0.0.2}/SunsetLog/models.py +19 -0
- sunsetlog-0.0.2/SunsetLog.code-workspace +57 -0
- sunsetlog-0.0.2/examples/get_channel_list.py +24 -0
- {sunsetlog-0.0.1 → sunsetlog-0.0.2}/pyproject.toml +1 -1
- {sunsetlog-0.0.1 → sunsetlog-0.0.2}/uv.lock +2 -2
- sunsetlog-0.0.1/PKG-INFO +0 -10
- sunsetlog-0.0.1/README.md +0 -2
- sunsetlog-0.0.1/SunsetLog.code-workspace +0 -61
- {sunsetlog-0.0.1 → sunsetlog-0.0.2}/.gitattributes +0 -0
- {sunsetlog-0.0.1 → sunsetlog-0.0.2}/.github/workflows/publish-pypi.yml +0 -0
- {sunsetlog-0.0.1 → sunsetlog-0.0.2}/.gitignore +0 -0
- {sunsetlog-0.0.1 → sunsetlog-0.0.2}/.python-version +0 -0
sunsetlog-0.0.2/PKG-INFO
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: SunsetLog
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: Add your description here
|
|
5
|
+
Requires-Python: <3.15,>=3.10
|
|
6
|
+
Requires-Dist: httpx>=0.28.1
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
|
|
9
|
+
# SunsetLog
|
|
10
|
+
|
|
11
|
+
Async Python client for [log-api.vmp.ir](https://log-api.vmp.ir): list channels and search logs. The library only returns data; you decide how to store or use it.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
**pip**
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install SunsetLog
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**uv**
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
uv add SunsetLog
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- Python: **3.10+**
|
|
30
|
+
- Dependency: **httpx**
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Quick start
|
|
35
|
+
|
|
36
|
+
You need an API **token** (Bearer). Use the client as an async context manager and call `get_channels` or `search`.
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
import asyncio
|
|
40
|
+
from SunsetLog import SunsetLogClient
|
|
41
|
+
|
|
42
|
+
TOKEN = "your-bearer-token"
|
|
43
|
+
|
|
44
|
+
async def main():
|
|
45
|
+
async with SunsetLogClient(TOKEN) as client:
|
|
46
|
+
# List channels for a gang (returns dict of channel_name -> {id, ts})
|
|
47
|
+
channels = await client.get_channels(gang=1)
|
|
48
|
+
print(list(channels.keys()))
|
|
49
|
+
|
|
50
|
+
# Search logs (all channels if channels=None)
|
|
51
|
+
data = await client.search(gang=1, from_offset=0)
|
|
52
|
+
print(data["total"], len(data["hits"]))
|
|
53
|
+
for hit in data["hits"]:
|
|
54
|
+
print(hit.get("index"), hit.get("content"), hit.get("ts"))
|
|
55
|
+
|
|
56
|
+
asyncio.run(main())
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## API overview
|
|
62
|
+
|
|
63
|
+
### `SunsetLogClient(token, *, base_url=..., timeout=30.0, headers=...)`
|
|
64
|
+
|
|
65
|
+
- **token** (str): Bearer token for the API.
|
|
66
|
+
- **base_url**: Default `"https://log-api.vmp.ir"`.
|
|
67
|
+
- **timeout**, **headers**: Optional.
|
|
68
|
+
|
|
69
|
+
Use as `async with SunsetLogClient(TOKEN) as client:` or call `await client.close()` when done.
|
|
70
|
+
|
|
71
|
+
### `get_channels(gang=1)`
|
|
72
|
+
|
|
73
|
+
- **Returns:** `dict[str, ChannelMeta]` — channel name → `{"id": str, "ts": int}`.
|
|
74
|
+
|
|
75
|
+
### `search(*, channels=None, gang=1, q="", from_offset=0, mode="exact", operator="and")`
|
|
76
|
+
|
|
77
|
+
- **channels:** `None` (all channels for the gang), a single channel name (str), or a list of channel names.
|
|
78
|
+
- **gang:** Gang id (default `1`).
|
|
79
|
+
- **q:** Search query string.
|
|
80
|
+
- **from_offset:** Pagination offset (API returns up to 100 hits per request).
|
|
81
|
+
- **Returns:** `{"total": int, "hits": list[LogHit]}`. Each hit has `id`, `index` (channel name), `content`, `ts`, `reactions`.
|
|
82
|
+
|
|
83
|
+
### `SunsetLogAPIError`
|
|
84
|
+
|
|
85
|
+
Raised on non-200 or invalid response. Has `.status_code` and `.body` when available.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Pagination
|
|
90
|
+
|
|
91
|
+
The search API returns at most **100 hits** per request. To fetch all results, request pages by increasing `from_offset` until a page has fewer than 100 hits:
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
async def fetch_all(client, gang=1):
|
|
95
|
+
all_hits = []
|
|
96
|
+
from_offset = 0
|
|
97
|
+
while True:
|
|
98
|
+
data = await client.search(gang=gang, from_offset=from_offset)
|
|
99
|
+
hits = data.get("hits") or []
|
|
100
|
+
all_hits.extend(hits)
|
|
101
|
+
if len(hits) < 100:
|
|
102
|
+
break
|
|
103
|
+
from_offset += len(hits)
|
|
104
|
+
return all_hits
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Saving results
|
|
110
|
+
|
|
111
|
+
The library does **not** write files. You get dicts; you save them (e.g. JSON):
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
import json
|
|
115
|
+
from pathlib import Path
|
|
116
|
+
|
|
117
|
+
def save_to_file(data: dict, path: str) -> None:
|
|
118
|
+
Path(path).parent.mkdir(parents=True, exist_ok=True)
|
|
119
|
+
with open(path, "w", encoding="utf-8") as f:
|
|
120
|
+
json.dump(data, f, ensure_ascii=False, indent=2)
|
|
121
|
+
|
|
122
|
+
# usage
|
|
123
|
+
data = await client.search(gang=1)
|
|
124
|
+
save_to_file(data, "my_logs.json")
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Exports
|
|
130
|
+
|
|
131
|
+
From `SunsetLog` you can import:
|
|
132
|
+
|
|
133
|
+
- `SunsetLogClient`
|
|
134
|
+
- `SunsetLogAPIError`
|
|
135
|
+
- `SearchResponse`, `ChannelsResponse`, `LogHit`, `ChannelMeta` (types)
|
|
136
|
+
|
|
137
|
+
---
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# SunsetLog
|
|
2
|
+
|
|
3
|
+
Async Python client for [log-api.vmp.ir](https://log-api.vmp.ir): list channels and search logs. The library only returns data; you decide how to store or use it.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
**pip**
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install SunsetLog
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**uv**
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
uv add SunsetLog
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
- Python: **3.10+**
|
|
22
|
+
- Dependency: **httpx**
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Quick start
|
|
27
|
+
|
|
28
|
+
You need an API **token** (Bearer). Use the client as an async context manager and call `get_channels` or `search`.
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
import asyncio
|
|
32
|
+
from SunsetLog import SunsetLogClient
|
|
33
|
+
|
|
34
|
+
TOKEN = "your-bearer-token"
|
|
35
|
+
|
|
36
|
+
async def main():
|
|
37
|
+
async with SunsetLogClient(TOKEN) as client:
|
|
38
|
+
# List channels for a gang (returns dict of channel_name -> {id, ts})
|
|
39
|
+
channels = await client.get_channels(gang=1)
|
|
40
|
+
print(list(channels.keys()))
|
|
41
|
+
|
|
42
|
+
# Search logs (all channels if channels=None)
|
|
43
|
+
data = await client.search(gang=1, from_offset=0)
|
|
44
|
+
print(data["total"], len(data["hits"]))
|
|
45
|
+
for hit in data["hits"]:
|
|
46
|
+
print(hit.get("index"), hit.get("content"), hit.get("ts"))
|
|
47
|
+
|
|
48
|
+
asyncio.run(main())
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## API overview
|
|
54
|
+
|
|
55
|
+
### `SunsetLogClient(token, *, base_url=..., timeout=30.0, headers=...)`
|
|
56
|
+
|
|
57
|
+
- **token** (str): Bearer token for the API.
|
|
58
|
+
- **base_url**: Default `"https://log-api.vmp.ir"`.
|
|
59
|
+
- **timeout**, **headers**: Optional.
|
|
60
|
+
|
|
61
|
+
Use as `async with SunsetLogClient(TOKEN) as client:` or call `await client.close()` when done.
|
|
62
|
+
|
|
63
|
+
### `get_channels(gang=1)`
|
|
64
|
+
|
|
65
|
+
- **Returns:** `dict[str, ChannelMeta]` — channel name → `{"id": str, "ts": int}`.
|
|
66
|
+
|
|
67
|
+
### `search(*, channels=None, gang=1, q="", from_offset=0, mode="exact", operator="and")`
|
|
68
|
+
|
|
69
|
+
- **channels:** `None` (all channels for the gang), a single channel name (str), or a list of channel names.
|
|
70
|
+
- **gang:** Gang id (default `1`).
|
|
71
|
+
- **q:** Search query string.
|
|
72
|
+
- **from_offset:** Pagination offset (API returns up to 100 hits per request).
|
|
73
|
+
- **Returns:** `{"total": int, "hits": list[LogHit]}`. Each hit has `id`, `index` (channel name), `content`, `ts`, `reactions`.
|
|
74
|
+
|
|
75
|
+
### `SunsetLogAPIError`
|
|
76
|
+
|
|
77
|
+
Raised on non-200 or invalid response. Has `.status_code` and `.body` when available.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Pagination
|
|
82
|
+
|
|
83
|
+
The search API returns at most **100 hits** per request. To fetch all results, request pages by increasing `from_offset` until a page has fewer than 100 hits:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
async def fetch_all(client, gang=1):
|
|
87
|
+
all_hits = []
|
|
88
|
+
from_offset = 0
|
|
89
|
+
while True:
|
|
90
|
+
data = await client.search(gang=gang, from_offset=from_offset)
|
|
91
|
+
hits = data.get("hits") or []
|
|
92
|
+
all_hits.extend(hits)
|
|
93
|
+
if len(hits) < 100:
|
|
94
|
+
break
|
|
95
|
+
from_offset += len(hits)
|
|
96
|
+
return all_hits
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Saving results
|
|
102
|
+
|
|
103
|
+
The library does **not** write files. You get dicts; you save them (e.g. JSON):
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
import json
|
|
107
|
+
from pathlib import Path
|
|
108
|
+
|
|
109
|
+
def save_to_file(data: dict, path: str) -> None:
|
|
110
|
+
Path(path).parent.mkdir(parents=True, exist_ok=True)
|
|
111
|
+
with open(path, "w", encoding="utf-8") as f:
|
|
112
|
+
json.dump(data, f, ensure_ascii=False, indent=2)
|
|
113
|
+
|
|
114
|
+
# usage
|
|
115
|
+
data = await client.search(gang=1)
|
|
116
|
+
save_to_file(data, "my_logs.json")
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Exports
|
|
122
|
+
|
|
123
|
+
From `SunsetLog` you can import:
|
|
124
|
+
|
|
125
|
+
- `SunsetLogClient`
|
|
126
|
+
- `SunsetLogAPIError`
|
|
127
|
+
- `SearchResponse`, `ChannelsResponse`, `LogHit`, `ChannelMeta` (types)
|
|
128
|
+
|
|
129
|
+
---
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
from SunsetLog.client import SunsetLogAPIError, SunsetLogClient
|
|
2
|
-
from SunsetLog.models import
|
|
2
|
+
from SunsetLog.models import (
|
|
3
|
+
ChannelInfo,
|
|
4
|
+
ChannelListResponse,
|
|
5
|
+
ChannelMeta,
|
|
6
|
+
ChannelsResponse,
|
|
7
|
+
LogHit,
|
|
8
|
+
SearchResponse,
|
|
9
|
+
)
|
|
3
10
|
|
|
4
11
|
__version__ = "0.1.0"
|
|
5
12
|
__all__ = [
|
|
@@ -7,6 +14,8 @@ __all__ = [
|
|
|
7
14
|
"SunsetLogAPIError",
|
|
8
15
|
"SearchResponse",
|
|
9
16
|
"ChannelsResponse",
|
|
17
|
+
"ChannelListResponse",
|
|
18
|
+
"ChannelInfo",
|
|
10
19
|
"LogHit",
|
|
11
20
|
"ChannelMeta",
|
|
12
21
|
]
|
|
@@ -2,13 +2,15 @@ from typing import Any
|
|
|
2
2
|
|
|
3
3
|
import httpx
|
|
4
4
|
|
|
5
|
-
from SunsetLog.models import ChannelsResponse, SearchResponse
|
|
5
|
+
from SunsetLog.models import ChannelListResponse, ChannelsResponse, SearchResponse
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class SunsetLogAPIError(Exception):
|
|
9
9
|
"""Raised when the API returns an error or unexpected response."""
|
|
10
10
|
|
|
11
|
-
def __init__(
|
|
11
|
+
def __init__(
|
|
12
|
+
self, message: str, status_code: int | None = None, body: str | None = None
|
|
13
|
+
):
|
|
12
14
|
super().__init__(message)
|
|
13
15
|
self.status_code = status_code
|
|
14
16
|
self.body = body
|
|
@@ -79,6 +81,28 @@ class SunsetLogClient:
|
|
|
79
81
|
raise SunsetLogAPIError("channels/latest returned non-object", body=r.text)
|
|
80
82
|
return data
|
|
81
83
|
|
|
84
|
+
async def get_channel_list(
|
|
85
|
+
self, gang: int = 1, job: int = 1
|
|
86
|
+
) -> ChannelListResponse:
|
|
87
|
+
"""
|
|
88
|
+
Fetch the available channels for a gang/job.
|
|
89
|
+
GET /user/getChannels?gang={gang}&job={job}
|
|
90
|
+
"""
|
|
91
|
+
client = self._get_client()
|
|
92
|
+
r = await client.get("/user/getChannels", params={"gang": gang, "job": job})
|
|
93
|
+
if r.status_code != 200:
|
|
94
|
+
raise SunsetLogAPIError(
|
|
95
|
+
f"user/getChannels failed: {r.status_code}",
|
|
96
|
+
status_code=r.status_code,
|
|
97
|
+
body=r.text,
|
|
98
|
+
)
|
|
99
|
+
data = r.json()
|
|
100
|
+
if not isinstance(data, dict) or "channels" not in data:
|
|
101
|
+
raise SunsetLogAPIError(
|
|
102
|
+
"user/getChannels returned invalid shape", body=r.text
|
|
103
|
+
)
|
|
104
|
+
return data
|
|
105
|
+
|
|
82
106
|
async def search(
|
|
83
107
|
self,
|
|
84
108
|
*,
|
|
@@ -94,8 +118,9 @@ class SunsetLogClient:
|
|
|
94
118
|
channels: single channel name or comma-separated list.
|
|
95
119
|
"""
|
|
96
120
|
if channels is None:
|
|
97
|
-
|
|
98
|
-
|
|
121
|
+
channel_list = await self.get_channel_list(gang=gang)
|
|
122
|
+
indexes = [c["index"] for c in channel_list.get("channels", [])]
|
|
123
|
+
channels = ",".join(indexes) if indexes else "gang_glitch_locker1"
|
|
99
124
|
elif isinstance(channels, list):
|
|
100
125
|
channels = ",".join(channels)
|
|
101
126
|
|
|
@@ -26,3 +26,22 @@ class SearchResponse(TypedDict):
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
ChannelsResponse = dict[str, ChannelMeta]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ChannelInfo(TypedDict):
|
|
32
|
+
"""Single channel entry from /user/getChannels."""
|
|
33
|
+
|
|
34
|
+
id: int
|
|
35
|
+
index: str
|
|
36
|
+
label: str
|
|
37
|
+
type: int
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class ChannelListResponse(TypedDict):
|
|
41
|
+
"""Response of /user/getChannels."""
|
|
42
|
+
|
|
43
|
+
channels: list[ChannelInfo]
|
|
44
|
+
categories: list[Any]
|
|
45
|
+
admin: bool
|
|
46
|
+
canViewAllGangs: bool
|
|
47
|
+
canViewAllJobs: bool
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"folders": [
|
|
3
|
+
{
|
|
4
|
+
"path": ".",
|
|
5
|
+
},
|
|
6
|
+
],
|
|
7
|
+
"settings": {
|
|
8
|
+
"python.analysis.inlayHints.variableTypes": true,
|
|
9
|
+
"python.analysis.autoImportCompletions": true,
|
|
10
|
+
"python.analysis.completeFunctionParens": true,
|
|
11
|
+
"python.analysis.inlayHints.pytestParameters": true,
|
|
12
|
+
"python.analysis.inlayHints.callArgumentNames": "all",
|
|
13
|
+
"python.analysis.inlayHints.functionReturnTypes": true,
|
|
14
|
+
"ruff.enable": true,
|
|
15
|
+
"ruff.importStrategy": "useBundled",
|
|
16
|
+
"ruff.fixAll": true,
|
|
17
|
+
"ruff.organizeImports": true,
|
|
18
|
+
"ruff.showSyntaxErrors": true,
|
|
19
|
+
"[python]": {
|
|
20
|
+
"editor.defaultFormatter": "charliermarsh.ruff",
|
|
21
|
+
"editor.formatOnSave": true,
|
|
22
|
+
"editor.codeActionsOnSave": {
|
|
23
|
+
"source.fixAll.ruff": "explicit",
|
|
24
|
+
"source.organizeImports.ruff": "explicit",
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
"editor.codeActionsOnSave": {
|
|
28
|
+
"source.fixAll": "explicit",
|
|
29
|
+
"source.organizeImports": "never",
|
|
30
|
+
},
|
|
31
|
+
"remote.localPortHost": "allInterfaces",
|
|
32
|
+
"files.autoSave": "afterDelay",
|
|
33
|
+
},
|
|
34
|
+
"launch": {
|
|
35
|
+
"version": "0.2.0",
|
|
36
|
+
"configurations": [
|
|
37
|
+
{
|
|
38
|
+
"name": "Python Debugger: Current File",
|
|
39
|
+
"type": "debugpy",
|
|
40
|
+
"request": "launch",
|
|
41
|
+
"program": "main.py",
|
|
42
|
+
"console": "integratedTerminal",
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
"compounds": [],
|
|
46
|
+
},
|
|
47
|
+
"extensions": {
|
|
48
|
+
"recommendations": [
|
|
49
|
+
"donjayamanne.python-extension-pack",
|
|
50
|
+
"charliermarsh.ruff",
|
|
51
|
+
"dbaeumer.vscode-eslint",
|
|
52
|
+
"esbenp.prettier-vscode",
|
|
53
|
+
"tamasfe.even-better-toml",
|
|
54
|
+
"Bar.python-import-helper",
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Standalone example: fetch the channel list via /user/getChannels."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
from SunsetLog import SunsetLogAPIError, SunsetLogClient
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
async def main() -> None:
|
|
10
|
+
token = os.environ["SUNSETLOG_TOKEN"]
|
|
11
|
+
|
|
12
|
+
async with SunsetLogClient(token) as client:
|
|
13
|
+
try:
|
|
14
|
+
result = await client.get_channel_list(gang=1, job=1)
|
|
15
|
+
except SunsetLogAPIError as e:
|
|
16
|
+
print(f"Error: {e} (status={e.status_code})")
|
|
17
|
+
return
|
|
18
|
+
|
|
19
|
+
for channel in result["channels"]:
|
|
20
|
+
print(f"{channel['id']:>6} {channel['index']:<30} {channel['label']}")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
if __name__ == "__main__":
|
|
24
|
+
asyncio.run(main())
|
|
@@ -30,7 +30,7 @@ name = "exceptiongroup"
|
|
|
30
30
|
version = "1.3.1"
|
|
31
31
|
source = { registry = "https://pypi.org/simple" }
|
|
32
32
|
dependencies = [
|
|
33
|
-
{ name = "typing-extensions"
|
|
33
|
+
{ name = "typing-extensions" },
|
|
34
34
|
]
|
|
35
35
|
sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" }
|
|
36
36
|
wheels = [
|
|
@@ -85,7 +85,7 @@ wheels = [
|
|
|
85
85
|
|
|
86
86
|
[[package]]
|
|
87
87
|
name = "sunsetlog"
|
|
88
|
-
version = "0.0.
|
|
88
|
+
version = "0.0.2"
|
|
89
89
|
source = { editable = "." }
|
|
90
90
|
dependencies = [
|
|
91
91
|
{ name = "httpx" },
|
sunsetlog-0.0.1/PKG-INFO
DELETED
sunsetlog-0.0.1/README.md
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"folders": [
|
|
3
|
-
{
|
|
4
|
-
"path": "."
|
|
5
|
-
}
|
|
6
|
-
],
|
|
7
|
-
"settings": {
|
|
8
|
-
"python.analysis.inlayHints.variableTypes": true,
|
|
9
|
-
"python.analysis.autoImportCompletions": true,
|
|
10
|
-
"python.analysis.completeFunctionParens": true,
|
|
11
|
-
"python.analysis.inlayHints.pytestParameters": true,
|
|
12
|
-
"python.analysis.inlayHints.callArgumentNames": "all",
|
|
13
|
-
"python.analysis.inlayHints.functionReturnTypes": true,
|
|
14
|
-
"ruff.enable": true,
|
|
15
|
-
"ruff.format.preview": true,
|
|
16
|
-
"ruff.fixAll": true,
|
|
17
|
-
"ruff.organizeImports": true,
|
|
18
|
-
"ruff.showSyntaxErrors": true,
|
|
19
|
-
"[python]": {
|
|
20
|
-
"editor.defaultFormatter": "charliermarsh.ruff",
|
|
21
|
-
"editor.formatOnSave": true,
|
|
22
|
-
"editor.codeActionsOnSave": {
|
|
23
|
-
"source.fixAll.ruff": "explicit",
|
|
24
|
-
"source.organizeImports.ruff": "explicit",
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
"ruff.configuration": "pyproject.toml",
|
|
28
|
-
|
|
29
|
-
"editor.codeActionsOnSave": {
|
|
30
|
-
"source.fixAll": "explicit",
|
|
31
|
-
"source.organizeImports": "never"
|
|
32
|
-
},
|
|
33
|
-
"remote.localPortHost": "allInterfaces",
|
|
34
|
-
"files.autoSave": "afterDelay",
|
|
35
|
-
"ruff.lineLength": 120,
|
|
36
|
-
},
|
|
37
|
-
"launch": {
|
|
38
|
-
"version": "0.2.0",
|
|
39
|
-
"configurations": [
|
|
40
|
-
{
|
|
41
|
-
"name": "Python Debugger: Current File",
|
|
42
|
-
"type": "debugpy",
|
|
43
|
-
"request": "launch",
|
|
44
|
-
"program": "main.py",
|
|
45
|
-
"console": "integratedTerminal"
|
|
46
|
-
}
|
|
47
|
-
],
|
|
48
|
-
"compounds": []
|
|
49
|
-
},
|
|
50
|
-
"extensions": {
|
|
51
|
-
"recommendations": [
|
|
52
|
-
"donjayamanne.python-extension-pack",
|
|
53
|
-
"charliermarsh.ruff",
|
|
54
|
-
"dbaeumer.vscode-eslint",
|
|
55
|
-
"esbenp.prettier-vscode",
|
|
56
|
-
"tamasfe.even-better-toml",
|
|
57
|
-
"Bar.python-import-helper"
|
|
58
|
-
|
|
59
|
-
]
|
|
60
|
-
}
|
|
61
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|