git-cai-cli 0.7.2__tar.gz → 0.7.4__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 (72) hide show
  1. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.github/cd/.SRCINFO +1 -4
  2. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.github/cd/PKGBUILD +1 -4
  3. {git_cai_cli-0.7.2/src/git_cai_cli.egg-info → git_cai_cli-0.7.4}/PKG-INFO +1 -4
  4. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/pyproject.toml +0 -3
  5. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/src/git_cai_cli/_version.py +3 -3
  6. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/src/git_cai_cli/core/llm.py +86 -46
  7. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4/src/git_cai_cli.egg-info}/PKG-INFO +1 -4
  8. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/src/git_cai_cli.egg-info/requires.txt +0 -3
  9. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/tests/unit/test_llm.py +133 -28
  10. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/uv.lock +0 -191
  11. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.caiignore +0 -0
  12. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.gitattributes +0 -0
  13. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.github/ci/_version.py +0 -0
  14. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.github/ci/cai_config.ci.yml +0 -0
  15. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.github/ci/tokens.ci.yml +0 -0
  16. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.github/workflows/python-tests.yml +0 -0
  17. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.github/workflows/release.yml +0 -0
  18. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.github/workflows/release_aur.yml +0 -0
  19. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.gitignore +0 -0
  20. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.linters/.bandit.yml +0 -0
  21. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.linters/.checkov.yml +0 -0
  22. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.linters/.flake8 +0 -0
  23. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.linters/.ls-lint.yml +0 -0
  24. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.linters/.markdown-link-check.json +0 -0
  25. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.linters/.markdownlint.json +0 -0
  26. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.linters/.proselintrc +0 -0
  27. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.linters/.pylintrc +0 -0
  28. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.linters/.yamllint.yml +0 -0
  29. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.linters/check_git_branch_name.sh +0 -0
  30. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.linters/lychee.toml +0 -0
  31. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.linters/pyrightconfig.json +0 -0
  32. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.mega-linter.yml +0 -0
  33. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.semgrepignore +0 -0
  34. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/.trivyignore +0 -0
  35. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/LICENSE +0 -0
  36. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/Makefile +0 -0
  37. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/README.md +0 -0
  38. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/docs/git-cai.txt +0 -0
  39. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/docs/man/git-cai.1 +0 -0
  40. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/setup.cfg +0 -0
  41. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/src/git_cai_cli/__init__.py +0 -0
  42. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/src/git_cai_cli/cli/__init__.py +0 -0
  43. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/src/git_cai_cli/cli/cli.py +0 -0
  44. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/src/git_cai_cli/cli/helptext.py +0 -0
  45. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/src/git_cai_cli/cli/modes.py +0 -0
  46. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/src/git_cai_cli/core/__init__.py +0 -0
  47. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/src/git_cai_cli/core/config.py +0 -0
  48. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/src/git_cai_cli/core/editors.py +0 -0
  49. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/src/git_cai_cli/core/gitutils.py +0 -0
  50. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/src/git_cai_cli/core/languages.py +0 -0
  51. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/src/git_cai_cli/core/options.py +0 -0
  52. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/src/git_cai_cli/core/squash.py +0 -0
  53. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/src/git_cai_cli/core/validate.py +0 -0
  54. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/src/git_cai_cli/main.py +0 -0
  55. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/src/git_cai_cli.egg-info/SOURCES.txt +0 -0
  56. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/src/git_cai_cli.egg-info/dependency_links.txt +0 -0
  57. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/src/git_cai_cli.egg-info/entry_points.txt +0 -0
  58. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/src/git_cai_cli.egg-info/top_level.txt +0 -0
  59. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/tests/integration/test_cli_integration.py +0 -0
  60. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/tests/integration/test_config_integration.py +0 -0
  61. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/tests/integration/test_gitutils_integration.py +0 -0
  62. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/tests/integration/test_modes_integration.py +0 -0
  63. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/tests/integration/test_options_integration.py +0 -0
  64. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/tests/integration/test_squash_integration.py +0 -0
  65. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/tests/unit/test_cli.py +0 -0
  66. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/tests/unit/test_config.py +0 -0
  67. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/tests/unit/test_gitutils.py +0 -0
  68. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/tests/unit/test_helptext.py +0 -0
  69. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/tests/unit/test_modes.py +0 -0
  70. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/tests/unit/test_options.py +0 -0
  71. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/tests/unit/test_squash.py +0 -0
  72. {git_cai_cli-0.7.2 → git_cai_cli-0.7.4}/tests/unit/test_validate.py +0 -0
@@ -1,5 +1,5 @@
1
1
  pkgbase = cai
2
- pkgdesc = Use LLM to create git commit messages.
2
+ pkgdesc = CLI tool that generates concise git commit messages from diffs or commit history using large language models
3
3
  pkgver = Y.Y.Y
4
4
  pkgrel = 1
