github-code-review 3.4.0__tar.gz → 3.4.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.
Files changed (40) hide show
  1. {github_code_review-3.4.0 → github_code_review-3.4.2}/PKG-INFO +16 -14
  2. {github_code_review-3.4.0 → github_code_review-3.4.2}/README.md +9 -9
  3. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/bootstrap.py +6 -1
  4. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/cli.py +4 -0
  5. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/config.toml +14 -1
  6. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/core.py +75 -16
  7. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/project_config.py +4 -0
  8. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/report_struct.py +10 -0
  9. {github_code_review-3.4.0 → github_code_review-3.4.2}/pyproject.toml +7 -7
  10. {github_code_review-3.4.0 → github_code_review-3.4.2}/LICENSE +0 -0
  11. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/__init__.py +0 -0
  12. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/__main__.py +0 -0
  13. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/cli_base.py +0 -0
  14. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/commands/__init__.py +0 -0
  15. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/commands/deploy.py +0 -0
  16. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/commands/fix.py +0 -0
  17. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/commands/gh_post_review_comment.py +0 -0
  18. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/commands/gh_react_to_comment.py +0 -0
  19. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/commands/linear_comment.py +0 -0
  20. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/commands/repl.py +0 -0
  21. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/commands/version.py +0 -0
  22. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/constants.py +0 -0
  23. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/context.py +0 -0
  24. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/env.py +0 -0
  25. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/gh_api.py +0 -0
  26. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/issue_trackers.py +0 -0
  27. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/pipeline.py +0 -0
  28. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/pipeline_steps/__init__.py +0 -0
  29. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/pipeline_steps/jira.py +0 -0
  30. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/pipeline_steps/linear.py +0 -0
  31. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/tpl/answer.j2 +0 -0
  32. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/tpl/github_workflows/components/env-vars.j2 +0 -0
  33. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/tpl/github_workflows/components/installs.j2 +0 -0
  34. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/tpl/github_workflows/gito-code-review.yml.j2 +0 -0
  35. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/tpl/github_workflows/gito-react-to-comments.yml.j2 +0 -0
  36. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/tpl/partial/aux_files.j2 +0 -0
  37. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/tpl/questions/changes_summary.j2 +0 -0
  38. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/tpl/questions/release_notes.j2 +0 -0
  39. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/tpl/questions/test_cases.j2 +0 -0
  40. {github_code_review-3.4.0 → github_code_review-3.4.2}/gito/utils.py +0 -0
@@ -1,8 +1,9 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: github-code-review
3
- Version: 3.4.0
3
+ Version: 3.4.2
4
4
  Summary: AI code review tool that works with any language model provider. It detects issues in GitHub pull requests or local changes—instantly, reliably, and without vendor lock-in.
5
5
  License: MIT
6
+ License-File: LICENSE
6
7
  Keywords: static code analysis,code review,code quality,ai,coding,assistant,llm,github,automation,devops,developer tools,github actions,workflows,git
7
8
  Author: Nayjest
8
9
  Author-email: mail@vitaliy.in
@@ -14,15 +15,16 @@ Classifier: Programming Language :: Python :: 3
14
15
  Classifier: Programming Language :: Python :: 3.11
15
16
  Classifier: Programming Language :: Python :: 3.12
16
17
  Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
17
19
  Classifier: Topic :: Software Development
18
20
  Requires-Dist: GitPython (>=3.1.44,<4.0.0)
19
- Requires-Dist: ai-microcore (==4.4.2)
20
- Requires-Dist: anthropic (>=0.57.1,<0.58.0)
21
+ Requires-Dist: ai-microcore (>=4.5,<4.6)
22
+ Requires-Dist: anthropic (>=0.57.1,<1)
21
23
  Requires-Dist: ghapi (>=1.0.6,<1.1.0)
22
24
  Requires-Dist: google-generativeai (>=0.8.5,<0.9.0)
