sing-box-cli 0.0.12__tar.gz → 0.0.13__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.
Files changed (27) hide show
  1. {sing_box_cli-0.0.12 → sing_box_cli-0.0.13}/.pre-commit-config.yaml +2 -2
  2. {sing_box_cli-0.0.12 → sing_box_cli-0.0.13}/CHANGELOG.md +18 -0
  3. {sing_box_cli-0.0.12 → sing_box_cli-0.0.13}/PKG-INFO +1 -1
  4. {sing_box_cli-0.0.12 → sing_box_cli-0.0.13}/config/client-android.json +11 -4
  5. {sing_box_cli-0.0.12 → sing_box_cli-0.0.13}/config/client-linux.json +12 -5
  6. {sing_box_cli-0.0.12 → sing_box_cli-0.0.13}/config/client-server.json +12 -5
  7. {sing_box_cli-0.0.12 → sing_box_cli-0.0.13}/config/client-win.json +12 -5
  8. {sing_box_cli-0.0.12 → sing_box_cli-0.0.13}/config/server.json +3 -0
  9. {sing_box_cli-0.0.12 → sing_box_cli-0.0.13}/pyproject.toml +2 -1
  10. sing_box_cli-0.0.13/scripts/format.sh +5 -0
  11. sing_box_cli-0.0.13/scripts/pre-commit.sh +9 -0
  12. {sing_box_cli-0.0.12 → sing_box_cli-0.0.13}/src/sing_box_service/__init__.py +1 -1
  13. {sing_box_cli-0.0.12 → sing_box_cli-0.0.13}/src/sing_box_service/config.py +42 -2
  14. sing_box_cli-0.0.13/tests/test_config.py +72 -0
  15. {sing_box_cli-0.0.12 → sing_box_cli-0.0.13}/uv.lock +56 -0
  16. sing_box_cli-0.0.12/scripts/format.sh +0 -5
  17. {sing_box_cli-0.0.12 → sing_box_cli-0.0.13}/.github/dependabot.yml +0 -0
  18. {sing_box_cli-0.0.12 → sing_box_cli-0.0.13}/.github/workflows/main.yml +0 -0
  19. {sing_box_cli-0.0.12 → sing_box_cli-0.0.13}/.gitignore +0 -0
  20. {sing_box_cli-0.0.12 → sing_box_cli-0.0.13}/LICENSE +0 -0
  21. {sing_box_cli-0.0.12 → sing_box_cli-0.0.13}/README.md +0 -0
  22. {sing_box_cli-0.0.12 → sing_box_cli-0.0.13}/assets/image.png +0 -0
  23. {sing_box_cli-0.0.12 → sing_box_cli-0.0.13}/scripts/bump.sh +0 -0
  24. {sing_box_cli-0.0.12 → sing_box_cli-0.0.13}/scripts/lint.sh +0 -0
  25. {sing_box_cli-0.0.12 → sing_box_cli-0.0.13}/src/sing_box_service/main.py +0 -0
  26. {sing_box_cli-0.0.12 → sing_box_cli-0.0.13}/src/sing_box_service/py.typed +0 -0
  27. {sing_box_cli-0.0.12 → sing_box_cli-0.0.13}/src/sing_box_service/service.py +0 -0
@@ -29,7 +29,7 @@ repos:
29
29
  files: \.(py|sh|json|yml|yaml|md)$
30
30
 
31
31
  - repo: https://github.com/astral-sh/ruff-pre-commit
32
- rev: v0.9.4
32
+ rev: v0.9.9
33
33
  hooks:
34
34
  - id: ruff
35
35
  args: [--fix]
@@ -37,7 +37,7 @@ repos:
37
37
 
38
38
  - repo: https://github.com/astral-sh/uv-pre-commit
39
39
  # uv version.
40
- rev: 0.5.27
40
+ rev: 0.6.3
41
41
  hooks:
42
42
  # Update the uv lockfile
43
43
  - id: uv-lock