5
5
  url = https://github.com/thorstenfoltz/cai
@@ -13,11 +13,8 @@ pkgbase = cai
13
13
  depends = python
14
14
  depends = python-yaml
15
15
  depends = python-openai
16
- depends = python-google-genai
17
16
  depends = python-requests
18
17
  depends = python-typer
19
- depends = python-groq
20
- depends = python-anthropic
21
18
  depends = git
22
19
  source = cai-Y.Y.Y.tar.gz::https://github.com/thorstenfoltz/cai/archive/refs/tags/Y.Y.Y.tar.gz
23
20
  sha256sums = YYYYYY
@@ -3,7 +3,7 @@
3
3
  pkgname=cai
4
4
  pkgver=X.X.X
5
5
  pkgrel=1
6
- pkgdesc="Use LLM to create git commit messages."
6
+ pkgdesc="CLI tool that generates concise git commit messages from diffs or commit history using large language models"
7
7
  arch=('any')
8
8
  url="https://github.com/thorstenfoltz/cai"
9
9
  license=('MIT')
@@ -11,11 +11,8 @@ depends=(
11
11
  python
12
12
  python-yaml
13
13
  python-openai
14
- python-google-genai
15
14
  python-requests
16
15
  python-typer
17
- python-groq
18
- python-anthropic
19
16
  git
20
17
  )