23
25
  Requires-Dist: jira (>=3.8.0,<4.0.0)
24
26
  Requires-Dist: pydantic (>=2.12.3,<3.0.0)
25
- Requires-Dist: typer (>=0.16.0,<0.17.0)
27
+ Requires-Dist: typer (>=0.16.0,<0.21)
26
28
  Requires-Dist: unidiff (>=0.7.5,<0.8.0)
27
29
  Project-URL: Homepage, https://github.com/Nayjest/Gito
28
30
  Project-URL: Repository, https://github.com/Nayjest/Gito
@@ -100,7 +102,7 @@ jobs:
100
102
  uses: actions/setup-python@v5
101
103
  with: { python-version: "3.13" }
102
104
  - name: Install AI Code Review tool
103
- run: pip install gito.bot~=3.0
105
+ run: pip install gito.bot~=3.4
104
106
  - name: Run AI code analysis
105
107
  env:
106
108
  LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
@@ -131,15 +133,15 @@ See [GitHub Setup Guide](https://github.com/Nayjest/Gito/blob/main/documentation
131
133
 
132
134
  **Prerequisites:** [Python](https://www.python.org/downloads/) 3.11 / 3.12 / 3.13
133
135
 
134
- **Step1:** Install [gito.bot](https://github.com/Nayjest/Gito) using [pip](https://en.wikipedia.org/wiki/Pip_(package_manager)).
136
+ **Step 1:** Install [gito.bot](https://github.com/Nayjest/Gito) using [pip](https://en.wikipedia.org/wiki/Pip_(package_manager)).
135
137
  ```bash
136
138
  pip install gito.bot
137
139
  ```
138
140
 
139
141
  > **Troubleshooting:**
140
- > pip may be also available via cli as `pip3` depending on your Python installation.
142
+ > pip may also be available via cli as `pip3` depending on your Python installation.
141
143
 
142
- **Step2:** Perform initial setup
144
+ **Step 2:** Perform initial setup
143
145
 
144
146
  The following command will perform one-time setup using an interactive wizard.
145
147
  You will be prompted to enter LLM configuration details (API type, API key, etc).
@@ -150,15 +152,15 @@ gito setup
150
152
  ```
151
153
 
152
154
  > **Troubleshooting:**
153
- > On some systems, `gito` command may not became available immediately after installation.
155
+ > On some systems, `gito` command may not become available immediately after installation.
154
156
  > Try restarting your terminal or running `python -m gito` instead.
155
157
 
156
158
 
157
159
  #### Perform your first AI code review locally
158
160
 
159
- **Step1:** Navigate to your repository root directory.
160
- **Step2:** Switch to the branch you want to review.
161
- **Step3:** Run following command
161
+ **Step 1:** Navigate to your repository root directory.
162
+ **Step 2:** Switch to the branch you want to review.
163
+ **Step 3:** Run following command
162
164
  ```bash
163
165
  gito review
164
166
  ```
@@ -232,5 +234,5 @@ See [CONTRIBUTING.md](https://github.com/Nayjest/Gito/blob/main/CONTRIBUTING.md)
232
234
 
233
235
  Licensed under the [MIT License](https://github.com/Nayjest/Gito/blob/main/LICENSE).
234
236
 
235
- © 2025 [Vitalii Stepanenko](mailto:mail@vitaliy.in)
237
+ © 2025–2026 [Vitalii Stepanenko](mailto:mail@vitaliy.in)
236
238
 
@@ -70,7 +70,7 @@ jobs:
70
70
  uses: actions/setup-python@v5
71
71
  with: { python-version: "3.13" }
72
72
  - name: Install AI Code Review tool
73
- run: pip install gito.bot~=3.0
73
+ run: pip install gito.bot~=3.4
74
74
  - name: Run AI code analysis
75
75
  env:
76
76
  LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
@@ -101,15 +101,15 @@ See [GitHub Setup Guide](https://github.com/Nayjest/Gito/blob/main/documentation
101
101
 
102
102
  **Prerequisites:** [Python](https://www.python.org/downloads/) 3.11 / 3.12 / 3.13
103
103
 
104
- **Step1:** Install [gito.bot](https://github.com/Nayjest/Gito) using [pip](https://en.wikipedia.org/wiki/Pip_(package_manager)).
104
+ **Step 1:** Install [gito.bot](https://github.com/Nayjest/Gito) using [pip](https://en.wikipedia.org/wiki/Pip_(package_manager)).
105
105
  ```bash
106
106
  pip install gito.bot
107
107
  ```
108
108
 
109
109
  > **Troubleshooting:**
110
- > pip may be also available via cli as `pip3` depending on your Python installation.
110
+ > pip may also be available via cli as `pip3` depending on your Python installation.
111
111
 
112
- **Step2:** Perform initial setup
112
+ **Step 2:** Perform initial setup
113
113
 
114
114
  The following command will perform one-time setup using an interactive wizard.
115
115
  You will be prompted to enter LLM configuration details (API type, API key, etc).
@@ -120,15 +120,15 @@ gito setup
120
120
  ```
121
121
 
122
122
  > **Troubleshooting:**
123
- > On some systems, `gito` command may not became available immediately after installation.
123
+ > On some systems, `gito` command may not become available immediately after installation.
124
124
  > Try restarting your terminal or running `python -m gito` instead.
125
125
 
126
126
 
127
127
  #### Perform your first AI code review locally
128
128
 
129
- **Step1:** Navigate to your repository root directory.
130
- **Step2:** Switch to the branch you want to review.
131
- **Step3:** Run following command
129
+ **Step 1:** Navigate to your repository root directory.
130
+ **Step 2:** Switch to the branch you want to review.
131
+ **Step 3:** Run following command
132
132
  ```bash
133
133
  gito review
134
134
  ```
@@ -202,4 +202,4 @@ See [CONTRIBUTING.md](https://github.com/Nayjest/Gito/blob/main/CONTRIBUTING.md)
202
202
 
203
203
  Licensed under the [MIT License](https://github.com/Nayjest/Gito/blob/main/LICENSE).
204
204
 
205
- © 2025 [Vitalii Stepanenko](mailto:mail@vitaliy.in)
205
+ © 2025–2026 [Vitalii Stepanenko](mailto:mail@vitaliy.in)
@@ -13,6 +13,7 @@ from .env import Env
13
13
 
14
14
 
15
15
  def setup_logging(log_level: int = logging.INFO):
16
+ """Setup custom CLI logging format with colored output."""
16
17
  class CustomFormatter(logging.Formatter):
17
18
  def format(self, record):
18
19
  dt = datetime.fromtimestamp(record.created).strftime("%Y-%m-%d %H:%M:%S")
@@ -23,7 +24,11 @@ def setup_logging(log_level: int = logging.INFO):
23
24
  if record.levelno >= logging.ERROR:
24
25
  message = mc.ui.red(message)
25
26
  level_name = mc.ui.red(level_name)
26
- return f"{dt} {level_name}: {message}"
27
+
28
+ formatted_message = f"{dt} {level_name}: {message}"
29
+ if record.exc_info:
30
+ formatted_message += "\n" + self.formatException(record.exc_info)
31
+ return formatted_message
27
32
 
28
33
  handler = logging.StreamHandler()
29
34
  handler.setFormatter(CustomFormatter())
@@ -25,6 +25,7 @@ from .constants import HOME_ENV_PATH, GITHUB_MD_REPORT_FILE_NAME
25
25
  from .bootstrap import bootstrap
26
26
  from .utils import no_subcommand, extract_gh_owner_repo, remove_html_comments
27
27
  from .gh_api import resolve_gh_token
28
+ from .project_config import ProjectConfig
28
29
 
29
30
  # Import fix command to register it
30
31
  from .commands import fix, gh_react_to_comment, repl, deploy, version # noqa
@@ -244,6 +245,9 @@ def files(
244
245
  try:
245
246
  patch_set = get_diff(repo=repo, what=_what, against=_against, use_merge_base=merge_base)
246
247
  patch_set = filter_diff(patch_set, filters)
248
+ cfg = ProjectConfig.load_for_repo(repo)
249
+ if cfg.exclude_files:
250
+ patch_set = filter_diff(patch_set, cfg.exclude_files, exclude=True)
247
251
  print(
248
252
  f"Changed files: "
249
253
  f"{mc.ui.green(_what or 'INDEX')} vs "
@@ -37,6 +37,12 @@ report_template_md = """
37
37
  {%- endfor -%}
38
38
  {{ "\n" }}
39
39
  {%- endfor -%}
40
+ {%- if report.processing_warnings -%}
41
+ {{- "\n\n" }}## Processing Warnings
42
+ {%- for warning in report.processing_warnings -%}
43
+ {{- "\n" }} - {{ warning.message -}}
44
+ {%- endfor -%}
45
+ {%- endif -%}
40
46
  {{- HTML_CR_COMMENT_MARKER -}}
41
47
  """
42
48
  report_template_cli = """
@@ -109,6 +115,13 @@ report_template_cli = """
109
115
  {%- endfor -%}
110
116
  {{ "\n" }}
111
117
  {%- endfor -%}
118
+ {%- if report.processing_warnings -%}
119
+ {{- "\n" }}
120
+ {{- "\n" }}{{ Style.BRIGHT }}⚠️ PROCESSING WARNINGS{{ Style.RESET_ALL -}}
121
+ {%- for warning in report.processing_warnings -%}
122
+ {{- "\n" }} {{ Fore.YELLOW }}- {{ warning.message }}{{ Style.RESET_ALL -}}
123
+ {%- endfor -%}
124
+ {%- endif -%}
112
125
  """
113
126
  retries = 3
114
127
  prompt = """
@@ -184,7 +197,7 @@ Confidence scale:
184
197
  - 1 — Highest, 100% confidence that code requires changes in any context
185
198
  - 2 — Very High
186
199
  - 3 — High
187
- - 4 — Medium - Should not be reported
200
+ - 4 — Medium, Should not be reported
188
201
 
189
202
  (!) - If no issues found according to the criteria, respond with empty list: []
190
203
  """
@@ -17,7 +17,7 @@ from unidiff.constants import DEV_NULL
17
17
 
18
18
  from .context import Context
19
19
  from .project_config import ProjectConfig
20
- from .report_struct import Report, RawIssue
20
+ from .report_struct import ProcessingWarning, Report, RawIssue
21
21
  from .constants import JSON_REPORT_FILE_NAME, REFS_VALUE_ALL
22
22
  from .utils import make_streaming_function
23
23
  from .pipeline import Pipeline
@@ -236,12 +236,21 @@ def get_diff(
236
236
 
237
237
 
238
238
  def filter_diff(
239
- patch_set: PatchSet | Iterable[PatchedFile], filters: str | list[str]
239
+ patch_set: PatchSet | Iterable[PatchedFile],
240
+ filters: str | list[str],
241
+ exclude: bool = False,
240
242
  ) -> PatchSet | Iterable[PatchedFile]:
241
243
  """
242
244
  Filter the diff files by the given fnmatch filters.
245
+ Args:
246
+ patch_set (PatchSet | Iterable[PatchedFile]): The diff to filter.
247
+ filters (str | list[str]): The fnmatch patterns to filter by.
248
+ exclude (bool): If True, inverse logic (exclude files matching the filters).
249
+ Returns:
250
+ PatchSet | Iterable[PatchedFile]: The filtered diff.
243
251
  """
244
- assert isinstance(filters, (list, str))
252
+ if not isinstance(filters, (list, str)):
253
+ raise ValueError("Filters must be a string or a list of strings")
245
254
  if not isinstance(filters, list):
246
255
  filters = [f.strip() for f in filters.split(",") if f.strip()]
247
256
  if not filters:
@@ -249,7 +258,10 @@ def filter_diff(
249
258
  files = [
250
259
  file
251
260
  for file in patch_set
252
- if any(fnmatch.fnmatch(file.path, pattern) for pattern in filters)
261
+ if (
262
+ not any(fnmatch.fnmatch(file.path, pattern) for pattern in filters) if exclude
263
+ else any(fnmatch.fnmatch(file.path, pattern) for pattern in filters)
264
+ )
253
265
  ]
254
266
  return files
255
267
 
@@ -330,6 +342,8 @@ def _prepare(
330
342
  repo=repo, what=what, against=against, use_merge_base=use_merge_base, pr=pr,
331
343
  )
332
344
  diff = filter_diff(diff, filters)
345
+ if cfg.exclude_files:
346
+ diff = filter_diff(diff, cfg.exclude_files, exclude=True)
333
347
  if not diff:
334
348
  raise NoChangesInContextError()
335
349
  lines = {
@@ -370,18 +384,39 @@ def get_affected_code_block(repo: Repo, file: str, start_line: int, end_line: in
370
384
  return None
371
385
 
372
386
 
373
- def provide_affected_code_blocks(issues: dict, repo: Repo):
387
+ def provide_affected_code_blocks(
388
+ issues: dict,
389
+ repo: Repo,
390
+ processing_warnings: list = None
391
+ ):
392
+ """
393
+ For each issue, fetch the affected code text block
394
+ and add it to the issue data.
395
+ """
374
396
  for file, file_issues in issues.items():
375
397
  for issue in file_issues:
376
- for i in issue.get("affected_lines", []):
377
- file_name = i.get("file", issue.get("file", file))
378
- if block := get_affected_code_block(
379
- repo,
380
- file_name,
381
- i.get("start_line"),
382
- i.get("end_line")
383
- ):
384
- i["affected_code"] = block
398
+ try:
399
+ for i in issue.get("affected_lines", []):
400
+ file_name = i.get("file", issue.get("file", file))
401
+ if block := get_affected_code_block(
402
+ repo,
403
+ file_name,
404
+ i.get("start_line"),
405
+ i.get("end_line")
406
+ ):
407
+ i["affected_code"] = block
408
+ except Exception as e:
409
+ logging.exception(e)
410
+ if processing_warnings is None:
411
+ continue
412
+ processing_warnings.append(
413
+ ProcessingWarning(
414
+ message=(
415
+ f"Error fetching affected code blocks for file {file}: {e}"
416
+ ),
417
+ file=file,
418
+ )
419
+ )
385
420
 
386
421
 
387
422
  def _llm_response_validator(parsed_response: list[dict]):
@@ -447,13 +482,37 @@ async def review(
447
482
  ],
448
483
  retries=cfg.retries,
449
484
  parse_json={"validator": _llm_response_validator},
485
+ allow_failures=True,
450
486
  )
487
+ processing_warnings: list[ProcessingWarning] = []
488
+ for i, (res_or_error, file) in enumerate(zip(responses, diff)):
489
+ if isinstance(res_or_error, Exception):
490
+ if isinstance(res_or_error, mc.LLMContextLengthExceededError):
491
+ message = f'File "{file.path}" was skipped due to large size: {str(res_or_error)}.'
492
+ else:
493
+ message = (
494
+ f"File {file.path} was skipped due to error: "
495
+ f"[{type(res_or_error).__name__}] {res_or_error}"
496
+ )
497
+ if not message.endswith('.'):
498
+ message += '.'
499
+ processing_warnings.append(
500
+ ProcessingWarning(
501
+ message=message,
502
+ file=file.path,
503
+ )
504
+ )
505
+ responses[i] = []
506
+
451
507
  issues = {file.path: issues for file, issues in zip(diff, responses) if issues}
452
- provide_affected_code_blocks(issues, repo)
508
+ provide_affected_code_blocks(issues, repo, processing_warnings)
453
509
  exec(cfg.post_process, {"mc": mc, **locals()})
454
510
  out_folder = Path(out_folder or repo.working_tree_dir)
455
511
  out_folder.mkdir(parents=True, exist_ok=True)
456
- report = Report(number_of_processed_files=len(diff))
512
+ report = Report(
513
+ number_of_processed_files=len(diff),
514
+ processing_warnings=processing_warnings,
515
+ )
457
516
  report.register_issues(issues)
458
517
  ctx = Context(
459
518
  report=report,
@@ -33,6 +33,10 @@ class ProjectConfig:
33
33
  when referenced in code review comments.
34
34
  """
35
35
  aux_files: list[str] = field(default_factory=list)
36
+ exclude_files: list[str] = field(default_factory=list)
37
+ """
38
+ List of file patterns to exclude from analysis.
39
+ """
36
40
  pipeline_steps: dict[str, dict | PipelineStep] = field(default_factory=dict)
37
41
  collapse_previous_code_review_comments: bool = field(default=True)
38
42
  """
@@ -72,6 +72,15 @@ class Issue(RawIssue):
72
72
  return url
73
73
 
74
74
 
75
+ @dataclass
76
+ class ProcessingWarning:
77
+ """
78
+ Warning generated during code review of files
79
+ """
80
+ message: str = field()
81
+ file: str | None = field(default=None)
82
+
83
+
75
84
  @dataclass
76
85
  class Report:
77
86
  class Format(StrEnum):
@@ -85,6 +94,7 @@ class Report:
85
94
  created_at: str = field(default_factory=lambda: datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
86
95
  model: str = field(default_factory=lambda: mc.config().MODEL)
87
96
  pipeline_out: dict = field(default_factory=dict)
97
+ processing_warnings: list[ProcessingWarning] = field(default_factory=list)
88
98
 
89
99
  @property
90
100
  def plain_issues(self):
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "github-code-review"
3
- version = "3.4.0"
3
+ version = "3.4.2"
4
4
  description = "AI code review tool that works with any language model provider. It detects issues in GitHub pull requests or local changes—instantly, reliably, and without vendor lock-in."
5
5
  authors = ["Nayjest <mail@vitaliy.in>"]
6
6
  readme = "README.md"
@@ -21,12 +21,12 @@ packages = [
21
21
 
22
22
  [tool.poetry.dependencies]
23
23
  python = "^3.11"
24
- ai-microcore = "4.4.2"
24
+ ai-microcore = "~4.5"
25
25
  GitPython = "^3.1.44"
26
26
  unidiff = "^0.7.5"
27
27
  google-generativeai = "^0.8.5"
28
- anthropic = "^0.57.1"
29
- typer = "^0.16.0"
28
+ anthropic = ">=0.57.1,<1"
29
+ typer = ">=0.16.0,<0.21"
30
30
  ghapi = "~=1.0.6"
31
31
  jira = "^3.8.0"
32
32
  pydantic = "^2.12.3"
@@ -41,10 +41,10 @@ pyflakes = "*"
41
41
  poetry = "*"
42
42
 
43
43
  [tool.poetry.group.test.dependencies]
44
- pytest = "^7.4.3"
45
- pytest-asyncio = ">=0.21.0"
44
+ pytest = ">=7.4.3,<10"
45
+ pytest-asyncio = ">=0.21.0,<2"
46
46
  pytest-mock = "^3.12.0"
47
- pytest-cov = "^4.1.0"
47
+ pytest-cov = ">=4.1.0,<8"
48
48
 
49
49
  [build-system]
50
50
  requires = ["poetry-core"]