@@ -2,6 +2,24 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## 0.0.13 - 2025-03-08
6
+
7
+ ### 🚀 Features
8
+
9
+ - Show diff after updating config
10
+
11
+ ### 📚 Documentation
12
+
13
+ - Add sniff action
14
+ - Update cloudflare ip
15
+ - Client-server config
16
+ - Update config
17
+ - Update ntp server
18
+
19
+ ### 🧪 Testing
20
+
21
+ - Add tests as scripts target
22
+
5
23
  ## 0.0.12 - 2025-02-28
6
24
 
7
25
  ### 🐛 Bug Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sing-box-cli
3
- Version: 0.0.12
3
+ Version: 0.0.13
4
4
  Summary: cross-platform sing-box-service manager.
5
5
  Project-URL: Homepage, https://github.com/aittcuszz/sing-box-service
6
6
  Project-URL: Issues, https://github.com/atticuszz/sing-box-service/issues
@@ -6,14 +6,20 @@
6
6
  "dns": {
7
7
  "servers": [
8
8
  {
9
- "tag": "dns_direct",
9
+ "tag": "dns_resolver",
10
10
  "address": "h3://223.6.6.6/dns-query",
11
11
  "detour": "direct"
12
12
  },
13
+ {
14
+ "tag": "dns_direct",
15
+ "address": "h3://dns.atticux.me/dns-query/asfljsndfaoifa",
16
+ "address_resolver": "dns_resolver",
17
+ "detour": "direct"
18
+ },
13
19
  {
14
20
  "tag": "dns_proxy",
15
21
  "address": "h3://dns.atticux.me/dns-query/asfljsndfaoifa",
16
- "address_resolver": "dns_direct",
22
+ "address_resolver": "dns_resolver",
17
23
  "client_subnet": "137.184.125.132",
18
24
  "detour": "proxy"
19
25
  },
@@ -51,6 +57,7 @@
51
57
  "reverse_mapping": true,
52
58
  "cache_capacity": 4096,
53
59
  "strategy": "prefer_ipv4",
60
+ "client_subnet": "180.110.148.0/24",
54
61
  "fakeip": {
55
62
  "enabled": true,
56
63
  "inet4_range": "198.18.0.0/15",
@@ -109,7 +116,7 @@
109
116
  "tag": "🌟San Francisco WS",
110
117
  "tcp_fast_open": true,
111
118
  "udp_fragment": true,
112
- "server": "172.66.45.88",
119
+ "server": "104.19.255.210",
113
120
  "server_port": 2053,
114
121
  "uuid": "6a5f528d-1641-406f-95b8-ee9c574d79b3",
115
122
  "tls": {
@@ -130,7 +137,7 @@
130
137
  {
131
138
  "type": "vless",
132
139
  "tag": "🌩️San Francisco WS",
133
- "server": "104.23.96.99",
140
+ "server": "104.24.13.124",
134
141
  "server_port": 443,
135
142
  "uuid": "717f9e5c-9922-49a0-aa12-3fa17d63a7a8",
136
143
  "tls": {
@@ -6,14 +6,20 @@
6
6
  "dns": {
7
7
  "servers": [
8
8
  {
9
- "tag": "dns_direct",
9
+ "tag": "dns_resolver",
10
10
  "address": "h3://223.6.6.6/dns-query",
11
11
  "detour": "direct"
12
12
  },
13
+ {
14
+ "tag": "dns_direct",
15
+ "address": "h3://dns.atticux.me/dns-query/asfljsndfaoifa",
16
+ "address_resolver": "dns_resolver",
17
+ "detour": "direct"
18
+ },
13
19
  {
14
20
  "tag": "dns_proxy",
15
21
  "address": "h3://dns.atticux.me/dns-query/asfljsndfaoifa",
16
- "address_resolver": "dns_direct",
22
+ "address_resolver": "dns_resolver",
17
23
  "client_subnet": "137.184.125.132",
18
24
  "detour": "proxy"
19
25
  },
@@ -51,6 +57,7 @@
51
57
  "reverse_mapping": true,
52
58
  "cache_capacity": 4096,
53
59
  "strategy": "prefer_ipv4",
60
+ "client_subnet": "180.110.148.0/24",
54
61
  "fakeip": {
55
62
  "enabled": true,
56
63
  "inet4_range": "198.18.0.0/15",
@@ -61,7 +68,7 @@
61
68
  "ntp": {
62
69
  "enabled": true,
63
70
  "interval": "30m0s",
64
- "server": "time.tencent.com",
71
+ "server": "time.cloudflare.com",
65
72
  "write_to_system": true,
66
73
  "server_port": 123
67
74
  },
@@ -102,7 +109,7 @@
102
109
  "tag": "🌟San Francisco WS",
103
110
  "tcp_fast_open": true,
104
111
  "udp_fragment": true,
105
- "server": "172.66.45.88",
112
+ "server": "104.19.255.210",
106
113
  "server_port": 2053,
107
114
  "uuid": "6a5f528d-1641-406f-95b8-ee9c574d79b3",
108
115
  "tls": {
@@ -123,7 +130,7 @@
123
130
  {
124
131
  "type": "vless",
125
132
  "tag": "🌩️San Francisco WS",
126
- "server": "104.23.96.99",
133
+ "server": "104.24.13.124",
127
134
  "server_port": 443,
128
135
  "uuid": "717f9e5c-9922-49a0-aa12-3fa17d63a7a8",
129
136
  "tls": {
@@ -6,16 +6,22 @@
6
6
  "dns": {
7
7
  "servers": [
8
8
  {
9
- "tag": "dns_direct",
9
+ "tag": "dns_resolver",
10
10
  "address": "h3://223.6.6.6/dns-query",
11
11
  "detour": "direct"
12
12
  },
13
+ {
14
+ "tag": "dns_direct",
15
+ "address": "h3://dns.atticux.me/dns-query/asfljsndfaoifa",
16
+ "address_resolver": "dns_resolver",
17
+ "detour": "direct"
18
+ },
13
19
  {
14
20
  "tag": "dns_proxy",
15
21
  "address": "h3://dns.atticux.me/dns-query/asfljsndfaoifa",
16
- "address_resolver": "dns_direct",
22
+ "address_resolver": "dns_resolver",
17
23
  "client_subnet": "137.184.125.132",
18
- "detour": "⚡San Francisco Hy2"
24
+ "detour": "proxy"
19
25
  },
20
26
  {
21
27
  "tag": "dns_fakeip",
@@ -51,6 +57,7 @@
51
57
  "reverse_mapping": true,
52
58
  "cache_capacity": 4096,
53
59
  "strategy": "prefer_ipv4",
60
+ "client_subnet": "180.110.148.0/24",
54
61
  "fakeip": {
55
62
  "enabled": true,
56
63
  "inet4_range": "198.18.0.0/15",
@@ -90,7 +97,7 @@
90
97
  "tag": "🌟San Francisco WS",
91
98
  "tcp_fast_open": true,
92
99
  "udp_fragment": true,
93
- "server": "104.23.96.99",
100
+ "server": "104.19.255.210",
94
101
  "server_port": 2053,
95
102
  "uuid": "6a5f528d-1641-406f-95b8-ee9c574d79b3",
96
103
  "tls": {
@@ -111,7 +118,7 @@
111
118
  {
112
119
  "type": "vless",
113
120
  "tag": "🌩️San Francisco WS",
114
- "server": "104.23.96.99",
121
+ "server": "104.24.13.124",
115
122
  "server_port": 443,
116
123
  "uuid": "717f9e5c-9922-49a0-aa12-3fa17d63a7a8",
117
124
  "tls": {
@@ -6,14 +6,20 @@
6
6
  "dns": {
7
7
  "servers": [
8
8
  {
9
- "tag": "dns_direct",
9
+ "tag": "dns_resolver",
10
10
  "address": "h3://223.6.6.6/dns-query",
11
11
  "detour": "direct"
12
12
  },
13
+ {
14
+ "tag": "dns_direct",
15
+ "address": "h3://dns.atticux.me/dns-query/asfljsndfaoifa",
16
+ "address_resolver": "dns_resolver",
17
+ "detour": "direct"
18
+ },
13
19
  {
14
20
  "tag": "dns_proxy",
15
21
  "address": "h3://dns.atticux.me/dns-query/asfljsndfaoifa",
16
- "address_resolver": "dns_direct",
22
+ "address_resolver": "dns_resolver",
17
23
  "client_subnet": "137.184.125.132",
18
24
  "detour": "proxy"
19
25
  },
@@ -51,6 +57,7 @@
51
57
  "reverse_mapping": true,
52
58
  "cache_capacity": 4096,
53
59
  "strategy": "prefer_ipv4",
60
+ "client_subnet": "180.110.148.0/24",
54
61
  "fakeip": {
55
62
  "enabled": true,
56
63
  "inet4_range": "198.18.0.0/15",
@@ -61,7 +68,7 @@
61
68
  "ntp": {
62
69
  "enabled": true,
63
70
  "interval": "30m0s",
64
- "server": "time.tencent.com",
71
+ "server": "time.cloudflare.com",
65
72
  "write_to_system": true,
66
73
  "server_port": 123
67
74
  },
@@ -101,7 +108,7 @@
101
108
  "tag": "🌟San Francisco WS",
102
109
  "tcp_fast_open": true,
103
110
  "udp_fragment": true,
104
- "server": "172.66.45.88",
111
+ "server": "104.19.255.210",
105
112
  "server_port": 2053,
106
113
  "uuid": "6a5f528d-1641-406f-95b8-ee9c574d79b3",
107
114
  "tls": {
@@ -122,7 +129,7 @@
122
129
  {
123
130
  "type": "vless",
124
131
  "tag": "🌩️San Francisco WS",
125
- "server": "104.23.96.99",
132
+ "server": "104.24.13.124",
126
133
  "server_port": 443,
127
134
  "uuid": "717f9e5c-9922-49a0-aa12-3fa17d63a7a8",
128
135
  "tls": {
@@ -87,6 +87,9 @@
87
87
  ],
88
88
  "route": {
89
89
  "rules": [
90
+ {
91
+ "action": "sniff"
92
+ },
90
93
  {
91
94
  "domain_suffix": [
92
95
  "kaggle.com",
@@ -58,6 +58,7 @@ dev = [
58
58
  "typos>=1.26.8",
59
59
  "types-psutil>=6.1.0.20241221",
60
60
  "types-requests>=2.32.0.20241016",
61
+ "pytest>=8.3.5",
61
62
  ]
62
63
 
63
64
  [tool.hatch.version]
@@ -209,7 +210,7 @@ sort_commits = "oldest"
209
210
 
210
211
 
211
212
  [tool.bumpversion]
212
- current_version = "0.0.12"
213
+ current_version = "0.0.13"
213
214
  parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
214
215
  serialize = ["{major}.{minor}.{patch}"]
215
216
  search = "{current_version}"
@@ -0,0 +1,5 @@
1
+ #!/bin/sh -e
2
+ set -x
3
+
4
+ ruff check src tests --fix
5
+ ruff format src tests
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+ set -x
5
+
6
+ pre-commit run --all-files
7
+ bash scripts/format.sh
8
+ bash scripts/lint.sh
9
+ pytest
@@ -2,4 +2,4 @@ from .main import main
2
2
 
3
3
  __all__ = ["main"]
4
4
 
5
- __version__ = "0.0.12"
5
+ __version__ = "0.0.13"
@@ -59,18 +59,31 @@ class Config:
59
59
  return self.subscription_file.read_text().strip()
60
60
 
61
61
  def update_config(self) -> bool:
62
+ """download configuration from subscription URL and show differences"""
62
63
  if not self.sub_url:
63
64
  print("❌ No valid subscription URL found.")
64
65
  return False
65
66
 
67
+ current_config = (
68
+ self.config_file.read_text(encoding="utf-8")
69
+ if self.config_file.exists()
70
+ else "{}"
71
+ )
66
72
  print(f"⌛ Updating configuration from {self.sub_url}")
67
73
  try:
68
74
  response = requests.get(self.sub_url)
69
75
  response.raise_for_status()
70
- self.config_file.write_text(response.text, encoding="utf-8")
76
+ new_config = response.text
77
+ self.config_file.write_text(new_config, encoding="utf-8")
71
78
  if not self.is_windows:
72
79
  shutil.chown(self.config_file, user=self.user, group=self.user)
73
- print("✅ Configuration updated successfully.")
80
+
81
+ if current_config == new_config:
82
+ print("📄 Configuration is up to date.")
83
+ else:
84
+ show_diff_config(current_config, new_config)
85
+ print("🔄 Configuration updated successfully")
86
+
74
87
  return True
75
88
  except Exception as e:
76
89
  print(f"❌ Failed to update configuration: {e}")
@@ -101,3 +114,30 @@ class Config:
101
114
  print("🗑️ Cache database removed.")
102
115
  else:
103
116
  print("❌ Cache database not found.")
117
+
118
+
119
+ def show_diff_config(current_config: str, new_config: str) -> None:
120
+ print("📄 Configuration differences:")
121
+ from difflib import unified_diff
122
+
123
+ diff = list(
124
+ unified_diff(
125
+ current_config.splitlines(),
126
+ new_config.splitlines(),
127
+ fromfile="old",
128
+ tofile="new",
129
+ lineterm="",
130
+ )
131
+ )
132
+
133
+ for line in diff:
134
+ if line.startswith("+"):
135
+ print(f"[green]{line}[/green]")
136
+ elif line.startswith("-"):
137
+ print(f"[red]{line}[/red]")
138
+ elif line.startswith("@@"):
139
+ print(f"[blue]{line}[/blue]")
140
+ elif line.startswith(("---", "+++")):
141
+ print(f"[dim]{line}[/dim]")
142
+ else:
143
+ print(f"[white]{line}[/white]")
@@ -0,0 +1,72 @@
1
+ import pytest
2
+
3
+ from sing_box_service.config import show_diff_config
4
+
5
+
6
+ def test_show_diff_config(capsys: pytest.CaptureFixture[str]) -> None:
7
+ # Test with complex configs and sensitive data changes
8
+ current = """{
9
+ "outbounds": [
10
+ {
11
+ "type": "vless",
12
+ "tag": "🌟Server WS",
13
+ "server": "104.19.255.210",
14
+ "uuid": "old-uuid-value",
15
+ "tls": {
16
+ "server_name": "cdn.example.com"
17
+ }
18
+ }
19
+ ]
20
+ }"""
21
+
22
+ new = """{
23
+ "outbounds": [
24
+ {
25
+ "type": "vless",
26
+ "tag": "🌟Server WS",
27
+ "server": "104.19.255.210",
28
+ "uuid": "new-uuid-value",
29
+ "tls": {
30
+ "server_name": "cdn.example.com"
31
+ }
32
+ }
33
+ ]
34
+ }"""
35
+
36
+ # Call function
37
+ show_diff_config(current, new)
38
+
39
+ # Get printed output
40
+ captured = capsys.readouterr()
41
+ output = captured.out
42
+
43
+ # Verify output contains key elements
44
+ assert "📄 Configuration differences:" in output
45
+ assert "---" in output # unified diff header
46
+ assert "+++" in output # unified diff header
47
+ assert '- "uuid": "old-uuid-value",' in output
48
+ assert '+ "uuid": "new-uuid-value",' in output
49
+
50
+
51
+ def test_show_diff_config_no_changes(capsys: pytest.CaptureFixture[str]) -> None:
52
+ # Test with identical configs
53
+ config = """{"key": "value"}"""
54
+
55
+ show_diff_config(config, config)
56
+
57
+ captured = capsys.readouterr()
58
+ output = captured.out
59
+
60
+ assert "📄 Configuration differences:" in output
61
+ assert len(output.splitlines()) == 1 # Only header line
62
+
63
+
64
+ def test_show_diff_config_empty(capsys: pytest.CaptureFixture[str]) -> None:
65
+ # Test with empty configs
66
+ show_diff_config("", "")
67
+
68
+ captured = capsys.readouterr()
69
+ output = captured.out
70
+
71
+ assert "📄 Configuration differences:" in output
72
+ assert len(output.splitlines()) == 1 # Only header line
@@ -1,4 +1,5 @@
1
1
  version = 1
2
+ revision = 1
2
3
  requires-python = ">=3.10"
3
4
  resolution-markers = [
4
5
  "sys_platform == 'win32'",
@@ -151,6 +152,15 @@ wheels = [
151
152
  { url = "https://files.pythonhosted.org/packages/91/a1/cf2472db20f7ce4a6be1253a81cfdf85ad9c7885ffbed7047fb72c24cf87/distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", size = 468973 },
152
153
  ]
153
154
 
155
+ [[package]]
156
+ name = "exceptiongroup"
157
+ version = "1.2.2"
158
+ source = { registry = "https://pypi.org/simple" }
159
+ sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 }
160
+ wheels = [
161
+ { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 },
162
+ ]
163
+
154
164
  [[package]]
155
165
  name = "filelock"
156
166
  version = "3.16.1"
@@ -193,6 +203,15 @@ wheels = [
193
203
  { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 },
194
204
  ]
195
205
 
206
+ [[package]]
207
+ name = "iniconfig"
208
+ version = "2.0.0"
209
+ source = { registry = "https://pypi.org/simple" }
210
+ sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 }
211
+ wheels = [
212
+ { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 },
213
+ ]
214
+
196
215
  [[package]]
197
216
  name = "markdown-it-py"
198
217
  version = "3.0.0"
@@ -262,6 +281,15 @@ wheels = [
262
281
  { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314 },
263
282
  ]
264
283
 
284
+ [[package]]
285
+ name = "packaging"
286
+ version = "24.2"
287
+ source = { registry = "https://pypi.org/simple" }
288
+ sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 }
289
+ wheels = [
290
+ { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 },
291
+ ]
292
+
265
293
  [[package]]
266
294
  name = "platformdirs"
267
295
  version = "4.3.6"
@@ -271,6 +299,15 @@ wheels = [
271
299
  { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 },
272
300
  ]
273
301
 
302
+ [[package]]
303
+ name = "pluggy"
304
+ version = "1.5.0"
305
+ source = { registry = "https://pypi.org/simple" }
306
+ sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 }
307
+ wheels = [
308
+ { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 },
309
+ ]
310
+
274
311
  [[package]]
275
312
  name = "pre-commit"
276
313
  version = "4.0.1"
@@ -413,6 +450,23 @@ wheels = [
413
450
  { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 },
414
451
  ]
415
452
 
453
+ [[package]]
454
+ name = "pytest"
455
+ version = "8.3.5"
456
+ source = { registry = "https://pypi.org/simple" }
457
+ dependencies = [
458
+ { name = "colorama", marker = "sys_platform == 'win32'" },
459
+ { name = "exceptiongroup", marker = "(python_full_version < '3.11' and sys_platform == 'linux') or (python_full_version < '3.11' and sys_platform == 'win32')" },
460
+ { name = "iniconfig", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
461
+ { name = "packaging", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
462
+ { name = "pluggy", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
463
+ { name = "tomli", marker = "(python_full_version < '3.11' and sys_platform == 'linux') or (python_full_version < '3.11' and sys_platform == 'win32')" },
464
+ ]
465
+ sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891 }
466
+ wheels = [
467
+ { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634 },
468
+ ]
469
+
416
470
  [[package]]
417
471
  name = "python-dotenv"
418
472
  version = "1.0.1"
@@ -560,6 +614,7 @@ dev = [
560
614
  { name = "git-cliff", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
561
615
  { name = "mypy", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
562
616
  { name = "pre-commit", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
617
+ { name = "pytest", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
563
618
  { name = "ruff", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
564
619
  { name = "types-psutil", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
565
620
  { name = "types-requests", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -579,6 +634,7 @@ dev = [
579
634
  { name = "git-cliff", specifier = ">=2.6.1" },
580
635
  { name = "mypy", specifier = ">=1.11.2" },
581
636
  { name = "pre-commit", specifier = ">=3.8.0" },
637
+ { name = "pytest", specifier = ">=8.3.5" },
582
638
  { name = "ruff", specifier = ">=0.6.3" },
583
639
  { name = "types-psutil", specifier = ">=6.1.0.20241221" },
584
640
  { name = "types-requests", specifier = ">=2.32.0.20241016" },
@@ -1,5 +0,0 @@
1
- #!/bin/sh -e
2
- set -x
3
-
4
- ruff check src --fix
5
- ruff format src
File without changes
File without changes
File without changes