21
18
  makedepends=(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: git-cai-cli
3
- Version: 0.7.2
3
+ Version: 0.7.4
4
4
  Summary: Use LLM to create git commit messages
5
5
  Author-email: Thorsten Foltz <thorsten.foltz@live.com>
6
6
  License-Expression: MIT
@@ -23,11 +23,8 @@ Description-Content-Type: text/markdown
23
23
  License-File: LICENSE
24
24
  Requires-Dist: pyyaml>=6.0
25
25
  Requires-Dist: openai>=1.0
26
- Requires-Dist: google-genai>=1.39
27
26
  Requires-Dist: typer>=0.19.2
28
27
  Requires-Dist: requests>=2.32.5
29
- Requires-Dist: anthropic>=0.75.0
30
- Requires-Dist: groq>=0.37.0
31
28
  Dynamic: license-file
32
29
 
33
30
  # cai
@@ -9,11 +9,8 @@ requires-python = ">=3.10"
9
9
  dependencies = [
10
10
  "pyyaml>=6.0",
11
11
  "openai>=1.0",
12
- "google-genai>=1.39",
13
12
  "typer>=0.19.2",
14
13
  "requests>=2.32.5",
15
- "anthropic>=0.75.0",
16
- "groq>=0.37.0",
17
14
  ]
18
15
  license = "MIT"
19
16
  classifiers = [
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.7.2'
32
- __version_tuple__ = version_tuple = (0, 7, 2)
31
+ __version__ = version = '0.7.4'
32
+ __version_tuple__ = version_tuple = (0, 7, 4)
33
33
 
34
- __commit_id__ = commit_id = 'g474d0e433'
34
+ __commit_id__ = commit_id = 'g641c4cec4'
@@ -7,11 +7,7 @@ from collections.abc import Callable
7
7
  from typing import Any, Dict, Optional, Type
8
8
 
9
9
  import requests
10
- from anthropic import Anthropic
11
10
  from git_cai_cli.core.languages import LANGUAGE_MAP
12
- from google import genai # type: ignore[reportUnknownImport]
13
- from google.genai import types # type: ignore[reportUnknownImport]
14
- from groq import Groq
15
11
  from openai import OpenAI
16
12
 
17
13
  log = logging.getLogger(__name__)
@@ -131,34 +127,50 @@ class CommitMessageGenerator:
131
127
  def generate_anthropic(
132
128
  self,
133
129
  content: str,
134
- anthropic_cls: Type[Any] = Anthropic,
135
130
  system_prompt_override: Optional[str] = None,
136
131
  ) -> str:
137
132
  """
138
133
  Shared Anthropic call for commit generation or commit history summarization.
134
+ Uses direct HTTP API instead of the Anthropic SDK.
139
135
  """
140
- client = anthropic_cls(api_key=self.token)
136
+ url = "https://api.anthropic.com/v1/messages"
137
+ headers = {
138
+ "Content-Type": "application/json",
139
+ "x-api-key": self.token,
140
+ "anthropic-version": "2023-06-01",
141
+ }
142
+
141
143
  model = self.config["anthropic"]["model"]
142
144
  temperature = self.config["anthropic"]["temperature"]
143
145
 
144
- prompt = [
145
- {
146
- "role": "assistant",
147
- "content": system_prompt_override,
148
- },
146
+ messages = []
147
+
148
+ if system_prompt_override:
149
+ messages.append(
150
+ {
151
+ "role": "assistant",
152
+ "content": system_prompt_override,
153
+ }
154
+ )
155
+
156
+ messages.append(
149
157
  {
150
158
  "role": "user",
151
159
  "content": content,
152
- },
153
- ]
154
-
155
- response = client.messages.create(
156
- model=model,
157
- messages=prompt,
158
- temperature=temperature,
159
- max_tokens=4096, # this field is required by Anthropic API
160
+ }
160
161
  )
161
- return response.content[0].text.strip()
162
+
163
+ request = {
164
+ "model": model,
165
+ "max_tokens": 8192,
166
+ "temperature": temperature,
167
+ "messages": messages,
168
+ }
169
+
170
+ response = requests.post(url, json=request, headers=headers, timeout=30)
171
+ response.raise_for_status()
172
+
173
+ return response.json()["content"][0]["text"].strip()
162
174
 
163
175
  def generate_deepseek(
164
176
  self,
@@ -180,56 +192,84 @@ class CommitMessageGenerator:
180
192
  def generate_gemini(
181
193
  self,
182
194
  content: str,
183
- genai_cls: Type[Any] = genai.Client,
184
195
  system_prompt_override: Optional[str] = None,
185
196
  ) -> str:
186
197
  """
187
198
  Shared Gemini call for commit generation or commit history summarization.
199
+ Uses direct HTTP API instead of the Google SDK.
188
200
  """
189
- client = genai_cls(api_key=self.token)
190
201
  model = self.config["gemini"]["model"]
191
202
  temperature = self.config["gemini"]["temperature"]
192
203
 
193
- response = client.models.generate_content(
194
- model=model,
195
- contents=content,
196
- config=types.GenerateContentConfig(
197
- system_instruction=system_prompt_override,
198
- temperature=temperature,
199
- ),
200
- )
201
- return response.text
204
+ url = f"https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent"
205
+
206
+ headers = {
207
+ "Content-Type": "application/json",
208
+ "x-goog-api-key": self.token,
209
+ }
210
+
211
+ text = content
212
+ if system_prompt_override:
213
+ text = f"{system_prompt_override}\n\n{text}"
214
+
215
+ request = {
216
+ "contents": [{"parts": [{"text": text}]}],
217
+ "generationConfig": {
218
+ "temperature": temperature,
219
+ },
220
+ }
221
+
222
+ response = requests.post(url, json=request, headers=headers, timeout=30)
223
+ response.raise_for_status()
224
+
225
+ return response.json()["candidates"][0]["content"]["parts"][0]["text"].strip()
202
226
 
203
227
  def generate_groq(
204
228
  self,
205
229
  content: str,
206
- genai_cls: Type[Any] = Groq,
207
230
  system_prompt_override: Optional[str] = None,
208
231
  ) -> str:
209
232
  """
210
233
  Shared Groq call for commit generation or commit history summarization.
234
+ Uses direct HTTP API instead of the Groq SDK.
211
235
  """
212
- client = genai_cls(api_key=self.token)
236
+ url = "https://api.groq.com/openai/v1/chat/completions"
237
+
238
+ headers = {
239
+ "Content-Type": "application/json",
240
+ "Authorization": f"Bearer {self.token}",
241
+ }
242
+
213
243
  model = self.config["groq"]["model"]
214
244
  temperature = self.config["groq"]["temperature"]
215
245
 
216
- prompt = [
217
- {
218
- "role": "system",
219
- "content": system_prompt_override,
220
- },
246
+ messages = []
247
+
248
+ if system_prompt_override:
249
+ messages.append(
250
+ {
251
+ "role": "system",
252
+ "content": system_prompt_override,
253
+ }
254
+ )
255
+
256
+ messages.append(
221
257
  {
222
258
  "role": "user",
223
259
  "content": content,
224
- },
225
- ]
226
-
227
- response = client.chat.completions.create(
228
- model=model,
229
- messages=prompt,
230
- temperature=temperature,
260
+ }
231
261
  )
232
- return response.choices[0].message.content.strip()
262
+
263
+ request = {
264
+ "model": model,
265
+ "messages": messages,
266
+ "temperature": temperature,
267
+ }
268
+
269
+ response = requests.post(url, json=request, headers=headers, timeout=30)
270
+ response.raise_for_status()
271
+
272
+ return response.json()["choices"][0]["message"]["content"].strip()
233
273
 
234
274
  def generate_mistral(
235
275
  self,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: git-cai-cli
3
- Version: 0.7.2
3
+ Version: 0.7.4
4
4
  Summary: Use LLM to create git commit messages
5
5
  Author-email: Thorsten Foltz <thorsten.foltz@live.com>
6
6
  License-Expression: MIT
@@ -23,11 +23,8 @@ Description-Content-Type: text/markdown
23
23
  License-File: LICENSE
24
24
  Requires-Dist: pyyaml>=6.0
25
25
  Requires-Dist: openai>=1.0
26
- Requires-Dist: google-genai>=1.39
27
26
  Requires-Dist: typer>=0.19.2
28
27
  Requires-Dist: requests>=2.32.5
29
- Requires-Dist: anthropic>=0.75.0
30
- Requires-Dist: groq>=0.37.0
31
28
  Dynamic: license-file
32
29
 
33
30
  # cai
@@ -1,7 +1,4 @@
1
1
  pyyaml>=6.0
2
2
  openai>=1.0
3
- google-genai>=1.39
4
3
  typer>=0.19.2
5
4
  requests>=2.32.5
6
- anthropic>=0.75.0
7
- groq>=0.37.0
@@ -153,60 +153,165 @@ def test_generate_openai(generator):
153
153
 
154
154
 
155
155
  # test anthropic
156
- def test_generate_anthropic(generator):
156
+ def test_generate_anthropic():
157
157
  """
158
158
  Test that the generate_anthropic method returns the correct message text
159
159
  """
160
- mock_cls = MagicMock()
161
- mock_client = MagicMock()
160
+ config = {
161
+ "anthropic": {
162
+ "model": "claude-sonnet-4-5",
163
+ "temperature": 0.7,
164
+ }
165
+ }
162
166
 
163
- mock_response = MagicMock()
164
- mock_response.content = [MagicMock(text=" test ")]
167
+ gen = CommitMessageGenerator(
168
+ token="fake-token",
169
+ config=config,
170
+ default_model="anthropic",
171
+ )
165
172
 
166
- mock_client.messages.create.return_value = mock_response
167
- mock_cls.return_value = mock_client
173
+ module_path = CommitMessageGenerator.__module__
174
+
175
+ mock_post = MagicMock()
176
+ mock_post.return_value.json.return_value = {
177
+ "content": [{"text": " test "}],
178
+ }
179
+
180
+ with patch(f"{module_path}.requests.post", mock_post):
181
+ result = gen.generate_anthropic("abc", system_prompt_override="sys")
168
182
 
169
- result = generator.generate_anthropic(
170
- "abc", anthropic_cls=mock_cls, system_prompt_override="sys"
171
- )
172
183
  assert result == "test"
173
- mock_client.messages.create.assert_called_once()
184
+ mock_post.assert_called_once()
185
+
186
+ # --- Extract call details ---
187
+ args, kwargs = mock_post.call_args
188
+
189
+ # Positional arg 0 = URL
190
+ called_url = args[0]
191
+ assert called_url == "https://api.anthropic.com/v1/messages"
192
+
193
+ assert kwargs["timeout"] == 30
194
+
195
+ assert kwargs["headers"] == {
196
+ "Content-Type": "application/json",
197
+ "x-api-key": "fake-token",
198
+ "anthropic-version": "2023-06-01",
199
+ }
200
+
201
+ assert kwargs["json"] == {
202
+ "model": "claude-sonnet-4-5",
203
+ "max_tokens": 8192,
204
+ "temperature": 0.7,
205
+ "messages": [
206
+ {"role": "assistant", "content": "sys"},
207
+ {"role": "user", "content": "abc"},
208
+ ],
209
+ }
174
210
 
175
211
 
176
212
  # test gemini
177
- def test_generate_gemini(generator):
213
+ def test_generate_gemini():
178
214
  """
179
215
  Test that the generate_gemini method returns the correct message text
180
216
  """
181
- mock_cls = MagicMock()
182
- mock_client = MagicMock()
183
-
184
- mock_client.models.generate_content.return_value = MagicMock(text="gemini text")
185
- mock_cls.return_value = mock_client
217
+ config = {
218
+ "gemini": {
219
+ "model": "gemini-2.5-flash",
220
+ "temperature": 0.6,
221
+ }
222
+ }
186
223
 
187
- result = generator.generate_gemini(
188
- "abc", genai_cls=mock_cls, system_prompt_override="sys"
224
+ gen = CommitMessageGenerator(
225
+ token="fake-token",
226
+ config=config,
227
+ default_model="gemini",
189
228
  )
229
+
230
+ module_path = CommitMessageGenerator.__module__
231
+
232
+ mock_post = MagicMock()
233
+ mock_post.return_value.json.return_value = {
234
+ "candidates": [{"content": {"parts": [{"text": " gemini text "}]}}]
235
+ }
236
+
237
+ with patch(f"{module_path}.requests.post", mock_post):
238
+ result = gen.generate_gemini("abc", system_prompt_override="sys")
239
+
190
240
  assert result == "gemini text"
241
+ mock_post.assert_called_once()
242
+
243
+ args, kwargs = mock_post.call_args
244
+
245
+ assert args[0] == (
246
+ "https://generativelanguage.googleapis.com/v1beta/"
247
+ "models/gemini-2.5-flash:generateContent"
248
+ )
249
+
250
+ assert kwargs["timeout"] == 30
251
+
252
+ assert kwargs["headers"] == {
253
+ "Content-Type": "application/json",
254
+ "x-goog-api-key": "fake-token",
255
+ }
256
+
257
+ assert kwargs["json"] == {
258
+ "contents": [{"parts": [{"text": "sys\n\nabc"}]}],
259
+ "generationConfig": {
260
+ "temperature": 0.6,
261
+ },
262
+ }
191
263
 
192
264
 
193
265
  # test groq
194
- def test_generate_groq(generator):
266
+ def test_generate_groq():
195
267
  """
196
268
  Test that the generate_groq method returns the correct message text
197
269
  """
198
- mock_cls = MagicMock()
199
- mock_client = MagicMock()
270
+ config = {
271
+ "groq": {
272
+ "model": "llama-3.3-70b-versatile",
273
+ "temperature": 0.7,
274
+ }
275
+ }
200
276
 
201
- mock_client.chat.completions.create.return_value = MagicMock(
202
- choices=[MagicMock(message=MagicMock(content=" groq result "))]
277
+ gen = CommitMessageGenerator(
278
+ token="fake-token",
279
+ config=config,
280
+ default_model="groq",
203
281
  )
204
- mock_cls.return_value = mock_client
205
282
 
206
- result = generator.generate_groq(
207
- "abc", genai_cls=mock_cls, system_prompt_override="sys"
208
- )
283
+ module_path = CommitMessageGenerator.__module__
284
+
285
+ mock_post = MagicMock()
286
+ mock_post.return_value.json.return_value = {
287
+ "choices": [{"message": {"content": " groq result "}}]
288
+ }
289
+
290
+ with patch(f"{module_path}.requests.post", mock_post):
291
+ result = gen.generate_groq("abc", system_prompt_override="sys")
292
+
209
293
  assert result == "groq result"
294
+ mock_post.assert_called_once()
295
+
296
+ args, kwargs = mock_post.call_args
297
+
298
+ assert args[0] == "https://api.groq.com/openai/v1/chat/completions"
299
+
300
+ assert kwargs["timeout"] == 30
301
+
302
+ assert kwargs["headers"] == {
303
+ "Content-Type": "application/json",
304
+ "Authorization": "Bearer fake-token",
305
+ }
306
+
307
+ assert kwargs["json"] == {
308
+ "model": "llama-3.3-70b-versatile",
309
+ "temperature": 0.7,
310
+ "messages": [
311
+ {"role": "system", "content": "sys"},
312
+ {"role": "user", "content": "abc"},
313
+ ],
314
+ }
210
315
 
211
316
 
212
317
  # test xai
@@ -11,25 +11,6 @@ wheels = [
11
11
  { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
12
12
  ]
13
13
 
14
- [[package]]
15
- name = "anthropic"
16
- version = "0.75.0"
17
- source = { registry = "https://pypi.org/simple" }
18
- dependencies = [
19
- { name = "anyio" },
20
- { name = "distro" },
21
- { name = "docstring-parser" },
22
- { name = "httpx" },
23
- { name = "jiter" },
24
- { name = "pydantic" },
25
- { name = "sniffio" },
26
- { name = "typing-extensions" },
27
- ]
28
- sdist = { url = "https://files.pythonhosted.org/packages/04/1f/08e95f4b7e2d35205ae5dcbb4ae97e7d477fc521c275c02609e2931ece2d/anthropic-0.75.0.tar.gz", hash = "sha256:e8607422f4ab616db2ea5baacc215dd5f028da99ce2f022e33c7c535b29f3dfb", size = 439565, upload-time = "2025-11-24T20:41:45.28Z" }
29
- wheels = [
30
- { url = "https://files.pythonhosted.org/packages/60/1c/1cd02b7ae64302a6e06724bf80a96401d5313708651d277b1458504a1730/anthropic-0.75.0-py3-none-any.whl", hash = "sha256:ea8317271b6c15d80225a9f3c670152746e88805a7a61e14d4a374577164965b", size = 388164, upload-time = "2025-11-24T20:41:43.587Z" },
31
- ]
32
-
33
14
  [[package]]
34
15
  name = "anyio"
35
16
  version = "4.12.1"
@@ -281,15 +262,6 @@ wheels = [
281
262
  { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" },
282
263
  ]
283
264
 
284
- [[package]]
285
- name = "docstring-parser"
286
- version = "0.17.0"
287
- source = { registry = "https://pypi.org/simple" }
288
- sdist = { url = "https://files.pythonhosted.org/packages/b2/9d/c3b43da9515bd270df0f80548d9944e389870713cc1fe2b8fb35fe2bcefd/docstring_parser-0.17.0.tar.gz", hash = "sha256:583de4a309722b3315439bb31d64ba3eebada841f2e2cee23b99df001434c912", size = 27442, upload-time = "2025-07-21T07:35:01.868Z" }
289
- wheels = [
290
- { url = "https://files.pythonhosted.org/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-py3-none-any.whl", hash = "sha256:cf2569abd23dce8099b300f9b4fa8191e9582dda731fd533daf54c4551658708", size = 36896, upload-time = "2025-07-21T07:35:00.684Z" },
291
- ]
292
-
293
265
  [[package]]
294
266
  name = "docutils"
295
267
  version = "0.22.4"
@@ -315,9 +287,6 @@ wheels = [
315
287
  name = "git-cai-cli"
316
288
  source = { editable = "." }
317
289
  dependencies = [
318
- { name = "anthropic" },
319
- { name = "google-genai" },
320
- { name = "groq" },
321
290
  { name = "openai" },
322
291
  { name = "pyyaml" },
323
292
  { name = "requests" },
@@ -334,9 +303,6 @@ dev = [
334
303
 
335
304
  [package.metadata]
336
305
  requires-dist = [
337
- { name = "anthropic", specifier = ">=0.75.0" },
338
- { name = "google-genai", specifier = ">=1.39" },
339
- { name = "groq", specifier = ">=0.37.0" },
340
306
  { name = "openai", specifier = ">=1.0" },
341
307
  { name = "pyyaml", specifier = ">=6.0" },
342
308
  { name = "requests", specifier = ">=2.32.5" },
@@ -351,62 +317,6 @@ dev = [
351
317
  { name = "twine", specifier = ">=6.2.0" },
352
318
  ]
353
319
 
354
- [[package]]
355
- name = "google-auth"
356
- version = "2.47.0"
357
- source = { registry = "https://pypi.org/simple" }
358
- dependencies = [
359
- { name = "pyasn1-modules" },
360
- { name = "rsa" },
361
- ]
362
- sdist = { url = "https://files.pythonhosted.org/packages/60/3c/ec64b9a275ca22fa1cd3b6e77fefcf837b0732c890aa32d2bd21313d9b33/google_auth-2.47.0.tar.gz", hash = "sha256:833229070a9dfee1a353ae9877dcd2dec069a8281a4e72e72f77d4a70ff945da", size = 323719, upload-time = "2026-01-06T21:55:31.045Z" }
363
- wheels = [
364
- { url = "https://files.pythonhosted.org/packages/db/18/79e9008530b79527e0d5f79e7eef08d3b179b7f851cfd3a2f27822fbdfa9/google_auth-2.47.0-py3-none-any.whl", hash = "sha256:c516d68336bfde7cf0da26aab674a36fedcf04b37ac4edd59c597178760c3498", size = 234867, upload-time = "2026-01-06T21:55:28.6Z" },
365
- ]
366
-
367
- [package.optional-dependencies]
368
- requests = [
369
- { name = "requests" },
370
- ]
371
-
372
- [[package]]
373
- name = "google-genai"
374
- version = "1.57.0"
375
- source = { registry = "https://pypi.org/simple" }
376
- dependencies = [
377
- { name = "anyio" },
378
- { name = "distro" },
379
- { name = "google-auth", extra = ["requests"] },
380
- { name = "httpx" },
381
- { name = "pydantic" },
382
- { name = "requests" },
383
- { name = "sniffio" },
384
- { name = "tenacity" },
385
- { name = "typing-extensions" },
386
- { name = "websockets" },
387
- ]
388
- sdist = { url = "https://files.pythonhosted.org/packages/2b/b4/8251c2d2576224a4b51a8ab6159820f9200b8da28ff555c78ee15607096e/google_genai-1.57.0.tar.gz", hash = "sha256:0ff9c36b8d68abfbdbd13b703ece926de5f3e67955666b36315ecf669b94a826", size = 485648, upload-time = "2026-01-07T20:38:20.271Z" }
389
- wheels = [
390
- { url = "https://files.pythonhosted.org/packages/d6/02/858bdae08e2184b6afe0b18bc3113318522c9cf326a5a1698055edd31f88/google_genai-1.57.0-py3-none-any.whl", hash = "sha256:d63c7a89a1f549c4d14032f41a0cdb4b6fe3f565e2eee6b5e0907a0aeceabefd", size = 713323, upload-time = "2026-01-07T20:38:18.051Z" },
391
- ]
392
-
393
- [[package]]
394
- name = "groq"
395
- version = "1.0.0"
396
- source = { registry = "https://pypi.org/simple" }
397
- dependencies = [
398
- { name = "anyio" },
399
- { name = "distro" },
400
- { name = "httpx" },
401
- { name = "pydantic" },
402
- { name = "sniffio" },
403
- { name = "typing-extensions" },
404
- ]
405
- sdist = { url = "https://files.pythonhosted.org/packages/3f/12/f4099a141677fcd2ed79dcc1fcec431e60c52e0e90c9c5d935f0ffaf8c0e/groq-1.0.0.tar.gz", hash = "sha256:66cb7bb729e6eb644daac7ce8efe945e99e4eb33657f733ee6f13059ef0c25a9", size = 146068, upload-time = "2025-12-17T23:34:23.115Z" }
406
- wheels = [
407
- { url = "https://files.pythonhosted.org/packages/4a/88/3175759d2ef30406ea721f4d837bfa1ba4339fde3b81ba8c5640a96ed231/groq-1.0.0-py3-none-any.whl", hash = "sha256:6e22bf92ffad988f01d2d4df7729add66b8fd5dbfb2154b5bbf3af245b72c731", size = 138292, upload-time = "2025-12-17T23:34:21.957Z" },
408
- ]
409
-
410
320
  [[package]]
411
321
  name = "h11"
412
322
  version = "0.16.0"
@@ -746,27 +656,6 @@ wheels = [
746
656
  { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
747
657
  ]
748
658
 
749
- [[package]]
750
- name = "pyasn1"
751
- version = "0.6.1"
752
- source = { registry = "https://pypi.org/simple" }
753
- sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322, upload-time = "2024-09-10T22:41:42.55Z" }
754
- wheels = [
755
- { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135, upload-time = "2024-09-11T16:00:36.122Z" },
756
- ]
757
-
758
- [[package]]
759
- name = "pyasn1-modules"
760
- version = "0.4.2"
761
- source = { registry = "https://pypi.org/simple" }
762
- dependencies = [
763
- { name = "pyasn1" },
764
- ]
765
- sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" }
766
- wheels = [
767
- { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" },
768
- ]
769
-
770
659
  [[package]]
771
660
  name = "pycparser"
772
661
  version = "2.23"
@@ -1093,18 +982,6 @@ wheels = [
1093
982
  { url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393, upload-time = "2025-10-09T14:16:51.245Z" },
1094
983
  ]
1095
984
 
1096
- [[package]]
1097
- name = "rsa"
1098
- version = "4.9.1"
1099
- source = { registry = "https://pypi.org/simple" }
1100
- dependencies = [
1101
- { name = "pyasn1" },
1102
- ]
1103
- sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" }
1104
- wheels = [
1105
- { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" },
1106
- ]
1107
-
1108
985
  [[package]]
1109
986
  name = "secretstorage"
1110
987
  version = "3.5.0"
@@ -1136,15 +1013,6 @@ wheels = [
1136
1013
  { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
1137
1014
  ]
1138
1015
 
1139
- [[package]]
1140
- name = "tenacity"
1141
- version = "9.1.2"
1142
- source = { registry = "https://pypi.org/simple" }
1143
- sdist = { url = "https://files.pythonhosted.org/packages/0a/d4/2b0cd0fe285e14b36db076e78c93766ff1d529d70408bd1d2a5a84f1d929/tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb", size = 48036, upload-time = "2025-04-02T08:25:09.966Z" }
1144
- wheels = [
1145
- { url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248, upload-time = "2025-04-02T08:25:07.678Z" },
1146
- ]
1147
-
1148
1016
  [[package]]
1149
1017
  name = "tomli"
1150
1018
  version = "2.3.0"
@@ -1271,65 +1139,6 @@ wheels = [
1271
1139
  { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" },
1272
1140
  ]
1273
1141
 
1274
- [[package]]
1275
- name = "websockets"
1276
- version = "15.0.1"
1277
- source = { registry = "https://pypi.org/simple" }
1278
- sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" }
1279
- wheels = [
1280
- { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423, upload-time = "2025-03-05T20:01:35.363Z" },
1281
- { url = "https://files.pythonhosted.org/packages/1c/9f/9d11c1a4eb046a9e106483b9ff69bce7ac880443f00e5ce64261b47b07e7/websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205", size = 173080, upload-time = "2025-03-05T20:01:37.304Z" },
1282
- { url = "https://files.pythonhosted.org/packages/d5/4f/b462242432d93ea45f297b6179c7333dd0402b855a912a04e7fc61c0d71f/websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a", size = 173329, upload-time = "2025-03-05T20:01:39.668Z" },
1283
- { url = "https://files.pythonhosted.org/packages/6e/0c/6afa1f4644d7ed50284ac59cc70ef8abd44ccf7d45850d989ea7310538d0/websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e", size = 182312, upload-time = "2025-03-05T20:01:41.815Z" },
1284
- { url = "https://files.pythonhosted.org/packages/dd/d4/ffc8bd1350b229ca7a4db2a3e1c482cf87cea1baccd0ef3e72bc720caeec/websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf", size = 181319, upload-time = "2025-03-05T20:01:43.967Z" },
1285
- { url = "https://files.pythonhosted.org/packages/97/3a/5323a6bb94917af13bbb34009fac01e55c51dfde354f63692bf2533ffbc2/websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb", size = 181631, upload-time = "2025-03-05T20:01:46.104Z" },
1286
- { url = "https://files.pythonhosted.org/packages/a6/cc/1aeb0f7cee59ef065724041bb7ed667b6ab1eeffe5141696cccec2687b66/websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d", size = 182016, upload-time = "2025-03-05T20:01:47.603Z" },
1287
- { url = "https://files.pythonhosted.org/packages/79/f9/c86f8f7af208e4161a7f7e02774e9d0a81c632ae76db2ff22549e1718a51/websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9", size = 181426, upload-time = "2025-03-05T20:01:48.949Z" },
1288
- { url = "https://files.pythonhosted.org/packages/c7/b9/828b0bc6753db905b91df6ae477c0b14a141090df64fb17f8a9d7e3516cf/websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c", size = 181360, upload-time = "2025-03-05T20:01:50.938Z" },
1289
- { url = "https://files.pythonhosted.org/packages/89/fb/250f5533ec468ba6327055b7d98b9df056fb1ce623b8b6aaafb30b55d02e/websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256", size = 176388, upload-time = "2025-03-05T20:01:52.213Z" },
1290
- { url = "https://files.pythonhosted.org/packages/1c/46/aca7082012768bb98e5608f01658ff3ac8437e563eca41cf068bd5849a5e/websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41", size = 176830, upload-time = "2025-03-05T20:01:53.922Z" },
1291
- { url = "https://files.pythonhosted.org/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423, upload-time = "2025-03-05T20:01:56.276Z" },
1292
- { url = "https://files.pythonhosted.org/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082, upload-time = "2025-03-05T20:01:57.563Z" },
1293
- { url = "https://files.pythonhosted.org/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330, upload-time = "2025-03-05T20:01:59.063Z" },
1294
- { url = "https://files.pythonhosted.org/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878, upload-time = "2025-03-05T20:02:00.305Z" },
1295
- { url = "https://files.pythonhosted.org/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883, upload-time = "2025-03-05T20:02:03.148Z" },
1296
- { url = "https://files.pythonhosted.org/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252, upload-time = "2025-03-05T20:02:05.29Z" },
1297
- { url = "https://files.pythonhosted.org/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521, upload-time = "2025-03-05T20:02:07.458Z" },
1298
- { url = "https://files.pythonhosted.org/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958, upload-time = "2025-03-05T20:02:09.842Z" },
1299
- { url = "https://files.pythonhosted.org/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918, upload-time = "2025-03-05T20:02:11.968Z" },
1300
- { url = "https://files.pythonhosted.org/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388, upload-time = "2025-03-05T20:02:13.32Z" },
1301
- { url = "https://files.pythonhosted.org/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828, upload-time = "2025-03-05T20:02:14.585Z" },
1302
- { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" },
1303
- { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" },
1304
- { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" },
1305
- { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" },
1306
- { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" },
1307
- { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" },
1308
- { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" },
1309
- { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" },
1310
- { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" },
1311
- { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" },
1312
- { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" },
1313
- { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" },
1314
- { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" },
1315
- { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" },
1316
- { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" },
1317
- { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" },
1318
- { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" },
1319
- { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" },
1320
- { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" },
1321
- { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" },
1322
- { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" },
1323
- { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" },
1324
- { url = "https://files.pythonhosted.org/packages/02/9e/d40f779fa16f74d3468357197af8d6ad07e7c5a27ea1ca74ceb38986f77a/websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3", size = 173109, upload-time = "2025-03-05T20:03:17.769Z" },
1325
- { url = "https://files.pythonhosted.org/packages/bc/cd/5b887b8585a593073fd92f7c23ecd3985cd2c3175025a91b0d69b0551372/websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1", size = 173343, upload-time = "2025-03-05T20:03:19.094Z" },
1326
- { url = "https://files.pythonhosted.org/packages/fe/ae/d34f7556890341e900a95acf4886833646306269f899d58ad62f588bf410/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475", size = 174599, upload-time = "2025-03-05T20:03:21.1Z" },
1327
- { url = "https://files.pythonhosted.org/packages/71/e6/5fd43993a87db364ec60fc1d608273a1a465c0caba69176dd160e197ce42/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9", size = 174207, upload-time = "2025-03-05T20:03:23.221Z" },
1328
- { url = "https://files.pythonhosted.org/packages/2b/fb/c492d6daa5ec067c2988ac80c61359ace5c4c674c532985ac5a123436cec/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04", size = 174155, upload-time = "2025-03-05T20:03:25.321Z" },
1329
- { url = "https://files.pythonhosted.org/packages/68/a1/dcb68430b1d00b698ae7a7e0194433bce4f07ded185f0ee5fb21e2a2e91e/websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122", size = 176884, upload-time = "2025-03-05T20:03:27.934Z" },
1330
- { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" },
1331
- ]
1332
-
1333
1142
  [[package]]
1334
1143
  name = "zipp"
1335
1144
  version = "3.23.0"
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