Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 31 additions & 4 deletions codeflash/code_utils/env_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,55 @@
from codeflash.code_utils.shell_utils import read_api_key_from_shell_config, save_api_key_to_rc
from codeflash.lsp.helpers import is_LSP_enabled

_get_language_support_by_common_formatters = None


def check_formatter_installed(
formatter_cmds: list[str], exit_on_failure: bool = True, language: str = "python"
) -> bool:
if not formatter_cmds or formatter_cmds[0] == "disabled":
return True
first_cmd = formatter_cmds[0]
cmd_tokens = shlex.split(first_cmd) if isinstance(first_cmd, str) else [first_cmd]

# Fast-path split for simple commands without quoting/backslashes; fall back to shlex for correctness.
if isinstance(first_cmd, str):
if ('"' not in first_cmd) and ("'" not in first_cmd) and ("\\" not in first_cmd):
cmd_tokens = first_cmd.split()
else:
cmd_tokens = shlex.split(first_cmd)
else:
cmd_tokens = [first_cmd]
Comment on lines +29 to +35

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since formatter_cmds: list[str], first_cmd is always a str, making the isinstance check always true and the else branch unreachable (mypy flags this as [unreachable]). The original code had the same dead branch in ternary form — consider removing it for clarity:

Suggested change
if isinstance(first_cmd, str):
if ('"' not in first_cmd) and ("'" not in first_cmd) and ("\\" not in first_cmd):
cmd_tokens = first_cmd.split()
else:
cmd_tokens = shlex.split(first_cmd)
else:
cmd_tokens = [first_cmd]
if ('"' not in first_cmd) and ("'" not in first_cmd) and ("\\" not in first_cmd):
cmd_tokens = first_cmd.split()
else:
cmd_tokens = shlex.split(first_cmd)



if not cmd_tokens:
return True

exe_name = cmd_tokens[0]
command_str = " ".join(formatter_cmds).replace(" $file", "")

if shutil.which(exe_name) is None:
command_str = " ".join(formatter_cmds).replace(" $file", "")
logger.error(
f"Could not find formatter: {command_str}\n"
f"Please install it or update 'formatter-cmds' in your codeflash configuration"
)
return False

# Import here to avoid circular import
from codeflash.languages.registry import get_language_support_by_common_formatters
# Import here to avoid circular import, but cache the imported callable to avoid repeated import cost.
global _get_language_support_by_common_formatters
if _get_language_support_by_common_formatters is None:
try:
from codeflash.languages.registry import \
get_language_support_by_common_formatters as _cached_helper

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This catches Exception for what should be an ImportError. If the import succeeds but the module has a runtime bug, this silently swallows the error and causes the function to return True (claiming the formatter is installed). Consider narrowing to except ImportError:.

Suggested change
except ImportError:

_get_language_support_by_common_formatters = _cached_helper
except Exception:
_get_language_support_by_common_formatters = None

get_language_support_by_common_formatters = _get_language_support_by_common_formatters
if not get_language_support_by_common_formatters:
logger.debug(f"Could not determine language for formatter: {formatter_cmds}")
return True


lang_support = get_language_support_by_common_formatters(formatter_cmds)
if not lang_support:
Expand All @@ -59,12 +84,14 @@ def check_formatter_installed(
format_code(formatter_cmds, tmp_file, print_status=False, exit_on_failure=False)
return True
except FileNotFoundError:
command_str = " ".join(formatter_cmds).replace(" $file", "")
logger.error(
f"Could not find formatter: {command_str}\n"
f"Please install it or update 'formatter-cmds' in your codeflash configuration"
)
return False
except Exception as e:
command_str = " ".join(formatter_cmds).replace(" $file", "")
logger.error(f"Formatter failed to run: {command_str}\nError: {e}")
return False

Expand Down
30 changes: 21 additions & 9 deletions codeflash/languages/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@

from codeflash.languages.base import LanguageSupport

_PY_FORMATTERS = frozenset(("black", "isort", "ruff", "autopep8", "yapf", "pyfmt"))

_JS_TS_FORMATTERS = frozenset(("prettier", "eslint", "biome", "rome", "deno", "standard", "tslint"))

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -211,29 +215,37 @@ def get_language_support(identifier: Path | Language | str) -> LanguageSupport:


def get_language_support_by_common_formatters(formatter_cmd: str | list[str]) -> LanguageSupport | None:
_ensure_languages_registered()
language: Language | None = None
_ensure_called = False

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead variable — _ensure_called is assigned but never read. Remove it.

Suggested change
_ensure_called = False

# Accept both a single string or list of strings
if isinstance(formatter_cmd, str):
formatter_cmd = [formatter_cmd]

if len(formatter_cmd) == 1:
formatter_cmd = formatter_cmd[0].split(" ")

# Try as extension first
ext = None
# Try to determine language by checking tokens against known formatter names using set intersection.
# This avoids generator overhead and repeated membership checks.
tokens_set = set(formatter_cmd)

py_formatters = ["black", "isort", "ruff", "autopep8", "yapf", "pyfmt"]
js_ts_formatters = ["prettier", "eslint", "biome", "rome", "deno", "standard", "tslint"]

if any(cmd in py_formatters for cmd in formatter_cmd):
ext: str | None = None
if tokens_set & _PY_FORMATTERS:
ext = ".py"
elif any(cmd in js_ts_formatters for cmd in formatter_cmd):
elif tokens_set & _JS_TS_FORMATTERS:
ext = ".js"

if ext is None:
# can't determine language
return None


# Only ensure languages registered if necessary to access registry
# This avoids the expensive registration step on every call when we can early-return.
if ext not in _EXTENSION_REGISTRY:
_ensure_languages_registered()
if ext not in _EXTENSION_REGISTRY:
# Still missing after ensuring registration; cannot determine language support
return None

cls = _EXTENSION_REGISTRY[ext]
language = cls().language

Expand Down
Loading