gac 1.9.1__py3-none-any.whl → 1.9.3__py3-none-any.whl

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.

Potentially problematic release.


This version of gac might be problematic. Click here for more details.

gac/__version__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """Version information for gac package."""
2
2
 
3
- __version__ = "1.9.1"
3
+ __version__ = "1.9.3"
gac/ai_utils.py CHANGED
@@ -38,7 +38,7 @@ def extract_text_content(content: str | list[dict[str, str]] | dict[str, Any]) -
38
38
  elif isinstance(content, list):
39
39
  return "\n".join(msg["content"] for msg in content if isinstance(msg, dict) and "content" in msg)
40
40
  elif isinstance(content, dict) and "content" in content:
41
- return content["content"]
41
+ return content["content"] # type: ignore[no-any-return]
42
42
  return ""
43
43
 
44
44
 
@@ -144,7 +144,7 @@ def generate_with_retries(
144
144
  spinner.succeed(f"Generated commit message with {provider} {model_name}")
145
145
 
146
146
  if content is not None and content.strip():
147
- return content.strip()
147
+ return content.strip() # type: ignore[no-any-return]
148
148
  else:
149
149
  logger.warning(f"Empty or None content received from {provider} {model_name}: {repr(content)}")
150
150
  raise AIError.model_error("Empty response from AI model")
gac/cli.py CHANGED
@@ -66,7 +66,7 @@ logger = logging.getLogger(__name__)
66
66
  def cli(
67
67
  ctx: click.Context,
68
68
  add_all: bool = False,
69
- log_level: str = config["log_level"],
69
+ log_level: str = str(config["log_level"]),
70
70
  one_liner: bool = False,
71
71
  push: bool = False,
72
72
  show_prompt: bool = False,
@@ -74,7 +74,7 @@ def cli(
74
74
  quiet: bool = False,
75
75
  yes: bool = False,
76
76
  hint: str = "",
77
- model: str = None,
77
+ model: str | None = None,
78
78
  version: bool = False,
79
79
  dry_run: bool = False,
80
80
  verbose: bool = False,
gac/config.py CHANGED
@@ -11,7 +11,7 @@ from dotenv import load_dotenv
11
11
  from gac.constants import EnvDefaults, Logging
12
12
 
13
13
 
14
- def load_config() -> dict[str, str | int | float | bool]:
14
+ def load_config() -> dict[str, str | int | float | bool | None]:
15
15
  """Load configuration from $HOME/.gac.env, then ./.gac.env or ./.env, then environment variables."""
16
16
  user_config = Path.home() / ".gac.env"
17
17
  if user_config.exists():
gac/constants.py CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  import os
4
4
  from enum import Enum
5
- from re import Pattern
6
5
 
7
6
 
8
7
  class FileStatus(Enum):
@@ -48,7 +47,7 @@ class FilePatterns:
48
47
  """Patterns for identifying special file types."""
49
48
 
50
49
  # Regex patterns to detect binary file changes in git diffs (e.g., images or other non-text files)
51
- BINARY: list[Pattern[str]] = [
50
+ BINARY: list[str] = [
52
51
  r"Binary files .* differ",
53
52
  r"GIT binary patch",
54
53
  ]
@@ -129,7 +128,7 @@ class CodePatternImportance:
129
128
 
130
129
  # Regex patterns to detect code structure changes in git diffs (e.g., class, function, import)
131
130
  # Note: The patterns are prefixed with "+" to match only added and modified lines
132
- PATTERNS: dict[Pattern[str], float] = {
131
+ PATTERNS: dict[str, float] = {
133
132
  # Structure changes
134
133
  r"\+\s*(class|interface|enum)\s+\w+": 1.8, # Class/interface/enum definitions
135
134
  r"\+\s*(def|function|func)\s+\w+\s*\(": 1.5, # Function definitions
gac/git.py CHANGED
@@ -120,8 +120,8 @@ def run_pre_commit_hooks() -> bool:
120
120
  # Check if pre-commit is installed and configured
121
121
  try:
122
122
  # First check if pre-commit is installed
123
- result = run_subprocess(["pre-commit", "--version"], silent=True, raise_on_error=False)
124
- if not result:
123
+ version_check = run_subprocess(["pre-commit", "--version"], silent=True, raise_on_error=False)
124
+ if not version_check:
125
125
  logger.debug("pre-commit not installed, skipping hooks")
126
126
  return True
127
127
 
@@ -170,8 +170,8 @@ def run_lefthook_hooks() -> bool:
170
170
  # Check if lefthook is installed and configured
171
171
  try:
172
172
  # First check if lefthook is installed
173
- result = run_subprocess(["lefthook", "--version"], silent=True, raise_on_error=False)
174
- if not result:
173
+ version_check = run_subprocess(["lefthook", "--version"], silent=True, raise_on_error=False)
174
+ if not version_check:
175
175
  logger.debug("Lefthook not installed, skipping hooks")
176
176
  return True
177
177
 
gac/init_cli.py CHANGED
@@ -17,7 +17,7 @@ def _prompt_required_text(prompt: str) -> str | None:
17
17
  return None
18
18
  value = response.strip()
19
19
  if value:
20
- return value
20
+ return value # type: ignore[no-any-return]
21
21
  click.echo("A value is required. Please try again.")
22
22
 
23
23
 
@@ -34,7 +34,7 @@ def init() -> None:
34
34
  providers = [
35
35
  ("Anthropic", "claude-haiku-4-5"),
36
36
  ("Cerebras", "qwen-3-coder-480b"),
37
- ("Chutes.ai", "zai-org/GLM-4.6-FP8"),
37
+ ("Chutes", "zai-org/GLM-4.6-FP8"),
38
38
  ("Gemini", "gemini-2.5-flash"),
39
39
  ("Groq", "meta-llama/llama-4-maverick-17b-128e-instruct"),
40
40
  ("LM Studio", "gemma3"),
@@ -51,7 +51,7 @@ def init() -> None:
51
51
  if not provider:
52
52
  click.echo("Provider selection cancelled. Exiting.")
53
53
  return
54
- provider_key = provider.lower().replace(".", "").replace(" ", "-").replace("syntheticnew", "synthetic")
54
+ provider_key = provider.lower().replace(".", "").replace(" ", "-")
55
55
 
56
56
  is_ollama = provider_key == "ollama"
57
57
  is_lmstudio = provider_key == "lm-studio"
@@ -104,7 +104,9 @@ def init() -> None:
104
104
 
105
105
  api_key = questionary.password(api_key_prompt).ask()
106
106
  if api_key:
107
- if is_zai:
107
+ if is_lmstudio:
108
+ api_key_name = "LMSTUDIO_API_KEY"
109
+ elif is_zai:
108
110
  api_key_name = "ZAI_API_KEY"
109
111
  else:
110
112
  api_key_name = f"{provider_key.upper()}_API_KEY"
gac/main.py CHANGED
@@ -57,18 +57,27 @@ def main(
57
57
  handle_error(GitError("Not in a git repository"), exit_program=True)
58
58
 
59
59
  if model is None:
60
- model = config["model"]
61
- if model is None:
60
+ model_from_config = config["model"]
61
+ if model_from_config is None:
62
62
  handle_error(
63
63
  AIError.model_error(
64
64
  "gac init hasn't been run yet. Please run 'gac init' to set up your configuration, then try again."
65
65
  ),
66
66
  exit_program=True,
67
67
  )
68
+ model = str(model_from_config)
68
69
 
69
- temperature = config["temperature"]
70
- max_output_tokens = config["max_output_tokens"]
71
- max_retries = config["max_retries"]
70
+ temperature_val = config["temperature"]
71
+ assert temperature_val is not None
72
+ temperature = float(temperature_val)
73
+
74
+ max_tokens_val = config["max_output_tokens"]
75
+ assert max_tokens_val is not None
76
+ max_output_tokens = int(max_tokens_val)
77
+
78
+ max_retries_val = config["max_retries"]
79
+ assert max_retries_val is not None
80
+ max_retries = int(max_retries_val)
72
81
 
73
82
  if stage_all and (not dry_run):
74
83
  logger.info("Staging all changes")
@@ -168,8 +177,8 @@ def main(
168
177
 
169
178
  # Preprocess the diff before passing to build_prompt
170
179
  logger.debug(f"Preprocessing diff ({len(diff)} characters)")
171
- model_id = model or config["model"]
172
- processed_diff = preprocess_diff(diff, token_limit=Utility.DEFAULT_DIFF_TOKEN_LIMIT, model=model_id)
180
+ assert model is not None
181
+ processed_diff = preprocess_diff(diff, token_limit=Utility.DEFAULT_DIFF_TOKEN_LIMIT, model=model)
173
182
  logger.debug(f"Processed diff ({len(processed_diff)} characters)")
174
183
 
175
184
  system_prompt, user_prompt = build_prompt(
@@ -197,7 +206,9 @@ def main(
197
206
  # Count tokens for both prompts
198
207
  prompt_tokens = count_tokens(system_prompt, model) + count_tokens(user_prompt, model)
199
208
 
200
- warning_limit = config.get("warning_limit_tokens", EnvDefaults.WARNING_LIMIT_TOKENS)
209
+ warning_limit_val = config.get("warning_limit_tokens", EnvDefaults.WARNING_LIMIT_TOKENS)
210
+ assert warning_limit_val is not None
211
+ warning_limit = int(warning_limit_val)
201
212
  if warning_limit and prompt_tokens > warning_limit:
202
213
  console.print(
203
214
  f"[yellow]⚠️ WARNING: Prompt contains {prompt_tokens} tokens, which exceeds the warning limit of "
gac/preprocess.py CHANGED
@@ -143,7 +143,7 @@ def extract_binary_file_summary(section: str) -> str:
143
143
  return extract_filtered_file_summary(section, "[Binary file change]")
144
144
 
145
145
 
146
- def extract_filtered_file_summary(section: str, change_type: str = None) -> str:
146
+ def extract_filtered_file_summary(section: str, change_type: str | None = None) -> str:
147
147
  """Extract a summary of filtered file changes from a diff section.
148
148
 
149
149
  Args:
gac/security.py CHANGED
@@ -179,7 +179,7 @@ def scan_diff_section(section: str) -> list[DetectedSecret]:
179
179
  Returns:
180
180
  List of detected secrets
181
181
  """
182
- secrets = []
182
+ secrets: list[DetectedSecret] = []
183
183
  file_path = extract_file_path_from_diff_section(section)
184
184
 
185
185
  if not file_path:
gac/utils.py CHANGED
@@ -36,7 +36,7 @@ def setup_logging(
36
36
  level=log_level,
37
37
  format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
38
38
  datefmt="%Y-%m-%d %H:%M:%S",
39
- **kwargs,
39
+ **kwargs, # type: ignore[arg-type]
40
40
  )
41
41
 
42
42
  if suppress_noisy:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gac
3
- Version: 1.9.1
3
+ Version: 1.9.3
4
4
  Summary: AI-powered Git commit message generator with multi-provider support
5
5
  Project-URL: Homepage, https://github.com/cellwebb/gac
6
6
  Project-URL: Documentation, https://github.com/cellwebb/gac#readme
@@ -50,7 +50,8 @@ Description-Content-Type: text/markdown
50
50
  [![Python](https://img.shields.io/badge/python-3.10%20|%203.11%20|%203.12%20|%203.13%20|%203.14-blue.svg)](https://www.python.org/downloads/)
51
51
  [![Build Status](https://github.com/cellwebb/gac/actions/workflows/ci.yml/badge.svg)](https://github.com/cellwebb/gac/actions)
52
52
  [![codecov](https://codecov.io/gh/cellwebb/gac/branch/main/graph/badge.svg)](https://app.codecov.io/gh/cellwebb/gac)
53
- [![Code Style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
53
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
54
+ [![mypy](https://img.shields.io/badge/mypy-checked-blue.svg)](https://mypy-lang.org/)
54
55
  [![Contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg)](docs/CONTRIBUTING.md)
55
56
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
56
57
 
@@ -1,20 +1,20 @@
1
1
  gac/__init__.py,sha256=z9yGInqtycFIT3g1ca24r-A3699hKVaRqGUI79wsmMc,415
2
- gac/__version__.py,sha256=G1n_WKkZXSioJbRY3wekL5t5AcCwR3K2fA6ITDQQ1NI,66
2
+ gac/__version__.py,sha256=bAfkjMjFPqHxyCDtIve6MEc-rYfJ1cDzL1dp4Kpo_QU,66
3
3
  gac/ai.py,sha256=-0rIZQCHC7yOEmkLtCLDzeInnrm960hVpiEELi8NM_U,3513
4
- gac/ai_utils.py,sha256=dGfac6ZWQARZDnH6ygnqQ2W4eTIDh_wOx6iGg5lA_Gw,7271
5
- gac/cli.py,sha256=15Io35xSvoZ7_q9ADgely1un0tAprNuLRPdghGaIQTg,5058
6
- gac/config.py,sha256=nVEnjCPmobspQl9NEcFLBYcIeUi2J9cui8CEzqIHnFY,1739
4
+ gac/ai_utils.py,sha256=eqrpiBTueCgSOxUC2b4Ei0G4DM1GMt866sJEIhWpytU,7333
5
+ gac/cli.py,sha256=crUUI6osYtE3QAZ7r6DRlVk9gR3X2PctzS1sssVQ9_g,5070
6
+ gac/config.py,sha256=n3TkQYBqSKkH68QUM6M7kwSK83ghmItoh0p5ZDFnhHA,1746
7
7
  gac/config_cli.py,sha256=v9nFHZO1RvK9fzHyuUS6SG-BCLHMsdOMDwWamBhVVh4,1608
8
- gac/constants.py,sha256=R3oUwPLk_uWnBkg-J7Or-vomRr-iVKeLf1xljJeKclo,4988
8
+ gac/constants.py,sha256=y3qMMwAne5LUk5FexIzEDxEFWnuPwaZk9aFZEdBZ3gw,4947
9
9
  gac/diff_cli.py,sha256=wnVQ9OFGnM0d2Pj9WVjWbo0jxqIuRHVAwmb8wU9Pa3E,5676
10
10
  gac/errors.py,sha256=ysDIVRCd0YQVTOW3Q6YzdolxCdtkoQCAFf3_jrqbjUY,7916
11
- gac/git.py,sha256=_Co25XA1Nku03h50C_HiEf4ugEz6rK5j_IYi-rr5gco,8005
12
- gac/init_cli.py,sha256=LEw26g-tb6GZdN3DaUuLx3OFvZPKPOIFKnqgDRe6Y8s,4677
13
- gac/main.py,sha256=odWu_1Z0KVr--3duc4iFOE9ix0SGqykgzRDz-JY482c,15771
14
- gac/preprocess.py,sha256=krrLPHsccYMdn_YAtUrppBJIoRgevxGWusDwhE40LEo,15366
11
+ gac/git.py,sha256=g6tvph50zV-wrTWrxARYXEpl0NeI8-ffFwHoqhp3fSE,8033
12
+ gac/init_cli.py,sha256=wq2MMi1xQrbVTib-5BsVdbPXQkPStB3G3Q8VnSKiKFQ,4740
13
+ gac/main.py,sha256=pQUvrJt3cqxKV7b7w7U_Gb9QOQMnoSB7tI0s_3uZAI0,16163
14
+ gac/preprocess.py,sha256=aMxsjGxy9YP752NWjgf0KP5Sn6p8keIJAGlMYr8jDgQ,15373
15
15
  gac/prompt.py,sha256=d_kBXmhf3bDVLyDj8J7AS7GBAxF2jlc8lXoHX3Dzi5k,24255
16
- gac/security.py,sha256=M1MZm6BLOeKl6rH_-UdXsSKol39FnA5fIP3YP394yZE,9898
17
- gac/utils.py,sha256=W3ladtmsH01MNLdckQYTzYrYbTGEdzCKI36he9C-y_E,3945
16
+ gac/security.py,sha256=15Yp6YR8QC4eECJi1BUCkMteh_veZXUbLL6W8qGcDm4,9920
17
+ gac/utils.py,sha256=nV42-brIHW_fBg7x855GM8nRrqEBbRzTSweg-GTyGE8,3971
18
18
  gac/providers/__init__.py,sha256=ejIM5vvmfTp7vfJSNeQQPIEJusOkKTUZpUE7OeWBc9Y,876
19
19
  gac/providers/anthropic.py,sha256=VK5d1s1PmBNDwh_x7illQ2CIZIHNIYU28btVfizwQPs,2036
20
20
  gac/providers/cerebras.py,sha256=Ik8lhlsliGJVkgDgqlThfpra9tqbdYQZkaC4eNxRd9w,1648
@@ -28,8 +28,8 @@ gac/providers/openrouter.py,sha256=H3ce8JcRUYq1I30lOjGESdX7jfoPkW3mKAYnc2aYfBw,2
28
28
  gac/providers/streamlake.py,sha256=KAA2ZnpuEI5imzvdWVWUhEBHSP0BMnprKXte6CbwBWY,2047
29
29
  gac/providers/synthetic.py,sha256=sRMIJTS9LpcXd9A7qp_ZjZxdqtTKRn9fl1W4YwJZP4c,1855
30
30
  gac/providers/zai.py,sha256=kywhhrCfPBu0rElZyb-iENxQxxpVGykvePuL4xrXlaU,2739
31
- gac-1.9.1.dist-info/METADATA,sha256=xUSS5EcAO1_k4RJ-ukG_XN7g_twtCy2F0jgjgn0RBLE,9279
32
- gac-1.9.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
33
- gac-1.9.1.dist-info/entry_points.txt,sha256=tdjN-XMmcWfL92swuRAjT62bFLOAwk9bTMRLGP5Z4aI,36
34
- gac-1.9.1.dist-info/licenses/LICENSE,sha256=vOab37NouL1PNs5BswnPayrMCqaN2sqLfMQfqPDrpZg,1103
35
- gac-1.9.1.dist-info/RECORD,,
31
+ gac-1.9.3.dist-info/METADATA,sha256=eIfvTaTy23On_QW6wNM4YPFtuS5gaNMDiEw3fko8UYE,9409
32
+ gac-1.9.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
33
+ gac-1.9.3.dist-info/entry_points.txt,sha256=tdjN-XMmcWfL92swuRAjT62bFLOAwk9bTMRLGP5Z4aI,36
34
+ gac-1.9.3.dist-info/licenses/LICENSE,sha256=vOab37NouL1PNs5BswnPayrMCqaN2sqLfMQfqPDrpZg,1103
35
+ gac-1.9.3.dist-info/RECORD,,
File without changes