From a96918766fb9bf21eef4b744684f9f371b751cf5 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Tue, 10 Feb 2026 04:57:10 -0500 Subject: [PATCH 001/100] refactor: replace jedi_definition with definition_type on FunctionSource Store only the type string instead of the full Jedi Name object, removing the need for arbitrary_types_allowed and the runtime dependency on jedi in the model layer. --- codeflash/code_utils/code_replacer.py | 3 +- codeflash/context/code_context_extractor.py | 8 ++--- .../context/unused_definition_remover.py | 8 ++--- codeflash/models/models.py | 5 ++- codeflash/optimization/function_optimizer.py | 4 +-- tests/test_code_replacement.py | 34 +++++-------------- tests/test_function_dependencies.py | 5 ++- tests/test_unused_helper_revert.py | 4 +-- 8 files changed, 26 insertions(+), 45 deletions(-) diff --git a/codeflash/code_utils/code_replacer.py b/codeflash/code_utils/code_replacer.py index e543d184d..c19de3b7e 100644 --- a/codeflash/code_utils/code_replacer.py +++ b/codeflash/code_utils/code_replacer.py @@ -871,8 +871,7 @@ def replace_optimized_code( [ callee.qualified_name for callee in code_context.helper_functions - if callee.file_path == module_path - and (callee.jedi_definition is None or callee.jedi_definition.type != "class") + if callee.file_path == module_path and callee.definition_type != "class" ] ), candidate.source_code, diff --git a/codeflash/context/code_context_extractor.py b/codeflash/context/code_context_extractor.py index 61de73c32..5142ce518 100644 --- a/codeflash/context/code_context_extractor.py +++ b/codeflash/context/code_context_extractor.py @@ -265,7 +265,7 @@ def get_code_optimization_context_for_language( fully_qualified_name=helper.qualified_name, only_function_name=helper.name, source_code=helper.source_code, - jedi_definition=None, + definition_type=None, ) ) @@ -488,7 +488,7 @@ def get_function_to_optimize_as_function_source( fully_qualified_name=name.full_name, only_function_name=name.name, source_code=name.get_line_code(), - jedi_definition=name, + definition_type=name.type, ) except Exception as e: logger.exception(f"Error while getting function source: {e}") @@ -544,7 +544,7 @@ def get_function_sources_from_jedi( fully_qualified_name=definition.full_name, only_function_name=definition.name, source_code=definition.get_line_code(), - jedi_definition=definition, + definition_type=definition.type, ) file_path_to_function_source[definition_path].add(function_source) function_source_list.append(function_source) @@ -562,7 +562,7 @@ def get_function_sources_from_jedi( fully_qualified_name=f"{definition.full_name}.__init__", only_function_name="__init__", source_code=definition.get_line_code(), - jedi_definition=definition, + definition_type=definition.type, ) file_path_to_function_source[definition_path].add(function_source) function_source_list.append(function_source) diff --git a/codeflash/context/unused_definition_remover.py b/codeflash/context/unused_definition_remover.py index f4eec94e8..00b077f63 100644 --- a/codeflash/context/unused_definition_remover.py +++ b/codeflash/context/unused_definition_remover.py @@ -630,8 +630,8 @@ def _analyze_imports_in_optimized_code( helpers_by_file_and_func = defaultdict(dict) helpers_by_file = defaultdict(list) # preserved for "import module" for helper in code_context.helper_functions: - jedi_type = helper.jedi_definition.type if helper.jedi_definition else None - if jedi_type != "class": # Include when jedi_definition is None (non-Python) + jedi_type = helper.definition_type + if jedi_type != "class": # Include when definition_type is None (non-Python) func_name = helper.only_function_name module_name = helper.file_path.stem # Cache function lookup for this (module, func) @@ -789,8 +789,8 @@ def detect_unused_helper_functions( unused_helpers = [] entrypoint_file_path = function_to_optimize.file_path for helper_function in code_context.helper_functions: - jedi_type = helper_function.jedi_definition.type if helper_function.jedi_definition else None - if jedi_type != "class": # Include when jedi_definition is None (non-Python) + jedi_type = helper_function.definition_type + if jedi_type != "class": # Include when definition_type is None (non-Python) # Check if the helper function is called using multiple name variants helper_qualified_name = helper_function.qualified_name helper_simple_name = helper_function.only_function_name diff --git a/codeflash/models/models.py b/codeflash/models/models.py index d56672ba8..924d3a466 100644 --- a/codeflash/models/models.py +++ b/codeflash/models/models.py @@ -25,7 +25,6 @@ from re import Pattern from typing import Any, NamedTuple, Optional, cast -from jedi.api.classes import Name from pydantic import BaseModel, ConfigDict, Field, PrivateAttr, ValidationError, model_validator from pydantic.dataclasses import dataclass @@ -136,14 +135,14 @@ class CoverReturnCode(IntEnum): ERROR = 2 -@dataclass(frozen=True, config={"arbitrary_types_allowed": True}) +@dataclass(frozen=True) class FunctionSource: file_path: Path qualified_name: str fully_qualified_name: str only_function_name: str source_code: str - jedi_definition: Name | None = None # None for non-Python languages + definition_type: str | None = None # e.g. "function", "class"; None for non-Python languages def __eq__(self, other: object) -> bool: if not isinstance(other, FunctionSource): diff --git a/codeflash/optimization/function_optimizer.py b/codeflash/optimization/function_optimizer.py index cac81fc92..e04e7626c 100644 --- a/codeflash/optimization/function_optimizer.py +++ b/codeflash/optimization/function_optimizer.py @@ -1501,8 +1501,8 @@ def replace_function_and_helpers_with_optimized_code( self.function_to_optimize.qualified_name ) for helper_function in code_context.helper_functions: - # Skip class definitions (jedi_definition may be None for non-Python languages) - if helper_function.jedi_definition is None or helper_function.jedi_definition.type != "class": + # Skip class definitions (definition_type may be None for non-Python languages) + if helper_function.definition_type != "class": read_writable_functions_by_file_path[helper_function.file_path].add(helper_function.qualified_name) for module_abspath, qualified_names in read_writable_functions_by_file_path.items(): did_update |= replace_function_definitions_in_module( diff --git a/tests/test_code_replacement.py b/tests/test_code_replacement.py index eccdc4e03..fbca6d71e 100644 --- a/tests/test_code_replacement.py +++ b/tests/test_code_replacement.py @@ -1,6 +1,5 @@ from __future__ import annotations -import dataclasses import os import re from collections import defaultdict @@ -19,28 +18,13 @@ replace_functions_in_file, ) from codeflash.discovery.functions_to_optimize import FunctionToOptimize -from codeflash.models.models import CodeOptimizationContext, CodeStringsMarkdown, FunctionParent +from codeflash.models.models import CodeOptimizationContext, CodeStringsMarkdown, FunctionParent, FunctionSource from codeflash.optimization.function_optimizer import FunctionOptimizer from codeflash.verification.verification_utils import TestConfig os.environ["CODEFLASH_API_KEY"] = "cf-test-key" -@dataclasses.dataclass -class JediDefinition: - type: str - - -@dataclasses.dataclass -class FakeFunctionSource: - file_path: Path - qualified_name: str - fully_qualified_name: str - only_function_name: str - source_code: str - jedi_definition: JediDefinition - - class Args: disable_imports_sorting = True formatter_cmds = ["disabled"] @@ -1137,7 +1121,7 @@ def get_test_pass_fail_report_by_type(self) -> dict[TestType, dict[str, int]]: preexisting_objects = find_preexisting_objects(original_code) helper_functions = [ - FakeFunctionSource( + FunctionSource( file_path=Path( "/Users/saurabh/Library/CloudStorage/Dropbox/codeflash/cli/codeflash/verification/test_results.py" ), @@ -1145,7 +1129,7 @@ def get_test_pass_fail_report_by_type(self) -> dict[TestType, dict[str, int]]: fully_qualified_name="codeflash.verification.test_results.TestType", only_function_name="TestType", source_code="", - jedi_definition=JediDefinition(type="class"), + definition_type="class", ) ] @@ -1160,7 +1144,7 @@ def get_test_pass_fail_report_by_type(self) -> dict[TestType, dict[str, int]]: helper_functions_by_module_abspath = defaultdict(set) for helper_function in helper_functions: - if helper_function.jedi_definition.type != "class": + if helper_function.definition_type != "class": helper_functions_by_module_abspath[helper_function.file_path].add(helper_function.qualified_name) for module_abspath, qualified_names in helper_functions_by_module_abspath.items(): new_code: str = replace_functions_and_add_imports( @@ -1352,21 +1336,21 @@ def cosine_similarity_top_k( preexisting_objects: set[tuple[str, tuple[FunctionParent, ...]]] = find_preexisting_objects(original_code) helper_functions = [ - FakeFunctionSource( + FunctionSource( file_path=(Path(__file__).parent / "code_to_optimize" / "math_utils.py").resolve(), qualified_name="Matrix", fully_qualified_name="code_to_optimize.math_utils.Matrix", only_function_name="Matrix", source_code="", - jedi_definition=JediDefinition(type="class"), + definition_type="class", ), - FakeFunctionSource( + FunctionSource( file_path=(Path(__file__).parent / "code_to_optimize" / "math_utils.py").resolve(), qualified_name="cosine_similarity", fully_qualified_name="code_to_optimize.math_utils.cosine_similarity", only_function_name="cosine_similarity", source_code="", - jedi_definition=JediDefinition(type="function"), + definition_type="function", ), ] @@ -1425,7 +1409,7 @@ def cosine_similarity_top_k( ) helper_functions_by_module_abspath = defaultdict(set) for helper_function in helper_functions: - if helper_function.jedi_definition.type != "class": + if helper_function.definition_type != "class": helper_functions_by_module_abspath[helper_function.file_path].add(helper_function.qualified_name) for module_abspath, qualified_names in helper_functions_by_module_abspath.items(): new_helper_code: str = replace_functions_and_add_imports( diff --git a/tests/test_function_dependencies.py b/tests/test_function_dependencies.py index f51780f92..988f60b7b 100644 --- a/tests/test_function_dependencies.py +++ b/tests/test_function_dependencies.py @@ -151,10 +151,9 @@ def test_class_method_dependencies() -> None: # The code_context above should have the topologicalSortUtil function in it assert len(code_context.helper_functions) == 1 assert ( - code_context.helper_functions[0].jedi_definition.full_name - == "test_function_dependencies.Graph.topologicalSortUtil" + code_context.helper_functions[0].fully_qualified_name == "test_function_dependencies.Graph.topologicalSortUtil" ) - assert code_context.helper_functions[0].jedi_definition.name == "topologicalSortUtil" + assert code_context.helper_functions[0].only_function_name == "topologicalSortUtil" assert ( code_context.helper_functions[0].fully_qualified_name == "test_function_dependencies.Graph.topologicalSortUtil" ) diff --git a/tests/test_unused_helper_revert.py b/tests/test_unused_helper_revert.py index 18d21de32..c33138200 100644 --- a/tests/test_unused_helper_revert.py +++ b/tests/test_unused_helper_revert.py @@ -915,7 +915,7 @@ def local_helper(self, x): "only_function_name": "global_helper_1", "fully_qualified_name": "main.global_helper_1", "file_path": main_file, - "jedi_definition": type("MockJedi", (), {"type": "function"})(), + "definition_type": "function", }, )(), type( @@ -926,7 +926,7 @@ def local_helper(self, x): "only_function_name": "global_helper_2", "fully_qualified_name": "main.global_helper_2", "file_path": main_file, - "jedi_definition": type("MockJedi", (), {"type": "function"})(), + "definition_type": "function", }, )(), ] From b69a713fe7e054156dc60463f018b5c8dd9894bd Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Tue, 10 Feb 2026 04:57:21 -0500 Subject: [PATCH 002/100] feat: add persistent CallGraph class with SQLite caching Introduces CallGraph that uses Jedi infer()+goto() to build call edges, stores them in codeflash_cache.db with content-hash invalidation, and serves as a drop-in replacement for get_function_sources_from_jedi(). --- codeflash/context/call_graph.py | 295 ++++++++++++++++++++++++++++++++ 1 file changed, 295 insertions(+) create mode 100644 codeflash/context/call_graph.py diff --git a/codeflash/context/call_graph.py b/codeflash/context/call_graph.py new file mode 100644 index 000000000..15ff20119 --- /dev/null +++ b/codeflash/context/call_graph.py @@ -0,0 +1,295 @@ +from __future__ import annotations + +import hashlib +import os +import sqlite3 +from collections import defaultdict +from pathlib import Path +from typing import TYPE_CHECKING + +from codeflash.cli_cmds.console import logger +from codeflash.code_utils.code_utils import get_qualified_name, path_belongs_to_site_packages +from codeflash.models.models import FunctionSource + +if TYPE_CHECKING: + from jedi.api.classes import Name + + +class CallGraph: + SCHEMA_VERSION = 1 + + def __init__(self, project_root: Path, db_path: Path | None = None) -> None: + import jedi + + self.project_root = project_root.resolve() + self.project_root_str = str(self.project_root) + self.jedi_project = jedi.Project(path=self.project_root) + + if db_path is None: + from codeflash.code_utils.compat import codeflash_cache_db + + db_path = codeflash_cache_db + + self.conn = sqlite3.connect(str(db_path)) + self.conn.execute("PRAGMA journal_mode=WAL") + self.indexed_file_hashes: dict[str, str] = {} + self._init_schema() + + def _init_schema(self) -> None: + cur = self.conn.cursor() + cur.execute("CREATE TABLE IF NOT EXISTS cg_schema_version (version INTEGER PRIMARY KEY)") + row = cur.execute("SELECT version FROM cg_schema_version LIMIT 1").fetchone() + if row is None: + cur.execute("INSERT INTO cg_schema_version (version) VALUES (?)", (self.SCHEMA_VERSION,)) + elif row[0] != self.SCHEMA_VERSION: + # Schema mismatch — drop all cg_ tables and recreate + cur.execute("DROP TABLE IF EXISTS cg_call_edges") + cur.execute("DROP TABLE IF EXISTS cg_indexed_files") + cur.execute("DELETE FROM cg_schema_version") + cur.execute("INSERT INTO cg_schema_version (version) VALUES (?)", (self.SCHEMA_VERSION,)) + + cur.execute( + """CREATE TABLE IF NOT EXISTS cg_indexed_files ( + project_root TEXT NOT NULL, + file_path TEXT NOT NULL, + file_hash TEXT NOT NULL, + PRIMARY KEY (project_root, file_path) + )""" + ) + cur.execute( + """CREATE TABLE IF NOT EXISTS cg_call_edges ( + project_root TEXT NOT NULL, + caller_file TEXT NOT NULL, + caller_qualified_name TEXT NOT NULL, + callee_file TEXT NOT NULL, + callee_qualified_name TEXT NOT NULL, + callee_fully_qualified_name TEXT NOT NULL, + callee_only_function_name TEXT NOT NULL, + callee_definition_type TEXT NOT NULL, + callee_source_line TEXT NOT NULL, + PRIMARY KEY (project_root, caller_file, caller_qualified_name, + callee_file, callee_qualified_name) + )""" + ) + cur.execute( + """CREATE INDEX IF NOT EXISTS idx_cg_edges_caller + ON cg_call_edges (project_root, caller_file, caller_qualified_name)""" + ) + self.conn.commit() + + def get_callees( + self, file_path_to_qualified_names: dict[Path, set[str]] + ) -> tuple[dict[Path, set[FunctionSource]], list[FunctionSource]]: + file_path_to_function_source: dict[Path, set[FunctionSource]] = defaultdict(set) + function_source_list: list[FunctionSource] = [] + + all_caller_keys: list[tuple[str, str]] = [] + for file_path, qualified_names in file_path_to_qualified_names.items(): + self.ensure_file_indexed(file_path) + fp_str = str(file_path.resolve()) + for qn in qualified_names: + all_caller_keys.append((fp_str, qn)) + + if not all_caller_keys: + return file_path_to_function_source, function_source_list + + cur = self.conn.cursor() + for caller_file, caller_qn in all_caller_keys: + rows = cur.execute( + """SELECT callee_file, callee_qualified_name, callee_fully_qualified_name, + callee_only_function_name, callee_definition_type, callee_source_line + FROM cg_call_edges + WHERE project_root = ? AND caller_file = ? AND caller_qualified_name = ?""", + (self.project_root_str, caller_file, caller_qn), + ).fetchall() + for callee_file, callee_qn, callee_fqn, callee_name, callee_type, callee_src in rows: + callee_path = Path(callee_file) + fs = FunctionSource( + file_path=callee_path, + qualified_name=callee_qn, + fully_qualified_name=callee_fqn, + only_function_name=callee_name, + source_code=callee_src, + definition_type=callee_type, + ) + file_path_to_function_source[callee_path].add(fs) + function_source_list.append(fs) + + return file_path_to_function_source, function_source_list + + def ensure_file_indexed(self, file_path: Path) -> None: + resolved = str(file_path.resolve()) + try: + content = file_path.read_text(encoding="utf-8") + except Exception: + return + file_hash = hashlib.sha256(content.encode("utf-8")).hexdigest() + + cached_hash = self.indexed_file_hashes.get(resolved) + if cached_hash == file_hash: + return + + # Check DB for stored hash + row = self.conn.execute( + "SELECT file_hash FROM cg_indexed_files WHERE project_root = ? AND file_path = ?", + (self.project_root_str, resolved), + ).fetchone() + if row and row[0] == file_hash: + self.indexed_file_hashes[resolved] = file_hash + return + + self.index_file(file_path, file_hash) + + def index_file(self, file_path: Path, file_hash: str) -> None: + import jedi + + resolved = str(file_path.resolve()) + + # Delete stale data for this file + cur = self.conn.cursor() + cur.execute( + "DELETE FROM cg_call_edges WHERE project_root = ? AND caller_file = ?", (self.project_root_str, resolved) + ) + cur.execute( + "DELETE FROM cg_indexed_files WHERE project_root = ? AND file_path = ?", (self.project_root_str, resolved) + ) + + try: + script = jedi.Script(path=file_path, project=self.jedi_project) + refs = script.get_names(all_scopes=True, definitions=False, references=True) + except Exception: + logger.debug(f"CallGraph: failed to parse {file_path}") + cur.execute( + "INSERT OR REPLACE INTO cg_indexed_files (project_root, file_path, file_hash) VALUES (?, ?, ?)", + (self.project_root_str, resolved, file_hash), + ) + self.conn.commit() + self.indexed_file_hashes[resolved] = file_hash + return + + edges: set[tuple[str, str, str, str, str, str, str, str]] = set() + + for ref in refs: + try: + caller_qn = self._get_enclosing_function_qualified_name(ref) + if caller_qn is None: + continue + + definitions = self._resolve_definitions(ref) + if not definitions: + continue + + definition = definitions[0] + definition_path = definition.module_path + if definition_path is None: + continue + + if not self._is_valid_definition(definition, caller_qn): + continue + + if definition.type == "function": + callee_qn = get_qualified_name(definition.module_name, definition.full_name) + if len(callee_qn.split(".")) > 2: + continue + edges.add( + ( + resolved, + caller_qn, + str(definition_path), + callee_qn, + definition.full_name, + definition.name, + definition.type, + definition.get_line_code(), + ) + ) + elif definition.type == "class": + init_qn = get_qualified_name(definition.module_name, f"{definition.full_name}.__init__") + if len(init_qn.split(".")) > 2: + continue + edges.add( + ( + resolved, + caller_qn, + str(definition_path), + init_qn, + f"{definition.full_name}.__init__", + "__init__", + definition.type, + definition.get_line_code(), + ) + ) + except Exception: + continue + + cur.executemany( + """INSERT OR REPLACE INTO cg_call_edges + (project_root, caller_file, caller_qualified_name, + callee_file, callee_qualified_name, callee_fully_qualified_name, + callee_only_function_name, callee_definition_type, callee_source_line) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""", + [(self.project_root_str, *edge) for edge in edges], + ) + cur.execute( + "INSERT OR REPLACE INTO cg_indexed_files (project_root, file_path, file_hash) VALUES (?, ?, ?)", + (self.project_root_str, resolved, file_hash), + ) + self.conn.commit() + self.indexed_file_hashes[resolved] = file_hash + + def _resolve_definitions(self, ref: Name) -> list[Name]: + try: + inferred = ref.infer() + valid = [d for d in inferred if d.type in ("function", "class")] + if valid: + return valid + except Exception: + pass + + try: + return ref.goto(follow_imports=True, follow_builtin_imports=False) + except Exception: + return [] + + def _is_valid_definition(self, definition: Name, caller_qualified_name: str) -> bool: + definition_path = definition.module_path + if definition_path is None: + return False + if not str(definition_path).startswith(self.project_root_str + os.sep): + return False + if path_belongs_to_site_packages(definition_path): + return False + if not definition.full_name or not definition.full_name.startswith(definition.module_name): + return False + if definition.type not in ("function", "class"): + return False + # No self-edges + try: + def_qn = get_qualified_name(definition.module_name, definition.full_name) + if def_qn == caller_qualified_name: + return False + except ValueError: + return False + # Not an inner function of the caller + try: + from codeflash.optimization.function_context import belongs_to_function_qualified + + if belongs_to_function_qualified(definition, caller_qualified_name): + return False + except Exception: + pass + return True + + def _get_enclosing_function_qualified_name(self, ref: Name) -> str | None: + try: + parent = ref.parent() + if parent is None or parent.type != "function": + return None + if not parent.full_name or not parent.full_name.startswith(parent.module_name): + return None + return get_qualified_name(parent.module_name, parent.full_name) + except (ValueError, AttributeError): + return None + + def close(self) -> None: + self.conn.close() From 0078539fe20c1227889a6e5bee44cd0aafcf2cbc Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Tue, 10 Feb 2026 04:57:38 -0500 Subject: [PATCH 003/100] feat: wire CallGraph into the optimization pipeline Create CallGraph in Optimizer.run() for Python runs, pass it through FunctionOptimizer to code_context_extractor where it replaces get_function_sources_from_jedi() calls when available. --- codeflash/context/code_context_extractor.py | 19 +++++++++++++------ codeflash/optimization/function_optimizer.py | 5 ++++- codeflash/optimization/optimizer.py | 20 ++++++++++++++++++++ 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/codeflash/context/code_context_extractor.py b/codeflash/context/code_context_extractor.py index 5142ce518..4650de795 100644 --- a/codeflash/context/code_context_extractor.py +++ b/codeflash/context/code_context_extractor.py @@ -37,6 +37,7 @@ from jedi.api.classes import Name from libcst import CSTNode + from codeflash.context.call_graph import CallGraph from codeflash.context.unused_definition_remover import UsageInfo from codeflash.languages.base import HelperFunction @@ -78,6 +79,7 @@ def get_code_optimization_context( project_root_path: Path, optim_token_limit: int = OPTIMIZATION_CONTEXT_TOKEN_LIMIT, testgen_token_limit: int = TESTGEN_CONTEXT_TOKEN_LIMIT, + call_graph: CallGraph | None = None, ) -> CodeOptimizationContext: # Route to language-specific implementation for non-Python languages if not is_python(): @@ -86,9 +88,11 @@ def get_code_optimization_context( ) # Get FunctionSource representation of helpers of FTO - helpers_of_fto_dict, helpers_of_fto_list = get_function_sources_from_jedi( - {function_to_optimize.file_path: {function_to_optimize.qualified_name}}, project_root_path - ) + fto_input = {function_to_optimize.file_path: {function_to_optimize.qualified_name}} + if call_graph is not None: + helpers_of_fto_dict, helpers_of_fto_list = call_graph.get_callees(fto_input) + else: + helpers_of_fto_dict, helpers_of_fto_list = get_function_sources_from_jedi(fto_input, project_root_path) # Add function to optimize into helpers of FTO dict, as they'll be processed together fto_as_function_source = get_function_to_optimize_as_function_source(function_to_optimize, project_root_path) @@ -105,9 +109,12 @@ def get_code_optimization_context( qualified_names.update({f"{qn.rsplit('.', 1)[0]}.__init__" for qn in qualified_names if "." in qn}) # Get FunctionSource representation of helpers of helpers of FTO - helpers_of_helpers_dict, _helpers_of_helpers_list = get_function_sources_from_jedi( - helpers_of_fto_qualified_names_dict, project_root_path - ) + if call_graph is not None: + helpers_of_helpers_dict, _helpers_of_helpers_list = call_graph.get_callees(helpers_of_fto_qualified_names_dict) + else: + helpers_of_helpers_dict, _helpers_of_helpers_list = get_function_sources_from_jedi( + helpers_of_fto_qualified_names_dict, project_root_path + ) # Extract code context for optimization final_read_writable_code = extract_code_markdown_context_from_files( diff --git a/codeflash/optimization/function_optimizer.py b/codeflash/optimization/function_optimizer.py index e04e7626c..024e77c89 100644 --- a/codeflash/optimization/function_optimizer.py +++ b/codeflash/optimization/function_optimizer.py @@ -132,6 +132,7 @@ if TYPE_CHECKING: from argparse import Namespace + from codeflash.context.call_graph import CallGraph from codeflash.discovery.functions_to_optimize import FunctionToOptimize from codeflash.either import Result from codeflash.models.models import ( @@ -437,6 +438,7 @@ def __init__( total_benchmark_timings: dict[BenchmarkKey, int] | None = None, args: Namespace | None = None, replay_tests_dir: Path | None = None, + call_graph: CallGraph | None = None, ) -> None: self.project_root = test_cfg.project_root_path self.test_cfg = test_cfg @@ -479,6 +481,7 @@ def __init__( self.function_benchmark_timings = function_benchmark_timings if function_benchmark_timings else {} self.total_benchmark_timings = total_benchmark_timings if total_benchmark_timings else {} self.replay_tests_dir = replay_tests_dir if replay_tests_dir else None + self.call_graph = call_graph n_tests = get_effort_value(EffortKeys.N_GENERATED_TESTS, self.effort) self.executor = concurrent.futures.ThreadPoolExecutor( max_workers=n_tests + 3 if self.experiment_id is None else n_tests + 4 @@ -1523,7 +1526,7 @@ def replace_function_and_helpers_with_optimized_code( def get_code_optimization_context(self) -> Result[CodeOptimizationContext, str]: try: new_code_ctx = code_context_extractor.get_code_optimization_context( - self.function_to_optimize, self.project_root + self.function_to_optimize, self.project_root, call_graph=self.call_graph ) except ValueError as e: return Failure(str(e)) diff --git a/codeflash/optimization/optimizer.py b/codeflash/optimization/optimizer.py index b8f42010f..1ff956450 100644 --- a/codeflash/optimization/optimizer.py +++ b/codeflash/optimization/optimizer.py @@ -34,6 +34,7 @@ from codeflash.benchmarking.function_ranker import FunctionRanker from codeflash.code_utils.checkpoint import CodeflashRunCheckpoint + from codeflash.context.call_graph import CallGraph from codeflash.discovery.functions_to_optimize import FunctionToOptimize from codeflash.models.models import BenchmarkKey, FunctionCalledInTest from codeflash.optimization.function_optimizer import FunctionOptimizer @@ -205,6 +206,7 @@ def create_function_optimizer( total_benchmark_timings: dict[BenchmarkKey, float] | None = None, original_module_ast: ast.Module | None = None, original_module_path: Path | None = None, + call_graph: CallGraph | None = None, ) -> FunctionOptimizer | None: from codeflash.code_utils.static_analysis import get_first_top_level_function_or_method_ast from codeflash.optimization.function_optimizer import FunctionOptimizer @@ -243,6 +245,7 @@ def create_function_optimizer( function_benchmark_timings=function_specific_timings, total_benchmark_timings=total_benchmark_timings if function_specific_timings else None, replay_tests_dir=self.replay_tests_dir, + call_graph=call_graph, ) def prepare_module_for_optimization( @@ -510,6 +513,19 @@ def run(self) -> None: function_benchmark_timings, total_benchmark_timings = self.run_benchmarks( file_to_funcs_to_optimize, num_optimizable_functions ) + + # Create persistent call graph for Python runs to cache Jedi analysis across functions + call_graph: CallGraph | None = None + from codeflash.languages import is_python + + if is_python(): + from codeflash.context.call_graph import CallGraph + + try: + call_graph = CallGraph(self.args.project_root) + except Exception: + logger.debug("Failed to initialize CallGraph, falling back to per-function Jedi analysis") + optimizations_found: int = 0 self.test_cfg.concolic_test_root_dir = Path( tempfile.mkdtemp(dir=self.args.tests_root, prefix="codeflash_concolic_") @@ -557,6 +573,7 @@ def run(self) -> None: total_benchmark_timings=total_benchmark_timings, original_module_ast=original_module_ast, original_module_path=original_module_path, + call_graph=call_graph, ) if function_optimizer is None: continue @@ -615,6 +632,9 @@ def run(self) -> None: else: logger.warning("⚠️ Failed to send completion email. Status") finally: + if call_graph is not None: + call_graph.close() + if function_optimizer: function_optimizer.cleanup_generated_files() From b604bf0a0ec6a8d23f6a4609b60f2e351f211bd5 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Tue, 10 Feb 2026 04:57:45 -0500 Subject: [PATCH 004/100] test: add unit and caching tests for CallGraph Covers same-file calls, cross-file calls, class instantiation, nested function exclusion, module-level exclusion, site-packages exclusion, empty/syntax-error files, and cache persistence. --- tests/test_call_graph.py | 286 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 tests/test_call_graph.py diff --git a/tests/test_call_graph.py b/tests/test_call_graph.py new file mode 100644 index 000000000..945bf7bf2 --- /dev/null +++ b/tests/test_call_graph.py @@ -0,0 +1,286 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +import pytest + +if TYPE_CHECKING: + from pathlib import Path + +from codeflash.context.call_graph import CallGraph + + +@pytest.fixture +def project(tmp_path: Path) -> Path: + project_root = tmp_path / "project" + project_root.mkdir() + return project_root + + +@pytest.fixture +def db_path(tmp_path: Path) -> Path: + return tmp_path / "cache.db" + + +def write_file(project: Path, name: str, content: str) -> Path: + fp = project / name + fp.write_text(content, encoding="utf-8") + return fp + + +# --------------------------------------------------------------------------- +# Unit tests +# --------------------------------------------------------------------------- + + +def test_simple_function_call(project: Path, db_path: Path) -> None: + write_file( + project, + "mod.py", + """\ +def helper(): + return 1 + +def caller(): + return helper() +""", + ) + cg = CallGraph(project, db_path=db_path) + try: + _, result_list = cg.get_callees({project / "mod.py": {"caller"}}) + callee_qns = {fs.qualified_name for fs in result_list} + assert "helper" in callee_qns + finally: + cg.close() + + +def test_cross_file_call(project: Path, db_path: Path) -> None: + write_file( + project, + "utils.py", + """\ +def utility(): + return 42 +""", + ) + write_file( + project, + "main.py", + """\ +from utils import utility + +def caller(): + return utility() +""", + ) + cg = CallGraph(project, db_path=db_path) + try: + _, result_list = cg.get_callees({project / "main.py": {"caller"}}) + callee_qns = {fs.qualified_name for fs in result_list} + assert "utility" in callee_qns + # Should be in the utils.py file + callee_files = {fs.file_path.resolve() for fs in result_list if fs.qualified_name == "utility"} + assert (project / "utils.py").resolve() in callee_files + finally: + cg.close() + + +def test_class_instantiation(project: Path, db_path: Path) -> None: + write_file( + project, + "mod.py", + """\ +class MyClass: + def __init__(self): + pass + +def caller(): + obj = MyClass() + return obj +""", + ) + cg = CallGraph(project, db_path=db_path) + try: + _, result_list = cg.get_callees({project / "mod.py": {"caller"}}) + callee_types = {fs.definition_type for fs in result_list} + assert "class" in callee_types + finally: + cg.close() + + +def test_nested_function_excluded(project: Path, db_path: Path) -> None: + write_file( + project, + "mod.py", + """\ +def caller(): + def inner(): + return 1 + return inner() +""", + ) + cg = CallGraph(project, db_path=db_path) + try: + _, result_list = cg.get_callees({project / "mod.py": {"caller"}}) + assert len(result_list) == 0 + finally: + cg.close() + + +def test_module_level_not_tracked(project: Path, db_path: Path) -> None: + write_file( + project, + "mod.py", + """\ +def helper(): + return 1 + +x = helper() +""", + ) + cg = CallGraph(project, db_path=db_path) + try: + # Module level calls have no enclosing function, so no edges + _, result_list = cg.get_callees({project / "mod.py": {"helper"}}) + # helper itself doesn't call anything + assert len(result_list) == 0 + finally: + cg.close() + + +def test_site_packages_excluded(project: Path, db_path: Path) -> None: + write_file( + project, + "mod.py", + """\ +import os + +def caller(): + return os.path.join("a", "b") +""", + ) + cg = CallGraph(project, db_path=db_path) + try: + _, result_list = cg.get_callees({project / "mod.py": {"caller"}}) + # os.path.join is stdlib, should not appear + assert len(result_list) == 0 + finally: + cg.close() + + +def test_empty_file(project: Path, db_path: Path) -> None: + write_file(project, "mod.py", "") + cg = CallGraph(project, db_path=db_path) + try: + _, result_list = cg.get_callees({project / "mod.py": set()}) + assert len(result_list) == 0 + finally: + cg.close() + + +def test_syntax_error_file(project: Path, db_path: Path) -> None: + write_file(project, "mod.py", "def broken(\n") + cg = CallGraph(project, db_path=db_path) + try: + _, result_list = cg.get_callees({project / "mod.py": {"broken"}}) + assert len(result_list) == 0 + finally: + cg.close() + + +# --------------------------------------------------------------------------- +# Caching tests +# --------------------------------------------------------------------------- + + +def test_caching_no_reindex(project: Path, db_path: Path) -> None: + write_file( + project, + "mod.py", + """\ +def helper(): + return 1 + +def caller(): + return helper() +""", + ) + cg = CallGraph(project, db_path=db_path) + try: + cg.get_callees({project / "mod.py": {"caller"}}) + # Second call should use in-memory cache (hash unchanged) + resolved = str((project / "mod.py").resolve()) + assert resolved in cg.indexed_file_hashes + old_hash = cg.indexed_file_hashes[resolved] + cg.get_callees({project / "mod.py": {"caller"}}) + assert cg.indexed_file_hashes[resolved] == old_hash + finally: + cg.close() + + +def test_incremental_update_on_change(project: Path, db_path: Path) -> None: + fp = write_file( + project, + "mod.py", + """\ +def helper(): + return 1 + +def caller(): + return helper() +""", + ) + cg = CallGraph(project, db_path=db_path) + try: + _, result_list = cg.get_callees({project / "mod.py": {"caller"}}) + assert any(fs.qualified_name == "helper" for fs in result_list) + + # Modify the file — caller no longer calls helper + fp.write_text( + """\ +def helper(): + return 1 + +def new_helper(): + return 2 + +def caller(): + return new_helper() +""", + encoding="utf-8", + ) + _, result_list = cg.get_callees({project / "mod.py": {"caller"}}) + callee_qns = {fs.qualified_name for fs in result_list} + assert "new_helper" in callee_qns + finally: + cg.close() + + +def test_persistence_across_sessions(project: Path, db_path: Path) -> None: + write_file( + project, + "mod.py", + """\ +def helper(): + return 1 + +def caller(): + return helper() +""", + ) + # First session: index the file + cg1 = CallGraph(project, db_path=db_path) + try: + _, result_list = cg1.get_callees({project / "mod.py": {"caller"}}) + assert any(fs.qualified_name == "helper" for fs in result_list) + finally: + cg1.close() + + # Second session: should read from DB without re-indexing + cg2 = CallGraph(project, db_path=db_path) + try: + assert len(cg2.indexed_file_hashes) == 0 # in-memory cache is empty + _, result_list = cg2.get_callees({project / "mod.py": {"caller"}}) + assert any(fs.qualified_name == "helper" for fs in result_list) + finally: + cg2.close() From 5c4a65c183eccdee42b8a56071f61e09308c23ce Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Tue, 10 Feb 2026 05:27:59 -0500 Subject: [PATCH 005/100] feat: add Rich Live visualization for call graph indexing Replace the simple progress bar with a Live + Tree + Panel display that shows files being analyzed, call edges discovered, cache hits, and summary stats during call graph indexing. --- codeflash/cli_cmds/console.py | 84 +++++++++++++++++++++++++- codeflash/context/call_graph.py | 36 ++++++++--- codeflash/optimization/optimizer.py | 7 ++- tests/test_call_graph.py | 93 ++++++++++++++++++++++++++++- 4 files changed, 210 insertions(+), 10 deletions(-) diff --git a/codeflash/cli_cmds/console.py b/codeflash/cli_cmds/console.py index dab746c47..63c975a84 100644 --- a/codeflash/cli_cmds/console.py +++ b/codeflash/cli_cmds/console.py @@ -24,10 +24,11 @@ from codeflash.lsp.lsp_message import LspCodeMessage, LspTextMessage if TYPE_CHECKING: - from collections.abc import Generator + from collections.abc import Callable, Generator from rich.progress import TaskID + from codeflash.context.call_graph import IndexResult from codeflash.lsp.lsp_message import LspMessage DEBUG_MODE = logging.getLogger().getEffectiveLevel() == logging.DEBUG @@ -196,3 +197,84 @@ def test_files_progress_bar(total: int, description: str) -> Generator[tuple[Pro ) as progress: task_id = progress.add_task(description, total=total) yield progress, task_id + + +MAX_TREE_ENTRIES = 8 +MAX_EDGE_CHILDREN = 3 + + +@contextmanager +def call_graph_live_display(total: int) -> Generator[Callable[[IndexResult], None], None, None]: + from rich.console import Group + from rich.live import Live + from rich.panel import Panel + from rich.text import Text + from rich.tree import Tree + + if is_LSP_enabled(): + lsp_log(LspTextMessage(text="Building call graph", takes_time=True)) + yield lambda _result: None + return + + progress = Progress( + SpinnerColumn(next(spinners)), + TextColumn("[progress.description]{task.description}"), + BarColumn(complete_style="cyan", finished_style="green", pulse_style="yellow"), + MofNCompleteColumn(), + TimeElapsedColumn(), + TimeRemainingColumn(), + auto_refresh=False, + ) + task_id = progress.add_task("Analyzing files", total=total) + + results: list[IndexResult] = [] + stats_indexed = 0 + stats_cached = 0 + stats_edges = 0 + stats_errors = 0 + + def make_display() -> Panel: + tree = Tree("[bold]Call Graph[/bold]") + for result in results[-MAX_TREE_ENTRIES:]: + name = result.file_path.name + if result.error: + tree.add(f"[red]{name} (error)[/red]") + elif result.cached: + tree.add(f"[dim]{name} (cached)[/dim]") + else: + branch = tree.add(f"[cyan]{name}[/cyan] [dim]({result.num_edges} edges)[/dim]") + for caller, callee in result.edges[:MAX_EDGE_CHILDREN]: + branch.add(f"[dim]{caller} -> {callee}[/dim]") + remaining = len(result.edges) - MAX_EDGE_CHILDREN + if remaining > 0: + branch.add(f"[dim italic]...and {remaining} more[/dim italic]") + + parts: list[str] = [] + if stats_indexed: + parts.append(f"{stats_indexed} indexed") + if stats_cached: + parts.append(f"{stats_cached} cached") + if stats_errors: + parts.append(f"{stats_errors} errors") + parts.append(f"{stats_edges} edges") + stats_text = Text(" . ".join(parts), style="dim") + + return Panel( + Group(progress, Text(""), tree, Text(""), stats_text), title="Building Call Graph", border_style="cyan" + ) + + def update(result: IndexResult) -> None: + nonlocal stats_indexed, stats_cached, stats_edges, stats_errors + results.append(result) + if result.error: + stats_errors += 1 + elif result.cached: + stats_cached += 1 + else: + stats_indexed += 1 + stats_edges += result.num_edges + progress.advance(task_id) + live.update(make_display()) + + with Live(make_display(), console=console, transient=True, refresh_per_second=8) as live: + yield update diff --git a/codeflash/context/call_graph.py b/codeflash/context/call_graph.py index 15ff20119..7f2151203 100644 --- a/codeflash/context/call_graph.py +++ b/codeflash/context/call_graph.py @@ -4,6 +4,7 @@ import os import sqlite3 from collections import defaultdict +from dataclasses import dataclass from pathlib import Path from typing import TYPE_CHECKING @@ -12,9 +13,20 @@ from codeflash.models.models import FunctionSource if TYPE_CHECKING: + from collections.abc import Callable, Iterable + from jedi.api.classes import Name +@dataclass(frozen=True, slots=True) +class IndexResult: + file_path: Path + cached: bool + num_edges: int + edges: tuple[tuple[str, str], ...] # (caller_qn, callee_name) pairs + error: bool + + class CallGraph: SCHEMA_VERSION = 1 @@ -117,17 +129,17 @@ def get_callees( return file_path_to_function_source, function_source_list - def ensure_file_indexed(self, file_path: Path) -> None: + def ensure_file_indexed(self, file_path: Path) -> IndexResult: resolved = str(file_path.resolve()) try: content = file_path.read_text(encoding="utf-8") except Exception: - return + return IndexResult(file_path=file_path, cached=False, num_edges=0, edges=(), error=True) file_hash = hashlib.sha256(content.encode("utf-8")).hexdigest() cached_hash = self.indexed_file_hashes.get(resolved) if cached_hash == file_hash: - return + return IndexResult(file_path=file_path, cached=True, num_edges=0, edges=(), error=False) # Check DB for stored hash row = self.conn.execute( @@ -136,11 +148,11 @@ def ensure_file_indexed(self, file_path: Path) -> None: ).fetchone() if row and row[0] == file_hash: self.indexed_file_hashes[resolved] = file_hash - return + return IndexResult(file_path=file_path, cached=True, num_edges=0, edges=(), error=False) - self.index_file(file_path, file_hash) + return self.index_file(file_path, file_hash) - def index_file(self, file_path: Path, file_hash: str) -> None: + def index_file(self, file_path: Path, file_hash: str) -> IndexResult: import jedi resolved = str(file_path.resolve()) @@ -165,7 +177,7 @@ def index_file(self, file_path: Path, file_hash: str) -> None: ) self.conn.commit() self.indexed_file_hashes[resolved] = file_hash - return + return IndexResult(file_path=file_path, cached=False, num_edges=0, edges=(), error=True) edges: set[tuple[str, str, str, str, str, str, str, str]] = set() @@ -237,6 +249,9 @@ def index_file(self, file_path: Path, file_hash: str) -> None: self.conn.commit() self.indexed_file_hashes[resolved] = file_hash + edges_summary = tuple((caller_qn, callee_name) for (_, caller_qn, _, _, _, callee_name, _, _) in edges) + return IndexResult(file_path=file_path, cached=False, num_edges=len(edges), edges=edges_summary, error=False) + def _resolve_definitions(self, ref: Name) -> list[Name]: try: inferred = ref.infer() @@ -291,5 +306,12 @@ def _get_enclosing_function_qualified_name(self, ref: Name) -> str | None: except (ValueError, AttributeError): return None + def build_index(self, file_paths: Iterable[Path], on_progress: Callable[[IndexResult], None] | None = None) -> None: + """Pre-index a batch of files. Calls on_progress(result) after each file.""" + for file_path in file_paths: + result = self.ensure_file_indexed(file_path) + if on_progress is not None: + on_progress(result) + def close(self) -> None: self.conn.close() diff --git a/codeflash/optimization/optimizer.py b/codeflash/optimization/optimizer.py index 1ff956450..2373dce31 100644 --- a/codeflash/optimization/optimizer.py +++ b/codeflash/optimization/optimizer.py @@ -11,7 +11,7 @@ from codeflash.api.aiservice import AiServiceClient, LocalAiServiceClient from codeflash.api.cfapi import send_completion_email -from codeflash.cli_cmds.console import console, logger, progress_bar +from codeflash.cli_cmds.console import call_graph_live_display, console, logger, progress_bar from codeflash.code_utils import env_utils from codeflash.code_utils.code_utils import cleanup_paths, get_run_tmp_file from codeflash.code_utils.env_utils import get_pr_number, is_pr_draft @@ -526,6 +526,11 @@ def run(self) -> None: except Exception: logger.debug("Failed to initialize CallGraph, falling back to per-function Jedi analysis") + if call_graph is not None and file_to_funcs_to_optimize: + source_files = list(file_to_funcs_to_optimize.keys()) + with call_graph_live_display(len(source_files)) as on_progress: + call_graph.build_index(source_files, on_progress=on_progress) + optimizations_found: int = 0 self.test_cfg.concolic_test_root_dir = Path( tempfile.mkdtemp(dir=self.args.tests_root, prefix="codeflash_concolic_") diff --git a/tests/test_call_graph.py b/tests/test_call_graph.py index 945bf7bf2..46b5f1135 100644 --- a/tests/test_call_graph.py +++ b/tests/test_call_graph.py @@ -7,7 +7,7 @@ if TYPE_CHECKING: from pathlib import Path -from codeflash.context.call_graph import CallGraph +from codeflash.context.call_graph import CallGraph, IndexResult @pytest.fixture @@ -284,3 +284,94 @@ def caller(): assert any(fs.qualified_name == "helper" for fs in result_list) finally: cg2.close() + + +def test_build_index_with_progress(project: Path, db_path: Path) -> None: + write_file( + project, + "a.py", + """\ +def helper_a(): + return 1 + +def caller_a(): + return helper_a() +""", + ) + write_file( + project, + "b.py", + """\ +from a import helper_a + +def caller_b(): + return helper_a() +""", + ) + + cg = CallGraph(project, db_path=db_path) + try: + progress_calls: list[IndexResult] = [] + files = [project / "a.py", project / "b.py"] + cg.build_index(files, on_progress=progress_calls.append) + + # Callback fired once per file + assert len(progress_calls) == 2 + + # Verify IndexResult fields for freshly indexed files + for result in progress_calls: + assert isinstance(result, IndexResult) + assert not result.error + assert not result.cached + assert result.num_edges > 0 + assert len(result.edges) == result.num_edges + + # Files are now indexed — get_callees should return correct results + _, result_list = cg.get_callees({project / "a.py": {"caller_a"}}) + callee_qns = {fs.qualified_name for fs in result_list} + assert "helper_a" in callee_qns + finally: + cg.close() + + +def test_build_index_cached_results(project: Path, db_path: Path) -> None: + write_file( + project, + "a.py", + """\ +def helper_a(): + return 1 + +def caller_a(): + return helper_a() +""", + ) + write_file( + project, + "b.py", + """\ +from a import helper_a + +def caller_b(): + return helper_a() +""", + ) + + cg = CallGraph(project, db_path=db_path) + try: + files = [project / "a.py", project / "b.py"] + # First pass — fresh indexing + cg.build_index(files) + + # Second pass — should all be cached + cached_results: list[IndexResult] = [] + cg.build_index(files, on_progress=cached_results.append) + + assert len(cached_results) == 2 + for result in cached_results: + assert result.cached + assert not result.error + assert result.num_edges == 0 + assert result.edges == () + finally: + cg.close() From 0c1397e8140185fed294e080a0be6039e282ff69 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Tue, 10 Feb 2026 06:12:32 -0500 Subject: [PATCH 006/100] feat: enrich call graph display with cross-file tracking and dependency summary Add cross-file edge detection to IndexResult, replace tree sub-entries with flat per-file dependency labels using plain language, and add a post-indexing summary panel showing per-function dependency stats. --- codeflash/cli_cmds/console.py | 74 +++++++++++++++++++++++------ codeflash/context/call_graph.py | 26 +++++++--- codeflash/optimization/optimizer.py | 4 +- tests/test_call_graph.py | 63 ++++++++++++++++++++++++ 4 files changed, 145 insertions(+), 22 deletions(-) diff --git a/codeflash/cli_cmds/console.py b/codeflash/cli_cmds/console.py index 63c975a84..6a5ae7997 100644 --- a/codeflash/cli_cmds/console.py +++ b/codeflash/cli_cmds/console.py @@ -25,10 +25,12 @@ if TYPE_CHECKING: from collections.abc import Callable, Generator + from pathlib import Path from rich.progress import TaskID - from codeflash.context.call_graph import IndexResult + from codeflash.context.call_graph import CallGraph, IndexResult + from codeflash.discovery.functions_to_optimize import FunctionToOptimize from codeflash.lsp.lsp_message import LspMessage DEBUG_MODE = logging.getLogger().getEffectiveLevel() == logging.DEBUG @@ -200,7 +202,6 @@ def test_files_progress_bar(total: int, description: str) -> Generator[tuple[Pro MAX_TREE_ENTRIES = 8 -MAX_EDGE_CHILDREN = 3 @contextmanager @@ -231,10 +232,11 @@ def call_graph_live_display(total: int) -> Generator[Callable[[IndexResult], Non stats_indexed = 0 stats_cached = 0 stats_edges = 0 + stats_external = 0 stats_errors = 0 def make_display() -> Panel: - tree = Tree("[bold]Call Graph[/bold]") + tree = Tree("[bold]Dependencies[/bold]") for result in results[-MAX_TREE_ENTRIES:]: name = result.file_path.name if result.error: @@ -242,29 +244,35 @@ def make_display() -> Panel: elif result.cached: tree.add(f"[dim]{name} (cached)[/dim]") else: - branch = tree.add(f"[cyan]{name}[/cyan] [dim]({result.num_edges} edges)[/dim]") - for caller, callee in result.edges[:MAX_EDGE_CHILDREN]: - branch.add(f"[dim]{caller} -> {callee}[/dim]") - remaining = len(result.edges) - MAX_EDGE_CHILDREN - if remaining > 0: - branch.add(f"[dim italic]...and {remaining} more[/dim italic]") + local = result.num_edges - result.cross_file_edges + parts = [] + if local: + parts.append(f"{local} in same file") + if result.cross_file_edges: + parts.append(f"{result.cross_file_edges} from other modules") + label = ", ".join(parts) if parts else "no dependencies" + tree.add(f"[cyan]{name}[/cyan] [dim]{label}[/dim]") parts: list[str] = [] if stats_indexed: - parts.append(f"{stats_indexed} indexed") + parts.append(f"{stats_indexed} files analyzed") if stats_cached: parts.append(f"{stats_cached} cached") if stats_errors: parts.append(f"{stats_errors} errors") - parts.append(f"{stats_edges} edges") - stats_text = Text(" . ".join(parts), style="dim") + parts.append(f"{stats_edges} dependencies found") + if stats_external: + parts.append(f"{stats_external} from other modules") + stats_text = Text(" · ".join(parts), style="dim") return Panel( - Group(progress, Text(""), tree, Text(""), stats_text), title="Building Call Graph", border_style="cyan" + Group(progress, Text(""), tree, Text(""), stats_text), + title="Building Call Graph", + border_style="cyan", ) def update(result: IndexResult) -> None: - nonlocal stats_indexed, stats_cached, stats_edges, stats_errors + nonlocal stats_indexed, stats_cached, stats_edges, stats_external, stats_errors results.append(result) if result.error: stats_errors += 1 @@ -273,8 +281,46 @@ def update(result: IndexResult) -> None: else: stats_indexed += 1 stats_edges += result.num_edges + stats_external += result.cross_file_edges progress.advance(task_id) live.update(make_display()) with Live(make_display(), console=console, transient=True, refresh_per_second=8) as live: yield update + + +def call_graph_summary(call_graph: CallGraph, file_to_funcs: dict[Path, list[FunctionToOptimize]]) -> None: + from rich.panel import Panel + + total_functions = sum(len(funcs) for funcs in file_to_funcs.values()) + if total_functions == 0: + return + + total_callees = 0 + with_context = 0 + leaf_functions = 0 + + for file_path, funcs in file_to_funcs.items(): + for func in funcs: + _, func_callees = call_graph.get_callees({file_path: {func.qualified_name}}) + count = len(func_callees) + total_callees += count + if count > 0: + with_context += 1 + else: + leaf_functions += 1 + + avg_callees = total_callees / total_functions if total_functions > 0 else 0 + + summary = ( + f"{total_functions} functions ready for optimization · " + f"avg {avg_callees:.1f} dependencies/function\n" + f"{with_context} call other functions · " + f"{leaf_functions} are self-contained" + ) + + if is_LSP_enabled(): + lsp_log(LspTextMessage(text=summary)) + return + + console.print(Panel(summary, title="Dependency Summary", border_style="cyan")) diff --git a/codeflash/context/call_graph.py b/codeflash/context/call_graph.py index 7f2151203..3bd078992 100644 --- a/codeflash/context/call_graph.py +++ b/codeflash/context/call_graph.py @@ -23,7 +23,8 @@ class IndexResult: file_path: Path cached: bool num_edges: int - edges: tuple[tuple[str, str], ...] # (caller_qn, callee_name) pairs + edges: tuple[tuple[str, str, bool], ...] # (caller_qn, callee_name, is_cross_file) + cross_file_edges: int error: bool @@ -134,12 +135,12 @@ def ensure_file_indexed(self, file_path: Path) -> IndexResult: try: content = file_path.read_text(encoding="utf-8") except Exception: - return IndexResult(file_path=file_path, cached=False, num_edges=0, edges=(), error=True) + return IndexResult(file_path=file_path, cached=False, num_edges=0, edges=(), cross_file_edges=0, error=True) file_hash = hashlib.sha256(content.encode("utf-8")).hexdigest() cached_hash = self.indexed_file_hashes.get(resolved) if cached_hash == file_hash: - return IndexResult(file_path=file_path, cached=True, num_edges=0, edges=(), error=False) + return IndexResult(file_path=file_path, cached=True, num_edges=0, edges=(), cross_file_edges=0, error=False) # Check DB for stored hash row = self.conn.execute( @@ -148,7 +149,7 @@ def ensure_file_indexed(self, file_path: Path) -> IndexResult: ).fetchone() if row and row[0] == file_hash: self.indexed_file_hashes[resolved] = file_hash - return IndexResult(file_path=file_path, cached=True, num_edges=0, edges=(), error=False) + return IndexResult(file_path=file_path, cached=True, num_edges=0, edges=(), cross_file_edges=0, error=False) return self.index_file(file_path, file_hash) @@ -177,7 +178,7 @@ def index_file(self, file_path: Path, file_hash: str) -> IndexResult: ) self.conn.commit() self.indexed_file_hashes[resolved] = file_hash - return IndexResult(file_path=file_path, cached=False, num_edges=0, edges=(), error=True) + return IndexResult(file_path=file_path, cached=False, num_edges=0, edges=(), cross_file_edges=0, error=True) edges: set[tuple[str, str, str, str, str, str, str, str]] = set() @@ -249,8 +250,19 @@ def index_file(self, file_path: Path, file_hash: str) -> IndexResult: self.conn.commit() self.indexed_file_hashes[resolved] = file_hash - edges_summary = tuple((caller_qn, callee_name) for (_, caller_qn, _, _, _, callee_name, _, _) in edges) - return IndexResult(file_path=file_path, cached=False, num_edges=len(edges), edges=edges_summary, error=False) + edges_summary = tuple( + (caller_qn, callee_name, caller_file != callee_file) + for (caller_file, caller_qn, callee_file, _, _, callee_name, _, _) in edges + ) + cross_file_count = sum(1 for e in edges_summary if e[2]) + return IndexResult( + file_path=file_path, + cached=False, + num_edges=len(edges), + edges=edges_summary, + cross_file_edges=cross_file_count, + error=False, + ) def _resolve_definitions(self, ref: Name) -> list[Name]: try: diff --git a/codeflash/optimization/optimizer.py b/codeflash/optimization/optimizer.py index 2373dce31..80f4e7ce0 100644 --- a/codeflash/optimization/optimizer.py +++ b/codeflash/optimization/optimizer.py @@ -11,7 +11,7 @@ from codeflash.api.aiservice import AiServiceClient, LocalAiServiceClient from codeflash.api.cfapi import send_completion_email -from codeflash.cli_cmds.console import call_graph_live_display, console, logger, progress_bar +from codeflash.cli_cmds.console import call_graph_live_display, call_graph_summary, console, logger, progress_bar from codeflash.code_utils import env_utils from codeflash.code_utils.code_utils import cleanup_paths, get_run_tmp_file from codeflash.code_utils.env_utils import get_pr_number, is_pr_draft @@ -530,6 +530,8 @@ def run(self) -> None: source_files = list(file_to_funcs_to_optimize.keys()) with call_graph_live_display(len(source_files)) as on_progress: call_graph.build_index(source_files, on_progress=on_progress) + call_graph_summary(call_graph, file_to_funcs_to_optimize) + raise SystemExit optimizations_found: int = 0 self.test_cfg.concolic_test_root_dir = Path( diff --git a/tests/test_call_graph.py b/tests/test_call_graph.py index 46b5f1135..a2918434a 100644 --- a/tests/test_call_graph.py +++ b/tests/test_call_graph.py @@ -325,6 +325,7 @@ def caller_b(): assert not result.cached assert result.num_edges > 0 assert len(result.edges) == result.num_edges + assert result.cross_file_edges >= 0 # Files are now indexed — get_callees should return correct results _, result_list = cg.get_callees({project / "a.py": {"caller_a"}}) @@ -373,5 +374,67 @@ def caller_b(): assert not result.error assert result.num_edges == 0 assert result.edges == () + assert result.cross_file_edges == 0 + finally: + cg.close() + + +def test_cross_file_edges_tracked(project: Path, db_path: Path) -> None: + write_file( + project, + "utils.py", + """\ +def utility(): + return 42 +""", + ) + write_file( + project, + "main.py", + """\ +from utils import utility + +def caller(): + return utility() +""", + ) + + cg = CallGraph(project, db_path=db_path) + try: + progress_calls: list[IndexResult] = [] + cg.build_index([project / "utils.py", project / "main.py"], on_progress=progress_calls.append) + + # main.py should have cross-file edges (calls into utils.py) + main_result = next(r for r in progress_calls if r.file_path.name == "main.py") + assert main_result.cross_file_edges > 0 + # At least one edge tuple should have is_cross_file=True + assert any(is_cross_file for _, _, is_cross_file in main_result.edges) + finally: + cg.close() + + +def test_same_file_edges_not_cross_file(project: Path, db_path: Path) -> None: + write_file( + project, + "mod.py", + """\ +def helper(): + return 1 + +def caller(): + return helper() +""", + ) + + cg = CallGraph(project, db_path=db_path) + try: + progress_calls: list[IndexResult] = [] + cg.build_index([project / "mod.py"], on_progress=progress_calls.append) + + assert len(progress_calls) == 1 + result = progress_calls[0] + assert result.cross_file_edges == 0 + # All edges should have is_cross_file=False + assert all(not is_cross_file for _, _, is_cross_file in result.edges) finally: cg.close() From 92be009f29b806643ccfb2da951a2b2472d80327 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Tue, 10 Feb 2026 06:16:48 -0500 Subject: [PATCH 007/100] feat: rank functions by dependency count when no trace file is available Use the call graph to sort functions by callee count (most dependencies first) in --all mode without benchmarks, replacing arbitrary ordering. --- codeflash/cli_cmds/console.py | 4 +--- codeflash/optimization/optimizer.py | 25 +++++++++++++++++++++---- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/codeflash/cli_cmds/console.py b/codeflash/cli_cmds/console.py index 6a5ae7997..3ab6a9619 100644 --- a/codeflash/cli_cmds/console.py +++ b/codeflash/cli_cmds/console.py @@ -266,9 +266,7 @@ def make_display() -> Panel: stats_text = Text(" · ".join(parts), style="dim") return Panel( - Group(progress, Text(""), tree, Text(""), stats_text), - title="Building Call Graph", - border_style="cyan", + Group(progress, Text(""), tree, Text(""), stats_text), title="Building Call Graph", border_style="cyan" ) def update(result: IndexResult) -> None: diff --git a/codeflash/optimization/optimizer.py b/codeflash/optimization/optimizer.py index 80f4e7ce0..a8e9de02c 100644 --- a/codeflash/optimization/optimizer.py +++ b/codeflash/optimization/optimizer.py @@ -389,7 +389,10 @@ def display_global_ranking( console.print(f"[dim]... and {len(globally_ranked) - display_count} more functions[/dim]") def rank_all_functions_globally( - self, file_to_funcs_to_optimize: dict[Path, list[FunctionToOptimize]], trace_file_path: Path | None + self, + file_to_funcs_to_optimize: dict[Path, list[FunctionToOptimize]], + trace_file_path: Path | None, + call_graph: CallGraph | None = None, ) -> list[tuple[Path, FunctionToOptimize]]: """Rank all functions globally across all files based on trace data. @@ -409,8 +412,10 @@ def rank_all_functions_globally( for file_path, functions in file_to_funcs_to_optimize.items(): all_functions.extend((file_path, func) for func in functions) - # If no trace file, return in original order + # If no trace file, rank by dependency count if call graph is available if not trace_file_path or not trace_file_path.exists(): + if call_graph is not None: + return self.rank_by_dependency_count(all_functions, call_graph) logger.debug("No trace file available, using original function order") return all_functions @@ -461,6 +466,17 @@ def rank_all_functions_globally( else: return globally_ranked + def rank_by_dependency_count( + self, all_functions: list[tuple[Path, FunctionToOptimize]], call_graph: CallGraph + ) -> list[tuple[Path, FunctionToOptimize]]: + counts: list[tuple[int, int, tuple[Path, FunctionToOptimize]]] = [] + for idx, (file_path, func) in enumerate(all_functions): + _, callee_list = call_graph.get_callees({file_path: {func.qualified_name}}) + counts.append((len(callee_list), idx, (file_path, func))) + counts.sort(key=lambda x: (-x[0], x[1])) + logger.debug(f"Ranked {len(counts)} functions by dependency count (most complex first)") + return [item for _, _, item in counts] + def run(self) -> None: from codeflash.code_utils.checkpoint import CodeflashRunCheckpoint @@ -531,7 +547,6 @@ def run(self) -> None: with call_graph_live_display(len(source_files)) as on_progress: call_graph.build_index(source_files, on_progress=on_progress) call_graph_summary(call_graph, file_to_funcs_to_optimize) - raise SystemExit optimizations_found: int = 0 self.test_cfg.concolic_test_root_dir = Path( @@ -548,7 +563,9 @@ def run(self) -> None: self.functions_checkpoint = CodeflashRunCheckpoint(self.args.module_root) # GLOBAL RANKING: Rank all functions together before optimizing - globally_ranked_functions = self.rank_all_functions_globally(file_to_funcs_to_optimize, trace_file_path) + globally_ranked_functions = self.rank_all_functions_globally( + file_to_funcs_to_optimize, trace_file_path, call_graph=call_graph + ) # Cache for module preparation (avoid re-parsing same files) prepared_modules: dict[Path, tuple[dict[Path, ValidCode], ast.Module | None]] = {} From 7d5638df0cc4bf3b8c7246e1aeec9c5487b1e899 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Tue, 10 Feb 2026 06:51:58 -0500 Subject: [PATCH 008/100] feat: parallelize call graph indexing with ProcessPoolExecutor Separate Jedi analysis (CPU-bound) from DB persistence so uncached files can be analyzed across multiple worker processes. Files are dispatched to a pool of up to 8 workers when >= 8 need indexing, with sequential fallback for small batches or on pool failure. --- codeflash/context/call_graph.py | 446 ++++++++++++++++++++++---------- 1 file changed, 308 insertions(+), 138 deletions(-) diff --git a/codeflash/context/call_graph.py b/codeflash/context/call_graph.py index 3bd078992..033f8399a 100644 --- a/codeflash/context/call_graph.py +++ b/codeflash/context/call_graph.py @@ -28,6 +28,166 @@ class IndexResult: error: bool +# --------------------------------------------------------------------------- +# Module-level helpers (must be top-level for ProcessPoolExecutor pickling) +# --------------------------------------------------------------------------- + +_PARALLEL_THRESHOLD = 8 + +# Per-worker state, initialised by _init_index_worker in child processes +_worker_jedi_project: object | None = None +_worker_project_root_str: str | None = None + + +def _init_index_worker(project_root: str) -> None: + import jedi + + global _worker_jedi_project, _worker_project_root_str + _worker_jedi_project = jedi.Project(path=project_root) + _worker_project_root_str = project_root + + +def _resolve_definitions(ref: Name) -> list[Name]: + try: + inferred = ref.infer() + valid = [d for d in inferred if d.type in ("function", "class")] + if valid: + return valid + except Exception: + pass + + try: + return ref.goto(follow_imports=True, follow_builtin_imports=False) + except Exception: + return [] + + +def _is_valid_definition(definition: Name, caller_qualified_name: str, project_root_str: str) -> bool: + definition_path = definition.module_path + if definition_path is None: + return False + + if not str(definition_path).startswith(project_root_str + os.sep): + return False + + if path_belongs_to_site_packages(definition_path): + return False + + if not definition.full_name or not definition.full_name.startswith(definition.module_name): + return False + + if definition.type not in ("function", "class"): + return False + + try: + def_qn = get_qualified_name(definition.module_name, definition.full_name) + if def_qn == caller_qualified_name: + return False + except ValueError: + return False + + try: + from codeflash.optimization.function_context import belongs_to_function_qualified + + if belongs_to_function_qualified(definition, caller_qualified_name): + return False + except Exception: + pass + + return True + + +def _get_enclosing_function_qn(ref: Name) -> str | None: + try: + parent = ref.parent() + if parent is None or parent.type != "function": + return None + if not parent.full_name or not parent.full_name.startswith(parent.module_name): + return None + return get_qualified_name(parent.module_name, parent.full_name) + except (ValueError, AttributeError): + return None + + +def _analyze_file(file_path: Path, jedi_project: object, project_root_str: str) -> tuple[set[tuple[str, ...]], bool]: + """Pure Jedi analysis — no DB access. Returns (edges, had_error).""" + import jedi + + resolved = str(file_path.resolve()) + + try: + script = jedi.Script(path=file_path, project=jedi_project) + refs = script.get_names(all_scopes=True, definitions=False, references=True) + except Exception: + return set(), True + + edges: set[tuple[str, str, str, str, str, str, str, str]] = set() + + for ref in refs: + try: + caller_qn = _get_enclosing_function_qn(ref) + if caller_qn is None: + continue + + definitions = _resolve_definitions(ref) + if not definitions: + continue + + definition = definitions[0] + definition_path = definition.module_path + if definition_path is None: + continue + + if not _is_valid_definition(definition, caller_qn, project_root_str): + continue + + # Extract common edge components + edge_base = (resolved, caller_qn, str(definition_path)) + + if definition.type == "function": + callee_qn = get_qualified_name(definition.module_name, definition.full_name) + if len(callee_qn.split(".")) > 2: + continue + edges.add( + ( + *edge_base, + callee_qn, + definition.full_name, + definition.name, + definition.type, + definition.get_line_code(), + ) + ) + elif definition.type == "class": + init_qn = get_qualified_name(definition.module_name, f"{definition.full_name}.__init__") + if len(init_qn.split(".")) > 2: + continue + edges.add( + ( + *edge_base, + init_qn, + f"{definition.full_name}.__init__", + "__init__", + definition.type, + definition.get_line_code(), + ) + ) + except Exception: + continue + + return edges, False + + +def _index_file_worker(args: tuple[str, str]) -> tuple[str, str, set[tuple[str, ...]], bool]: + """Worker entry point for ProcessPoolExecutor.""" + file_path_str, file_hash = args + edges, had_error = _analyze_file(Path(file_path_str), _worker_jedi_project, _worker_project_root_str) + return file_path_str, file_hash, edges, had_error + + +# --------------------------------------------------------------------------- + + class CallGraph: SCHEMA_VERSION = 1 @@ -96,16 +256,17 @@ def get_callees( file_path_to_function_source: dict[Path, set[FunctionSource]] = defaultdict(set) function_source_list: list[FunctionSource] = [] + # Build list of all caller keys all_caller_keys: list[tuple[str, str]] = [] for file_path, qualified_names in file_path_to_qualified_names.items(): self.ensure_file_indexed(file_path) - fp_str = str(file_path.resolve()) - for qn in qualified_names: - all_caller_keys.append((fp_str, qn)) + resolved = str(file_path.resolve()) + all_caller_keys.extend((resolved, qn) for qn in qualified_names) if not all_caller_keys: return file_path_to_function_source, function_source_list + # Query all callees cur = self.conn.cursor() for caller_file, caller_qn in all_caller_keys: rows = cur.execute( @@ -115,6 +276,7 @@ def get_callees( WHERE project_root = ? AND caller_file = ? AND caller_qualified_name = ?""", (self.project_root_str, caller_file, caller_qn), ).fetchall() + for callee_file, callee_qn, callee_fqn, callee_name, callee_type, callee_src in rows: callee_path = Path(callee_file) fs = FunctionSource( @@ -132,14 +294,16 @@ def get_callees( def ensure_file_indexed(self, file_path: Path) -> IndexResult: resolved = str(file_path.resolve()) + try: content = file_path.read_text(encoding="utf-8") except Exception: return IndexResult(file_path=file_path, cached=False, num_edges=0, edges=(), cross_file_edges=0, error=True) + file_hash = hashlib.sha256(content.encode("utf-8")).hexdigest() - cached_hash = self.indexed_file_hashes.get(resolved) - if cached_hash == file_hash: + # Check in-memory cache first + if self.indexed_file_hashes.get(resolved) == file_hash: return IndexResult(file_path=file_path, cached=True, num_edges=0, edges=(), cross_file_edges=0, error=False) # Check DB for stored hash @@ -147,6 +311,7 @@ def ensure_file_indexed(self, file_path: Path) -> IndexResult: "SELECT file_hash FROM cg_indexed_files WHERE project_root = ? AND file_path = ?", (self.project_root_str, resolved), ).fetchone() + if row and row[0] == file_hash: self.indexed_file_hashes[resolved] = file_hash return IndexResult(file_path=file_path, cached=True, num_edges=0, edges=(), cross_file_edges=0, error=False) @@ -154,12 +319,18 @@ def ensure_file_indexed(self, file_path: Path) -> IndexResult: return self.index_file(file_path, file_hash) def index_file(self, file_path: Path, file_hash: str) -> IndexResult: - import jedi - resolved = str(file_path.resolve()) + edges, had_error = _analyze_file(file_path, self.jedi_project, self.project_root_str) + if had_error: + logger.debug(f"CallGraph: failed to parse {file_path}") + return self._persist_edges(file_path, resolved, file_hash, edges, had_error) - # Delete stale data for this file + def _persist_edges( + self, file_path: Path, resolved: str, file_hash: str, edges: set[tuple[str, ...]], had_error: bool + ) -> IndexResult: cur = self.conn.cursor() + + # Clear existing data for this file cur.execute( "DELETE FROM cg_call_edges WHERE project_root = ? AND caller_file = ?", (self.project_root_str, resolved) ) @@ -167,163 +338,162 @@ def index_file(self, file_path: Path, file_hash: str) -> IndexResult: "DELETE FROM cg_indexed_files WHERE project_root = ? AND file_path = ?", (self.project_root_str, resolved) ) - try: - script = jedi.Script(path=file_path, project=self.jedi_project) - refs = script.get_names(all_scopes=True, definitions=False, references=True) - except Exception: - logger.debug(f"CallGraph: failed to parse {file_path}") - cur.execute( - "INSERT OR REPLACE INTO cg_indexed_files (project_root, file_path, file_hash) VALUES (?, ?, ?)", - (self.project_root_str, resolved, file_hash), + # Insert new edges if parsing succeeded + if not had_error and edges: + cur.executemany( + """INSERT OR REPLACE INTO cg_call_edges + (project_root, caller_file, caller_qualified_name, + callee_file, callee_qualified_name, callee_fully_qualified_name, + callee_only_function_name, callee_definition_type, callee_source_line) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""", + [(self.project_root_str, *edge) for edge in edges], ) - self.conn.commit() - self.indexed_file_hashes[resolved] = file_hash - return IndexResult(file_path=file_path, cached=False, num_edges=0, edges=(), cross_file_edges=0, error=True) - edges: set[tuple[str, str, str, str, str, str, str, str]] = set() - - for ref in refs: - try: - caller_qn = self._get_enclosing_function_qualified_name(ref) - if caller_qn is None: - continue - - definitions = self._resolve_definitions(ref) - if not definitions: - continue - - definition = definitions[0] - definition_path = definition.module_path - if definition_path is None: - continue - - if not self._is_valid_definition(definition, caller_qn): - continue - - if definition.type == "function": - callee_qn = get_qualified_name(definition.module_name, definition.full_name) - if len(callee_qn.split(".")) > 2: - continue - edges.add( - ( - resolved, - caller_qn, - str(definition_path), - callee_qn, - definition.full_name, - definition.name, - definition.type, - definition.get_line_code(), - ) - ) - elif definition.type == "class": - init_qn = get_qualified_name(definition.module_name, f"{definition.full_name}.__init__") - if len(init_qn.split(".")) > 2: - continue - edges.add( - ( - resolved, - caller_qn, - str(definition_path), - init_qn, - f"{definition.full_name}.__init__", - "__init__", - definition.type, - definition.get_line_code(), - ) - ) - except Exception: - continue - - cur.executemany( - """INSERT OR REPLACE INTO cg_call_edges - (project_root, caller_file, caller_qualified_name, - callee_file, callee_qualified_name, callee_fully_qualified_name, - callee_only_function_name, callee_definition_type, callee_source_line) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""", - [(self.project_root_str, *edge) for edge in edges], - ) + # Record that this file has been indexed cur.execute( "INSERT OR REPLACE INTO cg_indexed_files (project_root, file_path, file_hash) VALUES (?, ?, ?)", (self.project_root_str, resolved, file_hash), ) + self.conn.commit() self.indexed_file_hashes[resolved] = file_hash + # Build summary for return value edges_summary = tuple( (caller_qn, callee_name, caller_file != callee_file) for (caller_file, caller_qn, callee_file, _, _, callee_name, _, _) in edges ) - cross_file_count = sum(1 for e in edges_summary if e[2]) + cross_file_count = sum(is_cross_file for _, _, is_cross_file in edges_summary) + return IndexResult( file_path=file_path, cached=False, num_edges=len(edges), edges=edges_summary, cross_file_edges=cross_file_count, - error=False, + error=had_error, ) - def _resolve_definitions(self, ref: Name) -> list[Name]: - try: - inferred = ref.infer() - valid = [d for d in inferred if d.type in ("function", "class")] - if valid: - return valid - except Exception: - pass + def build_index(self, file_paths: Iterable[Path], on_progress: Callable[[IndexResult], None] | None = None) -> None: + """Pre-index a batch of files, using multiprocessing for large uncached batches.""" + to_index: list[tuple[Path, str, str]] = [] - try: - return ref.goto(follow_imports=True, follow_builtin_imports=False) - except Exception: - return [] + for file_path in file_paths: + resolved = str(file_path.resolve()) - def _is_valid_definition(self, definition: Name, caller_qualified_name: str) -> bool: - definition_path = definition.module_path - if definition_path is None: - return False - if not str(definition_path).startswith(self.project_root_str + os.sep): - return False - if path_belongs_to_site_packages(definition_path): - return False - if not definition.full_name or not definition.full_name.startswith(definition.module_name): - return False - if definition.type not in ("function", "class"): - return False - # No self-edges - try: - def_qn = get_qualified_name(definition.module_name, definition.full_name) - if def_qn == caller_qualified_name: - return False - except ValueError: - return False - # Not an inner function of the caller - try: - from codeflash.optimization.function_context import belongs_to_function_qualified + try: + content = file_path.read_text(encoding="utf-8") + except Exception: + self._report_progress( + on_progress, + IndexResult( + file_path=file_path, cached=False, num_edges=0, edges=(), cross_file_edges=0, error=True + ), + ) + continue - if belongs_to_function_qualified(definition, caller_qualified_name): - return False - except Exception: - pass - return True + file_hash = hashlib.sha256(content.encode("utf-8")).hexdigest() + + # Check if already cached (in-memory or DB) + if self._is_file_cached(resolved, file_hash): + self._report_progress( + on_progress, + IndexResult( + file_path=file_path, cached=True, num_edges=0, edges=(), cross_file_edges=0, error=False + ), + ) + continue + + to_index.append((file_path, resolved, file_hash)) + + if not to_index: + return + + # Index uncached files + if len(to_index) >= _PARALLEL_THRESHOLD: + self._build_index_parallel(to_index, on_progress) + else: + for file_path, _resolved, file_hash in to_index: + result = self.index_file(file_path, file_hash) + self._report_progress(on_progress, result) + + def _is_file_cached(self, resolved: str, file_hash: str) -> bool: + """Check if file is cached in memory or DB.""" + # Check in-memory cache + if self.indexed_file_hashes.get(resolved) == file_hash: + return True + + # Check DB cache + row = self.conn.execute( + "SELECT file_hash FROM cg_indexed_files WHERE project_root = ? AND file_path = ?", + (self.project_root_str, resolved), + ).fetchone() + + if row and row[0] == file_hash: + self.indexed_file_hashes[resolved] = file_hash + return True + + return False + + def _report_progress(self, on_progress: Callable[[IndexResult], None] | None, result: IndexResult) -> None: + """Report progress if callback provided.""" + if on_progress is not None: + on_progress(result) + + def _build_index_parallel( + self, to_index: list[tuple[Path, str, str]], on_progress: Callable[[IndexResult], None] | None + ) -> None: + from concurrent.futures import ProcessPoolExecutor, as_completed + + max_workers = min(os.cpu_count() or 1, len(to_index), 8) + path_info: dict[str, tuple[Path, str]] = {resolved: (fp, fh) for fp, resolved, fh in to_index} + worker_args = [(resolved, fh) for _fp, resolved, fh in to_index] + + logger.debug(f"CallGraph: indexing {len(to_index)} files across {max_workers} workers") - def _get_enclosing_function_qualified_name(self, ref: Name) -> str | None: try: - parent = ref.parent() - if parent is None or parent.type != "function": - return None - if not parent.full_name or not parent.full_name.startswith(parent.module_name): - return None - return get_qualified_name(parent.module_name, parent.full_name) - except (ValueError, AttributeError): - return None + with ProcessPoolExecutor( + max_workers=max_workers, initializer=_init_index_worker, initargs=(self.project_root_str,) + ) as executor: + futures = {executor.submit(_index_file_worker, args): args[0] for args in worker_args} + + for future in as_completed(futures): + resolved = futures[future] + file_path, file_hash = path_info[resolved] + + try: + _, _, edges, had_error = future.result() + except Exception: + logger.debug(f"CallGraph: worker failed for {file_path}") + self._persist_edges(file_path, resolved, file_hash, set(), had_error=True) + self._report_progress( + on_progress, + IndexResult( + file_path=file_path, cached=False, num_edges=0, edges=(), cross_file_edges=0, error=True + ), + ) + continue - def build_index(self, file_paths: Iterable[Path], on_progress: Callable[[IndexResult], None] | None = None) -> None: - """Pre-index a batch of files. Calls on_progress(result) after each file.""" - for file_path in file_paths: - result = self.ensure_file_indexed(file_path) - if on_progress is not None: - on_progress(result) + if had_error: + logger.debug(f"CallGraph: failed to parse {file_path}") + + result = self._persist_edges(file_path, resolved, file_hash, edges, had_error) + self._report_progress(on_progress, result) + + except Exception: + logger.debug("CallGraph: parallel indexing failed, falling back to sequential") + self._fallback_sequential_index(to_index, on_progress) + + def _fallback_sequential_index( + self, to_index: list[tuple[Path, str, str]], on_progress: Callable[[IndexResult], None] | None + ) -> None: + """Fallback to sequential indexing when parallel processing fails.""" + for file_path, resolved, file_hash in to_index: + # Skip files already persisted before the failure + if resolved in self.indexed_file_hashes: + continue + result = self.index_file(file_path, file_hash) + self._report_progress(on_progress, result) def close(self) -> None: self.conn.close() From 9cc10042ee1d203beb32237a97ffac6abd2f202c Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 11 Feb 2026 20:21:36 -0500 Subject: [PATCH 009/100] refactor: improve call graph live display and filter non-Python files Use bounded deque for results, batch updates every 8 results with manual refresh to reduce flicker, and filter source_files to Python-only before passing to the call graph indexer. --- codeflash/cli_cmds/console.py | 148 +++++++++++++++++----------- codeflash/optimization/optimizer.py | 2 +- 2 files changed, 89 insertions(+), 61 deletions(-) diff --git a/codeflash/cli_cmds/console.py b/codeflash/cli_cmds/console.py index 3ab6a9619..e9e921e91 100644 --- a/codeflash/cli_cmds/console.py +++ b/codeflash/cli_cmds/console.py @@ -1,6 +1,7 @@ from __future__ import annotations import logging +from collections import deque from contextlib import contextmanager from itertools import cycle from typing import TYPE_CHECKING, Optional @@ -214,7 +215,7 @@ def call_graph_live_display(total: int) -> Generator[Callable[[IndexResult], Non if is_LSP_enabled(): lsp_log(LspTextMessage(text="Building call graph", takes_time=True)) - yield lambda _result: None + yield lambda _: None return progress = Progress( @@ -228,87 +229,114 @@ def call_graph_live_display(total: int) -> Generator[Callable[[IndexResult], Non ) task_id = progress.add_task("Analyzing files", total=total) - results: list[IndexResult] = [] - stats_indexed = 0 - stats_cached = 0 - stats_edges = 0 - stats_external = 0 - stats_errors = 0 - - def make_display() -> Panel: - tree = Tree("[bold]Dependencies[/bold]") - for result in results[-MAX_TREE_ENTRIES:]: - name = result.file_path.name + results: deque[IndexResult] = deque(maxlen=MAX_TREE_ENTRIES) + stats = { + "indexed": 0, + "cached": 0, + "edges": 0, + "external": 0, + "errors": 0, + } + + tree = Tree("[bold]Dependencies[/bold]") + stats_text = Text("0 dependencies found", style="dim") + panel = Panel( + Group(progress, Text(""), tree, Text(""), stats_text), + title="Building Call Graph", + border_style="cyan", + ) + + def create_tree_node(result: IndexResult) -> Tree: + name = f"{result.file_path.parent.name}/{result.file_path.name}" + + if result.error: + return Tree(f"[red]{name} (error)[/red]") + + if result.cached: + return Tree(f"[dim]{name} (cached)[/dim]") + + local_edges = result.num_edges - result.cross_file_edges + edge_info = [] + + if local_edges: + edge_info.append(f"{local_edges} in same file") + if result.cross_file_edges: + edge_info.append(f"{result.cross_file_edges} from other modules") + + label = ", ".join(edge_info) if edge_info else "no dependencies" + return Tree(f"[cyan]{name}[/cyan] [dim]{label}[/dim]") + + def refresh_display() -> None: + tree.children = [create_tree_node(r) for r in results] + tree.children.extend([Tree(" ")] * (MAX_TREE_ENTRIES - len(results))) + + # Update stats + stat_parts = [] + if stats["indexed"]: + stat_parts.append(f"{stats['indexed']} files analyzed") + if stats["cached"]: + stat_parts.append(f"{stats['cached']} cached") + if stats["errors"]: + stat_parts.append(f"{stats['errors']} errors") + stat_parts.append(f"{stats['edges']} dependencies found") + if stats["external"]: + stat_parts.append(f"{stats['external']} from other modules") + + stats_text.truncate(0) + stats_text.append(" · ".join(stat_parts), style="dim") + + batch: list[IndexResult] = [] + + def process_batch() -> None: + for result in batch: + results.append(result) + if result.error: - tree.add(f"[red]{name} (error)[/red]") + stats["errors"] += 1 elif result.cached: - tree.add(f"[dim]{name} (cached)[/dim]") + stats["cached"] += 1 else: - local = result.num_edges - result.cross_file_edges - parts = [] - if local: - parts.append(f"{local} in same file") - if result.cross_file_edges: - parts.append(f"{result.cross_file_edges} from other modules") - label = ", ".join(parts) if parts else "no dependencies" - tree.add(f"[cyan]{name}[/cyan] [dim]{label}[/dim]") - - parts: list[str] = [] - if stats_indexed: - parts.append(f"{stats_indexed} files analyzed") - if stats_cached: - parts.append(f"{stats_cached} cached") - if stats_errors: - parts.append(f"{stats_errors} errors") - parts.append(f"{stats_edges} dependencies found") - if stats_external: - parts.append(f"{stats_external} from other modules") - stats_text = Text(" · ".join(parts), style="dim") - - return Panel( - Group(progress, Text(""), tree, Text(""), stats_text), title="Building Call Graph", border_style="cyan" - ) + stats["indexed"] += 1 + stats["edges"] += result.num_edges + stats["external"] += result.cross_file_edges + + progress.advance(task_id) + + batch.clear() + refresh_display() + live.refresh() def update(result: IndexResult) -> None: - nonlocal stats_indexed, stats_cached, stats_edges, stats_external, stats_errors - results.append(result) - if result.error: - stats_errors += 1 - elif result.cached: - stats_cached += 1 - else: - stats_indexed += 1 - stats_edges += result.num_edges - stats_external += result.cross_file_edges - progress.advance(task_id) - live.update(make_display()) - - with Live(make_display(), console=console, transient=True, refresh_per_second=8) as live: + batch.append(result) + if len(batch) >= 8: + process_batch() + + with Live(panel, console=console, transient=True, auto_refresh=False) as live: yield update + if batch: + process_batch() def call_graph_summary(call_graph: CallGraph, file_to_funcs: dict[Path, list[FunctionToOptimize]]) -> None: from rich.panel import Panel total_functions = sum(len(funcs) for funcs in file_to_funcs.values()) - if total_functions == 0: + if not total_functions: return total_callees = 0 with_context = 0 - leaf_functions = 0 for file_path, funcs in file_to_funcs.items(): for func in funcs: _, func_callees = call_graph.get_callees({file_path: {func.qualified_name}}) - count = len(func_callees) - total_callees += count - if count > 0: + callee_count = len(func_callees) + total_callees += callee_count + if callee_count > 0: with_context += 1 - else: - leaf_functions += 1 - avg_callees = total_callees / total_functions if total_functions > 0 else 0 + leaf_functions = total_functions - with_context + avg_callees = total_callees / total_functions summary = ( f"{total_functions} functions ready for optimization · " diff --git a/codeflash/optimization/optimizer.py b/codeflash/optimization/optimizer.py index a8e9de02c..c0bb5539e 100644 --- a/codeflash/optimization/optimizer.py +++ b/codeflash/optimization/optimizer.py @@ -543,7 +543,7 @@ def run(self) -> None: logger.debug("Failed to initialize CallGraph, falling back to per-function Jedi analysis") if call_graph is not None and file_to_funcs_to_optimize: - source_files = list(file_to_funcs_to_optimize.keys()) + source_files = [f for f in file_to_funcs_to_optimize if f.suffix in (".py", ".pyw")] with call_graph_live_display(len(source_files)) as on_progress: call_graph.build_index(source_files, on_progress=on_progress) call_graph_summary(call_graph, file_to_funcs_to_optimize) From f3f0b0e020784e63e97cdd604aaec9dc1f324c7f Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 11 Feb 2026 20:48:34 -0500 Subject: [PATCH 010/100] refactor: move CallGraph into Python language support layer Add DependencyResolver protocol and IndexResult to base.py, move call_graph.py to languages/python/, and use factory method in optimizer instead of is_python() gating. --- codeflash/cli_cmds/console.py | 16 ++----- codeflash/context/code_context_extractor.py | 5 +-- codeflash/languages/__init__.py | 4 ++ codeflash/languages/base.py | 45 ++++++++++++++++++- codeflash/languages/javascript/support.py | 3 ++ codeflash/languages/python/__init__.py | 3 +- .../python}/call_graph.py | 12 +---- codeflash/languages/python/support.py | 10 +++++ codeflash/optimization/function_optimizer.py | 4 +- codeflash/optimization/optimizer.py | 42 ++++++++--------- tests/test_call_graph.py | 3 +- 11 files changed, 92 insertions(+), 55 deletions(-) rename codeflash/{context => languages/python}/call_graph.py (98%) diff --git a/codeflash/cli_cmds/console.py b/codeflash/cli_cmds/console.py index e9e921e91..317d5feae 100644 --- a/codeflash/cli_cmds/console.py +++ b/codeflash/cli_cmds/console.py @@ -30,8 +30,8 @@ from rich.progress import TaskID - from codeflash.context.call_graph import CallGraph, IndexResult from codeflash.discovery.functions_to_optimize import FunctionToOptimize + from codeflash.languages.base import DependencyResolver, IndexResult from codeflash.lsp.lsp_message import LspMessage DEBUG_MODE = logging.getLogger().getEffectiveLevel() == logging.DEBUG @@ -230,20 +230,12 @@ def call_graph_live_display(total: int) -> Generator[Callable[[IndexResult], Non task_id = progress.add_task("Analyzing files", total=total) results: deque[IndexResult] = deque(maxlen=MAX_TREE_ENTRIES) - stats = { - "indexed": 0, - "cached": 0, - "edges": 0, - "external": 0, - "errors": 0, - } + stats = {"indexed": 0, "cached": 0, "edges": 0, "external": 0, "errors": 0} tree = Tree("[bold]Dependencies[/bold]") stats_text = Text("0 dependencies found", style="dim") panel = Panel( - Group(progress, Text(""), tree, Text(""), stats_text), - title="Building Call Graph", - border_style="cyan", + Group(progress, Text(""), tree, Text(""), stats_text), title="Building Call Graph", border_style="cyan" ) def create_tree_node(result: IndexResult) -> Tree: @@ -317,7 +309,7 @@ def update(result: IndexResult) -> None: process_batch() -def call_graph_summary(call_graph: CallGraph, file_to_funcs: dict[Path, list[FunctionToOptimize]]) -> None: +def call_graph_summary(call_graph: DependencyResolver, file_to_funcs: dict[Path, list[FunctionToOptimize]]) -> None: from rich.panel import Panel total_functions = sum(len(funcs) for funcs in file_to_funcs.values()) diff --git a/codeflash/context/code_context_extractor.py b/codeflash/context/code_context_extractor.py index 4650de795..3764f4544 100644 --- a/codeflash/context/code_context_extractor.py +++ b/codeflash/context/code_context_extractor.py @@ -37,9 +37,8 @@ from jedi.api.classes import Name from libcst import CSTNode - from codeflash.context.call_graph import CallGraph from codeflash.context.unused_definition_remover import UsageInfo - from codeflash.languages.base import HelperFunction + from codeflash.languages.base import DependencyResolver, HelperFunction def build_testgen_context( @@ -79,7 +78,7 @@ def get_code_optimization_context( project_root_path: Path, optim_token_limit: int = OPTIMIZATION_CONTEXT_TOKEN_LIMIT, testgen_token_limit: int = TESTGEN_CONTEXT_TOKEN_LIMIT, - call_graph: CallGraph | None = None, + call_graph: DependencyResolver | None = None, ) -> CodeOptimizationContext: # Route to language-specific implementation for non-Python languages if not is_python(): diff --git a/codeflash/languages/__init__.py b/codeflash/languages/__init__.py index 47136f4e7..daf33b43c 100644 --- a/codeflash/languages/__init__.py +++ b/codeflash/languages/__init__.py @@ -19,7 +19,9 @@ from codeflash.languages.base import ( CodeContext, + DependencyResolver, HelperFunction, + IndexResult, Language, LanguageSupport, ParentInfo, @@ -82,8 +84,10 @@ def __getattr__(name: str): __all__ = [ "CodeContext", + "DependencyResolver", "FunctionInfo", "HelperFunction", + "IndexResult", "Language", "LanguageSupport", "ParentInfo", diff --git a/codeflash/languages/base.py b/codeflash/languages/base.py index 99cefdf46..76357a4d1 100644 --- a/codeflash/languages/base.py +++ b/codeflash/languages/base.py @@ -11,10 +11,11 @@ from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable if TYPE_CHECKING: - from collections.abc import Sequence + from collections.abc import Callable, Iterable, Sequence from pathlib import Path from codeflash.discovery.functions_to_optimize import FunctionToOptimize + from codeflash.models.models import FunctionSource from codeflash.languages.language_enum import Language from codeflash.models.function_types import FunctionParent @@ -34,6 +35,16 @@ def __getattr__(name: str) -> Any: raise AttributeError(msg) +@dataclass(frozen=True, slots=True) +class IndexResult: + file_path: Path + cached: bool + num_edges: int + edges: tuple[tuple[str, str, bool], ...] # (caller_qn, callee_name, is_cross_file) + cross_file_edges: int + error: bool + + @dataclass class HelperFunction: """A helper function that is a dependency of the target function. @@ -192,6 +203,29 @@ class ReferenceInfo: caller_function: str | None = None +@runtime_checkable +class DependencyResolver(Protocol): + """Protocol for language-specific dependency resolution. + + Implementations analyze source files to discover call-graph edges + between functions so the optimizer can extract richer context. + """ + + def build_index(self, file_paths: Iterable[Path], on_progress: Callable[[IndexResult], None] | None = None) -> None: + """Pre-index a batch of files.""" + ... + + def get_callees( + self, file_path_to_qualified_names: dict[Path, set[str]] + ) -> tuple[dict[Path, set[FunctionSource]], list[FunctionSource]]: + """Return callees for the given functions.""" + ... + + def close(self) -> None: + """Release resources (e.g. database connections).""" + ... + + @runtime_checkable class LanguageSupport(Protocol): """Protocol defining what a language implementation must provide. @@ -565,6 +599,15 @@ def ensure_runtime_environment(self, project_root: Path) -> bool: # Default implementation: just copy runtime files return False + def create_dependency_resolver(self, project_root: Path) -> DependencyResolver | None: + """Create a language-specific dependency resolver, if available. + + Returns: + A DependencyResolver instance, or None if not supported. + + """ + return None + def instrument_existing_test( self, test_path: Path, diff --git a/codeflash/languages/javascript/support.py b/codeflash/languages/javascript/support.py index d32cce001..9d41b9cd4 100644 --- a/codeflash/languages/javascript/support.py +++ b/codeflash/languages/javascript/support.py @@ -1942,6 +1942,9 @@ def ensure_runtime_environment(self, project_root: Path) -> bool: logger.error("Could not install codeflash. Please run: npm install --save-dev codeflash") return False + def create_dependency_resolver(self, project_root: Path) -> None: + return None + def instrument_existing_test( self, test_path: Path, diff --git a/codeflash/languages/python/__init__.py b/codeflash/languages/python/__init__.py index e599d1431..50eb1a51e 100644 --- a/codeflash/languages/python/__init__.py +++ b/codeflash/languages/python/__init__.py @@ -5,6 +5,7 @@ to the LanguageSupport protocol. """ +from codeflash.languages.python.call_graph import CallGraph from codeflash.languages.python.support import PythonSupport -__all__ = ["PythonSupport"] +__all__ = ["CallGraph", "PythonSupport"] diff --git a/codeflash/context/call_graph.py b/codeflash/languages/python/call_graph.py similarity index 98% rename from codeflash/context/call_graph.py rename to codeflash/languages/python/call_graph.py index 033f8399a..16002c5e2 100644 --- a/codeflash/context/call_graph.py +++ b/codeflash/languages/python/call_graph.py @@ -4,12 +4,12 @@ import os import sqlite3 from collections import defaultdict -from dataclasses import dataclass from pathlib import Path from typing import TYPE_CHECKING from codeflash.cli_cmds.console import logger from codeflash.code_utils.code_utils import get_qualified_name, path_belongs_to_site_packages +from codeflash.languages.base import IndexResult from codeflash.models.models import FunctionSource if TYPE_CHECKING: @@ -18,16 +18,6 @@ from jedi.api.classes import Name -@dataclass(frozen=True, slots=True) -class IndexResult: - file_path: Path - cached: bool - num_edges: int - edges: tuple[tuple[str, str, bool], ...] # (caller_qn, callee_name, is_cross_file) - cross_file_edges: int - error: bool - - # --------------------------------------------------------------------------- # Module-level helpers (must be top-level for ProcessPoolExecutor pickling) # --------------------------------------------------------------------------- diff --git a/codeflash/languages/python/support.py b/codeflash/languages/python/support.py index 58f66d0b8..03c376478 100644 --- a/codeflash/languages/python/support.py +++ b/codeflash/languages/python/support.py @@ -9,6 +9,7 @@ from codeflash.discovery.functions_to_optimize import FunctionToOptimize from codeflash.languages.base import ( CodeContext, + DependencyResolver, FunctionFilterCriteria, HelperFunction, Language, @@ -801,6 +802,15 @@ def ensure_runtime_environment(self, project_root: Path) -> bool: """ return True + def create_dependency_resolver(self, project_root: Path) -> DependencyResolver | None: + from codeflash.languages.python.call_graph import CallGraph + + try: + return CallGraph(project_root) + except Exception: + logger.debug("Failed to initialize CallGraph, falling back to per-function Jedi analysis") + return None + def instrument_existing_test( self, test_path: Path, diff --git a/codeflash/optimization/function_optimizer.py b/codeflash/optimization/function_optimizer.py index 024e77c89..f2e1887db 100644 --- a/codeflash/optimization/function_optimizer.py +++ b/codeflash/optimization/function_optimizer.py @@ -132,9 +132,9 @@ if TYPE_CHECKING: from argparse import Namespace - from codeflash.context.call_graph import CallGraph from codeflash.discovery.functions_to_optimize import FunctionToOptimize from codeflash.either import Result + from codeflash.languages.base import DependencyResolver from codeflash.models.models import ( BenchmarkKey, CodeStringsMarkdown, @@ -438,7 +438,7 @@ def __init__( total_benchmark_timings: dict[BenchmarkKey, int] | None = None, args: Namespace | None = None, replay_tests_dir: Path | None = None, - call_graph: CallGraph | None = None, + call_graph: DependencyResolver | None = None, ) -> None: self.project_root = test_cfg.project_root_path self.test_cfg = test_cfg diff --git a/codeflash/optimization/optimizer.py b/codeflash/optimization/optimizer.py index c0bb5539e..ff068f5c1 100644 --- a/codeflash/optimization/optimizer.py +++ b/codeflash/optimization/optimizer.py @@ -24,7 +24,7 @@ ) from codeflash.code_utils.time_utils import humanize_runtime from codeflash.either import is_successful -from codeflash.languages import is_javascript, set_current_language +from codeflash.languages import current_language_support, is_javascript, set_current_language from codeflash.models.models import ValidCode from codeflash.telemetry.posthog_cf import ph from codeflash.verification.verification_utils import TestConfig @@ -34,8 +34,8 @@ from codeflash.benchmarking.function_ranker import FunctionRanker from codeflash.code_utils.checkpoint import CodeflashRunCheckpoint - from codeflash.context.call_graph import CallGraph from codeflash.discovery.functions_to_optimize import FunctionToOptimize + from codeflash.languages.base import DependencyResolver from codeflash.models.models import BenchmarkKey, FunctionCalledInTest from codeflash.optimization.function_optimizer import FunctionOptimizer @@ -206,7 +206,7 @@ def create_function_optimizer( total_benchmark_timings: dict[BenchmarkKey, float] | None = None, original_module_ast: ast.Module | None = None, original_module_path: Path | None = None, - call_graph: CallGraph | None = None, + call_graph: DependencyResolver | None = None, ) -> FunctionOptimizer | None: from codeflash.code_utils.static_analysis import get_first_top_level_function_or_method_ast from codeflash.optimization.function_optimizer import FunctionOptimizer @@ -392,7 +392,7 @@ def rank_all_functions_globally( self, file_to_funcs_to_optimize: dict[Path, list[FunctionToOptimize]], trace_file_path: Path | None, - call_graph: CallGraph | None = None, + call_graph: DependencyResolver | None = None, ) -> list[tuple[Path, FunctionToOptimize]]: """Rank all functions globally across all files based on trace data. @@ -467,7 +467,7 @@ def rank_all_functions_globally( return globally_ranked def rank_by_dependency_count( - self, all_functions: list[tuple[Path, FunctionToOptimize]], call_graph: CallGraph + self, all_functions: list[tuple[Path, FunctionToOptimize]], call_graph: DependencyResolver ) -> list[tuple[Path, FunctionToOptimize]]: counts: list[tuple[int, int, tuple[Path, FunctionToOptimize]]] = [] for idx, (file_path, func) in enumerate(all_functions): @@ -530,23 +530,17 @@ def run(self) -> None: file_to_funcs_to_optimize, num_optimizable_functions ) - # Create persistent call graph for Python runs to cache Jedi analysis across functions - call_graph: CallGraph | None = None - from codeflash.languages import is_python + # Create a language-specific dependency resolver (e.g. Jedi-based call graph for Python) + resolver: DependencyResolver | None = None + lang_support = current_language_support() + if hasattr(lang_support, "create_dependency_resolver"): + resolver = lang_support.create_dependency_resolver(self.args.project_root) - if is_python(): - from codeflash.context.call_graph import CallGraph - - try: - call_graph = CallGraph(self.args.project_root) - except Exception: - logger.debug("Failed to initialize CallGraph, falling back to per-function Jedi analysis") - - if call_graph is not None and file_to_funcs_to_optimize: - source_files = [f for f in file_to_funcs_to_optimize if f.suffix in (".py", ".pyw")] + if resolver is not None and file_to_funcs_to_optimize: + source_files = list(file_to_funcs_to_optimize.keys()) with call_graph_live_display(len(source_files)) as on_progress: - call_graph.build_index(source_files, on_progress=on_progress) - call_graph_summary(call_graph, file_to_funcs_to_optimize) + resolver.build_index(source_files, on_progress=on_progress) + call_graph_summary(resolver, file_to_funcs_to_optimize) optimizations_found: int = 0 self.test_cfg.concolic_test_root_dir = Path( @@ -564,7 +558,7 @@ def run(self) -> None: # GLOBAL RANKING: Rank all functions together before optimizing globally_ranked_functions = self.rank_all_functions_globally( - file_to_funcs_to_optimize, trace_file_path, call_graph=call_graph + file_to_funcs_to_optimize, trace_file_path, call_graph=resolver ) # Cache for module preparation (avoid re-parsing same files) prepared_modules: dict[Path, tuple[dict[Path, ValidCode], ast.Module | None]] = {} @@ -597,7 +591,7 @@ def run(self) -> None: total_benchmark_timings=total_benchmark_timings, original_module_ast=original_module_ast, original_module_path=original_module_path, - call_graph=call_graph, + call_graph=resolver, ) if function_optimizer is None: continue @@ -656,8 +650,8 @@ def run(self) -> None: else: logger.warning("⚠️ Failed to send completion email. Status") finally: - if call_graph is not None: - call_graph.close() + if resolver is not None: + resolver.close() if function_optimizer: function_optimizer.cleanup_generated_files() diff --git a/tests/test_call_graph.py b/tests/test_call_graph.py index a2918434a..22c306055 100644 --- a/tests/test_call_graph.py +++ b/tests/test_call_graph.py @@ -7,7 +7,8 @@ if TYPE_CHECKING: from pathlib import Path -from codeflash.context.call_graph import CallGraph, IndexResult +from codeflash.languages.base import IndexResult +from codeflash.languages.python.call_graph import CallGraph @pytest.fixture From ed31cd11eea78f485cda3a59e7a8e0a495036b7a Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 11 Feb 2026 21:03:31 -0500 Subject: [PATCH 011/100] refactor: filter files by language extensions and show project-relative paths in call graph Display file paths relative to project root in the call graph live display for easier navigation. Filter indexed files by the language support's file extensions to avoid processing irrelevant file types. --- codeflash/cli_cmds/console.py | 12 ++++++++++-- codeflash/languages/python/call_graph.py | 1 - codeflash/languages/python/support.py | 3 ++- codeflash/optimization/optimizer.py | 9 ++++----- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/codeflash/cli_cmds/console.py b/codeflash/cli_cmds/console.py index 317d5feae..3e1aa64d7 100644 --- a/codeflash/cli_cmds/console.py +++ b/codeflash/cli_cmds/console.py @@ -206,7 +206,9 @@ def test_files_progress_bar(total: int, description: str) -> Generator[tuple[Pro @contextmanager -def call_graph_live_display(total: int) -> Generator[Callable[[IndexResult], None], None, None]: +def call_graph_live_display( + total: int, project_root: Path | None = None +) -> Generator[Callable[[IndexResult], None], None, None]: from rich.console import Group from rich.live import Live from rich.panel import Panel @@ -239,7 +241,13 @@ def call_graph_live_display(total: int) -> Generator[Callable[[IndexResult], Non ) def create_tree_node(result: IndexResult) -> Tree: - name = f"{result.file_path.parent.name}/{result.file_path.name}" + if project_root: + try: + name = str(result.file_path.resolve().relative_to(project_root.resolve())) + except ValueError: + name = f"{result.file_path.parent.name}/{result.file_path.name}" + else: + name = f"{result.file_path.parent.name}/{result.file_path.name}" if result.error: return Tree(f"[red]{name} (error)[/red]") diff --git a/codeflash/languages/python/call_graph.py b/codeflash/languages/python/call_graph.py index 16002c5e2..bc6dadb8a 100644 --- a/codeflash/languages/python/call_graph.py +++ b/codeflash/languages/python/call_graph.py @@ -131,7 +131,6 @@ def _analyze_file(file_path: Path, jedi_project: object, project_root_str: str) if not _is_valid_definition(definition, caller_qn, project_root_str): continue - # Extract common edge components edge_base = (resolved, caller_qn, str(definition_path)) if definition.type == "function": diff --git a/codeflash/languages/python/support.py b/codeflash/languages/python/support.py index 03c376478..429f9e1f9 100644 --- a/codeflash/languages/python/support.py +++ b/codeflash/languages/python/support.py @@ -9,7 +9,6 @@ from codeflash.discovery.functions_to_optimize import FunctionToOptimize from codeflash.languages.base import ( CodeContext, - DependencyResolver, FunctionFilterCriteria, HelperFunction, Language, @@ -22,6 +21,8 @@ if TYPE_CHECKING: from collections.abc import Sequence + from codeflash.languages.base import DependencyResolver + logger = logging.getLogger(__name__) diff --git a/codeflash/optimization/optimizer.py b/codeflash/optimization/optimizer.py index ff068f5c1..380a1d8be 100644 --- a/codeflash/optimization/optimizer.py +++ b/codeflash/optimization/optimizer.py @@ -531,14 +531,13 @@ def run(self) -> None: ) # Create a language-specific dependency resolver (e.g. Jedi-based call graph for Python) - resolver: DependencyResolver | None = None lang_support = current_language_support() - if hasattr(lang_support, "create_dependency_resolver"): - resolver = lang_support.create_dependency_resolver(self.args.project_root) + resolver = lang_support.create_dependency_resolver(self.args.project_root) if lang_support else None if resolver is not None and file_to_funcs_to_optimize: - source_files = list(file_to_funcs_to_optimize.keys()) - with call_graph_live_display(len(source_files)) as on_progress: + supported_exts = lang_support.file_extensions + source_files = [f for f in file_to_funcs_to_optimize if f.suffix in supported_exts] + with call_graph_live_display(len(source_files), project_root=self.args.project_root) as on_progress: resolver.build_index(source_files, on_progress=on_progress) call_graph_summary(resolver, file_to_funcs_to_optimize) From 5341ac8fdeab87b85c37f6535d659391a985f855 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 11 Feb 2026 21:13:32 -0500 Subject: [PATCH 012/100] fix: improve CLI output formatting for runtime estimate and call graph sections Split the runtime estimate and PR message into separate log lines to avoid awkward line wrapping. Add console rules between sections for clearer visual separation. --- codeflash/optimization/optimizer.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/codeflash/optimization/optimizer.py b/codeflash/optimization/optimizer.py index 380a1d8be..d58aad00a 100644 --- a/codeflash/optimization/optimizer.py +++ b/codeflash/optimization/optimizer.py @@ -519,12 +519,12 @@ def run(self) -> None: if self.args.all: three_min_in_ns = int(1.8e11) console.rule() - pr_message = ( - "\nCodeflash will keep opening pull requests as it finds optimizations." if not self.args.no_pr else "" - ) logger.info( - f"It might take about {humanize_runtime(num_optimizable_functions * three_min_in_ns)} to fully optimize this project.{pr_message}" + f"It might take about {humanize_runtime(num_optimizable_functions * three_min_in_ns)} to fully optimize this project." ) + if not self.args.no_pr: + logger.info("Codeflash will keep opening pull requests as it finds optimizations.") + console.rule() function_benchmark_timings, total_benchmark_timings = self.run_benchmarks( file_to_funcs_to_optimize, num_optimizable_functions @@ -539,6 +539,7 @@ def run(self) -> None: source_files = [f for f in file_to_funcs_to_optimize if f.suffix in supported_exts] with call_graph_live_display(len(source_files), project_root=self.args.project_root) as on_progress: resolver.build_index(source_files, on_progress=on_progress) + console.rule() call_graph_summary(resolver, file_to_funcs_to_optimize) optimizations_found: int = 0 From ee0da841eaa64a8cef0ffbfdf606ff5e995ad1ea Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 11 Feb 2026 21:50:36 -0500 Subject: [PATCH 013/100] refactor: simplify call graph DB schema to two flat human-readable tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the normalized relational hierarchy (cg_projects → cg_languages → cg_indexed_files/cg_call_edges) with two self-describing tables (indexed_files, call_edges) where every row includes project_root and language as text columns. --- codeflash/languages/python/call_graph.py | 94 +++++++++++++----------- codeflash/languages/python/support.py | 2 +- 2 files changed, 51 insertions(+), 45 deletions(-) diff --git a/codeflash/languages/python/call_graph.py b/codeflash/languages/python/call_graph.py index bc6dadb8a..596c8db4f 100644 --- a/codeflash/languages/python/call_graph.py +++ b/codeflash/languages/python/call_graph.py @@ -178,13 +178,14 @@ def _index_file_worker(args: tuple[str, str]) -> tuple[str, str, set[tuple[str, class CallGraph: - SCHEMA_VERSION = 1 + SCHEMA_VERSION = 2 - def __init__(self, project_root: Path, db_path: Path | None = None) -> None: + def __init__(self, project_root: Path, language: str = "python", db_path: Path | None = None) -> None: import jedi self.project_root = project_root.resolve() self.project_root_str = str(self.project_root) + self.language = language self.jedi_project = jedi.Project(path=self.project_root) if db_path is None: @@ -200,27 +201,35 @@ def __init__(self, project_root: Path, db_path: Path | None = None) -> None: def _init_schema(self) -> None: cur = self.conn.cursor() cur.execute("CREATE TABLE IF NOT EXISTS cg_schema_version (version INTEGER PRIMARY KEY)") + row = cur.execute("SELECT version FROM cg_schema_version LIMIT 1").fetchone() if row is None: cur.execute("INSERT INTO cg_schema_version (version) VALUES (?)", (self.SCHEMA_VERSION,)) elif row[0] != self.SCHEMA_VERSION: - # Schema mismatch — drop all cg_ tables and recreate - cur.execute("DROP TABLE IF EXISTS cg_call_edges") - cur.execute("DROP TABLE IF EXISTS cg_indexed_files") + for table in [ + "cg_call_edges", "cg_indexed_files", "cg_languages", "cg_projects", "cg_project_meta", + "indexed_files", "call_edges", + ]: + cur.execute(f"DROP TABLE IF EXISTS {table}") cur.execute("DELETE FROM cg_schema_version") cur.execute("INSERT INTO cg_schema_version (version) VALUES (?)", (self.SCHEMA_VERSION,)) cur.execute( - """CREATE TABLE IF NOT EXISTS cg_indexed_files ( + """ + CREATE TABLE IF NOT EXISTS indexed_files ( project_root TEXT NOT NULL, + language TEXT NOT NULL, file_path TEXT NOT NULL, file_hash TEXT NOT NULL, - PRIMARY KEY (project_root, file_path) - )""" + PRIMARY KEY (project_root, language, file_path) + ) + """ ) cur.execute( - """CREATE TABLE IF NOT EXISTS cg_call_edges ( + """ + CREATE TABLE IF NOT EXISTS call_edges ( project_root TEXT NOT NULL, + language TEXT NOT NULL, caller_file TEXT NOT NULL, caller_qualified_name TEXT NOT NULL, callee_file TEXT NOT NULL, @@ -229,13 +238,16 @@ def _init_schema(self) -> None: callee_only_function_name TEXT NOT NULL, callee_definition_type TEXT NOT NULL, callee_source_line TEXT NOT NULL, - PRIMARY KEY (project_root, caller_file, caller_qualified_name, + PRIMARY KEY (project_root, language, caller_file, caller_qualified_name, callee_file, callee_qualified_name) - )""" + ) + """ ) cur.execute( - """CREATE INDEX IF NOT EXISTS idx_cg_edges_caller - ON cg_call_edges (project_root, caller_file, caller_qualified_name)""" + """ + CREATE INDEX IF NOT EXISTS idx_call_edges_caller + ON call_edges (project_root, language, caller_file, caller_qualified_name) + """ ) self.conn.commit() @@ -259,11 +271,13 @@ def get_callees( cur = self.conn.cursor() for caller_file, caller_qn in all_caller_keys: rows = cur.execute( - """SELECT callee_file, callee_qualified_name, callee_fully_qualified_name, - callee_only_function_name, callee_definition_type, callee_source_line - FROM cg_call_edges - WHERE project_root = ? AND caller_file = ? AND caller_qualified_name = ?""", - (self.project_root_str, caller_file, caller_qn), + """ + SELECT callee_file, callee_qualified_name, callee_fully_qualified_name, + callee_only_function_name, callee_definition_type, callee_source_line + FROM call_edges + WHERE project_root = ? AND language = ? AND caller_file = ? AND caller_qualified_name = ? + """, + (self.project_root_str, self.language, caller_file, caller_qn), ).fetchall() for callee_file, callee_qn, callee_fqn, callee_name, callee_type, callee_src in rows: @@ -291,18 +305,7 @@ def ensure_file_indexed(self, file_path: Path) -> IndexResult: file_hash = hashlib.sha256(content.encode("utf-8")).hexdigest() - # Check in-memory cache first - if self.indexed_file_hashes.get(resolved) == file_hash: - return IndexResult(file_path=file_path, cached=True, num_edges=0, edges=(), cross_file_edges=0, error=False) - - # Check DB for stored hash - row = self.conn.execute( - "SELECT file_hash FROM cg_indexed_files WHERE project_root = ? AND file_path = ?", - (self.project_root_str, resolved), - ).fetchone() - - if row and row[0] == file_hash: - self.indexed_file_hashes[resolved] = file_hash + if self._is_file_cached(resolved, file_hash): return IndexResult(file_path=file_path, cached=True, num_edges=0, edges=(), cross_file_edges=0, error=False) return self.index_file(file_path, file_hash) @@ -318,30 +321,35 @@ def _persist_edges( self, file_path: Path, resolved: str, file_hash: str, edges: set[tuple[str, ...]], had_error: bool ) -> IndexResult: cur = self.conn.cursor() + scope = (self.project_root_str, self.language) # Clear existing data for this file cur.execute( - "DELETE FROM cg_call_edges WHERE project_root = ? AND caller_file = ?", (self.project_root_str, resolved) + "DELETE FROM call_edges WHERE project_root = ? AND language = ? AND caller_file = ?", + (*scope, resolved), ) cur.execute( - "DELETE FROM cg_indexed_files WHERE project_root = ? AND file_path = ?", (self.project_root_str, resolved) + "DELETE FROM indexed_files WHERE project_root = ? AND language = ? AND file_path = ?", + (*scope, resolved), ) # Insert new edges if parsing succeeded if not had_error and edges: cur.executemany( - """INSERT OR REPLACE INTO cg_call_edges - (project_root, caller_file, caller_qualified_name, - callee_file, callee_qualified_name, callee_fully_qualified_name, - callee_only_function_name, callee_definition_type, callee_source_line) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""", - [(self.project_root_str, *edge) for edge in edges], + """ + INSERT OR REPLACE INTO call_edges + (project_root, language, caller_file, caller_qualified_name, + callee_file, callee_qualified_name, callee_fully_qualified_name, + callee_only_function_name, callee_definition_type, callee_source_line) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + """, + [(*scope, *edge) for edge in edges], ) # Record that this file has been indexed cur.execute( - "INSERT OR REPLACE INTO cg_indexed_files (project_root, file_path, file_hash) VALUES (?, ?, ?)", - (self.project_root_str, resolved, file_hash), + "INSERT OR REPLACE INTO indexed_files (project_root, language, file_path, file_hash) VALUES (?, ?, ?, ?)", + (*scope, resolved, file_hash), ) self.conn.commit() @@ -408,14 +416,12 @@ def build_index(self, file_paths: Iterable[Path], on_progress: Callable[[IndexRe def _is_file_cached(self, resolved: str, file_hash: str) -> bool: """Check if file is cached in memory or DB.""" - # Check in-memory cache if self.indexed_file_hashes.get(resolved) == file_hash: return True - # Check DB cache row = self.conn.execute( - "SELECT file_hash FROM cg_indexed_files WHERE project_root = ? AND file_path = ?", - (self.project_root_str, resolved), + "SELECT file_hash FROM indexed_files WHERE project_root = ? AND language = ? AND file_path = ?", + (self.project_root_str, self.language, resolved), ).fetchone() if row and row[0] == file_hash: diff --git a/codeflash/languages/python/support.py b/codeflash/languages/python/support.py index 429f9e1f9..77a37759d 100644 --- a/codeflash/languages/python/support.py +++ b/codeflash/languages/python/support.py @@ -807,7 +807,7 @@ def create_dependency_resolver(self, project_root: Path) -> DependencyResolver | from codeflash.languages.python.call_graph import CallGraph try: - return CallGraph(project_root) + return CallGraph(project_root, language=self.language.value) except Exception: logger.debug("Failed to initialize CallGraph, falling back to per-function Jedi analysis") return None From 0a5e8141b46f4f4bb1d252c14b44d48566674f8c Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 11 Feb 2026 22:55:07 -0500 Subject: [PATCH 014/100] Update config_consts.py --- codeflash/code_utils/config_consts.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codeflash/code_utils/config_consts.py b/codeflash/code_utils/config_consts.py index e344fad8a..32e5c7c54 100644 --- a/codeflash/code_utils/config_consts.py +++ b/codeflash/code_utils/config_consts.py @@ -4,8 +4,8 @@ from typing import Any, Union MAX_TEST_RUN_ITERATIONS = 5 -OPTIMIZATION_CONTEXT_TOKEN_LIMIT = 16000 -TESTGEN_CONTEXT_TOKEN_LIMIT = 16000 +OPTIMIZATION_CONTEXT_TOKEN_LIMIT = 100000 +TESTGEN_CONTEXT_TOKEN_LIMIT = 100000 INDIVIDUAL_TESTCASE_TIMEOUT = 15 MAX_FUNCTION_TEST_SECONDS = 60 MIN_IMPROVEMENT_THRESHOLD = 0.05 From 54aa7e1eabd37eb902961454beddf90d9fc30c29 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 12 Feb 2026 00:40:14 -0500 Subject: [PATCH 015/100] fix: skip call graph building in CI and fix ruff formatting Skip dependency resolver creation in CI environments where the cache DB doesn't persist between runs. Also apply ruff formatting to call_graph.py. --- codeflash/languages/python/call_graph.py | 15 +++++++++------ codeflash/optimization/optimizer.py | 5 ++++- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/codeflash/languages/python/call_graph.py b/codeflash/languages/python/call_graph.py index 596c8db4f..7d331d252 100644 --- a/codeflash/languages/python/call_graph.py +++ b/codeflash/languages/python/call_graph.py @@ -207,8 +207,13 @@ def _init_schema(self) -> None: cur.execute("INSERT INTO cg_schema_version (version) VALUES (?)", (self.SCHEMA_VERSION,)) elif row[0] != self.SCHEMA_VERSION: for table in [ - "cg_call_edges", "cg_indexed_files", "cg_languages", "cg_projects", "cg_project_meta", - "indexed_files", "call_edges", + "cg_call_edges", + "cg_indexed_files", + "cg_languages", + "cg_projects", + "cg_project_meta", + "indexed_files", + "call_edges", ]: cur.execute(f"DROP TABLE IF EXISTS {table}") cur.execute("DELETE FROM cg_schema_version") @@ -325,12 +330,10 @@ def _persist_edges( # Clear existing data for this file cur.execute( - "DELETE FROM call_edges WHERE project_root = ? AND language = ? AND caller_file = ?", - (*scope, resolved), + "DELETE FROM call_edges WHERE project_root = ? AND language = ? AND caller_file = ?", (*scope, resolved) ) cur.execute( - "DELETE FROM indexed_files WHERE project_root = ? AND language = ? AND file_path = ?", - (*scope, resolved), + "DELETE FROM indexed_files WHERE project_root = ? AND language = ? AND file_path = ?", (*scope, resolved) ) # Insert new edges if parsing succeeded diff --git a/codeflash/optimization/optimizer.py b/codeflash/optimization/optimizer.py index d58aad00a..810c1758b 100644 --- a/codeflash/optimization/optimizer.py +++ b/codeflash/optimization/optimizer.py @@ -531,8 +531,11 @@ def run(self) -> None: ) # Create a language-specific dependency resolver (e.g. Jedi-based call graph for Python) + # Skip in CI — the cache DB doesn't persist between runs on ephemeral runners lang_support = current_language_support() - resolver = lang_support.create_dependency_resolver(self.args.project_root) if lang_support else None + resolver = None + if lang_support and not env_utils.is_ci(): + resolver = lang_support.create_dependency_resolver(self.args.project_root) if resolver is not None and file_to_funcs_to_optimize: supported_exts = lang_support.file_extensions From c096c82b50204c849db2cab5178b6fb1523270bc Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 12 Feb 2026 00:43:11 -0500 Subject: [PATCH 016/100] refactor: simplify compat.py by removing unnecessary class wrapper --- codeflash/code_utils/compat.py | 44 ++++++---------------------------- 1 file changed, 7 insertions(+), 37 deletions(-) diff --git a/codeflash/code_utils/compat.py b/codeflash/code_utils/compat.py index eb4e5b561..b73a6a5a7 100644 --- a/codeflash/code_utils/compat.py +++ b/codeflash/code_utils/compat.py @@ -2,46 +2,16 @@ import sys import tempfile from pathlib import Path -from typing import TYPE_CHECKING from platformdirs import user_config_dir -if TYPE_CHECKING: - codeflash_temp_dir: Path - codeflash_cache_dir: Path - codeflash_cache_db: Path +LF: str = os.linesep +IS_POSIX: bool = os.name != "nt" +SAFE_SYS_EXECUTABLE: str = Path(sys.executable).as_posix() +codeflash_cache_dir: Path = Path(user_config_dir(appname="codeflash", appauthor="codeflash-ai", ensure_exists=True)) -class Compat: - # os-independent newline - LF: str = os.linesep +codeflash_temp_dir: Path = Path(tempfile.gettempdir()) / "codeflash" +codeflash_temp_dir.mkdir(parents=True, exist_ok=True) - SAFE_SYS_EXECUTABLE: str = Path(sys.executable).as_posix() - - IS_POSIX: bool = os.name != "nt" - - @property - def codeflash_cache_dir(self) -> Path: - return Path(user_config_dir(appname="codeflash", appauthor="codeflash-ai", ensure_exists=True)) - - @property - def codeflash_temp_dir(self) -> Path: - temp_dir = Path(tempfile.gettempdir()) / "codeflash" - if not temp_dir.exists(): - temp_dir.mkdir(parents=True, exist_ok=True) - return temp_dir - - @property - def codeflash_cache_db(self) -> Path: - return self.codeflash_cache_dir / "codeflash_cache.db" - - -_compat = Compat() - - -codeflash_temp_dir = _compat.codeflash_temp_dir -codeflash_cache_dir = _compat.codeflash_cache_dir -codeflash_cache_db = _compat.codeflash_cache_db -LF = _compat.LF -SAFE_SYS_EXECUTABLE = _compat.SAFE_SYS_EXECUTABLE -IS_POSIX = _compat.IS_POSIX +codeflash_cache_db: Path = codeflash_cache_dir / "codeflash_cache.db" From 8555da065a7906a3c9ea2b40adc901dc9dc913cc Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Thu, 12 Feb 2026 05:48:27 +0000 Subject: [PATCH 017/100] fix: resolve mypy type errors in call_graph.py --- codeflash/languages/python/call_graph.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/codeflash/languages/python/call_graph.py b/codeflash/languages/python/call_graph.py index 7d331d252..bf4483d90 100644 --- a/codeflash/languages/python/call_graph.py +++ b/codeflash/languages/python/call_graph.py @@ -47,7 +47,8 @@ def _resolve_definitions(ref: Name) -> list[Name]: pass try: - return ref.goto(follow_imports=True, follow_builtin_imports=False) + result: list[Name] = ref.goto(follow_imports=True, follow_builtin_imports=False) + return result except Exception: return [] @@ -111,7 +112,7 @@ def _analyze_file(file_path: Path, jedi_project: object, project_root_str: str) except Exception: return set(), True - edges: set[tuple[str, str, str, str, str, str, str, str]] = set() + edges: set[tuple[str, ...]] = set() for ref in refs: try: @@ -170,6 +171,7 @@ def _analyze_file(file_path: Path, jedi_project: object, project_root_str: str) def _index_file_worker(args: tuple[str, str]) -> tuple[str, str, set[tuple[str, ...]], bool]: """Worker entry point for ProcessPoolExecutor.""" file_path_str, file_hash = args + assert _worker_project_root_str is not None edges, had_error = _analyze_file(Path(file_path_str), _worker_jedi_project, _worker_project_root_str) return file_path_str, file_hash, edges, had_error From 513e590b8b13562d40f41b037b4914d7d3eea0ba Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 12 Feb 2026 01:00:53 -0500 Subject: [PATCH 018/100] fix: revert token limits back to 16K from unintended 100K increase --- codeflash/code_utils/config_consts.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codeflash/code_utils/config_consts.py b/codeflash/code_utils/config_consts.py index 32e5c7c54..e344fad8a 100644 --- a/codeflash/code_utils/config_consts.py +++ b/codeflash/code_utils/config_consts.py @@ -4,8 +4,8 @@ from typing import Any, Union MAX_TEST_RUN_ITERATIONS = 5 -OPTIMIZATION_CONTEXT_TOKEN_LIMIT = 100000 -TESTGEN_CONTEXT_TOKEN_LIMIT = 100000 +OPTIMIZATION_CONTEXT_TOKEN_LIMIT = 16000 +TESTGEN_CONTEXT_TOKEN_LIMIT = 16000 INDIVIDUAL_TESTCASE_TIMEOUT = 15 MAX_FUNCTION_TEST_SECONDS = 60 MIN_IMPROVEMENT_THRESHOLD = 0.05 From be4a2ca09ef56b56029bb7bb475c4b08c829c2d9 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 12 Feb 2026 01:01:45 -0500 Subject: [PATCH 019/100] feat: increase optimization and testgen token limits to 64K --- codeflash/code_utils/config_consts.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codeflash/code_utils/config_consts.py b/codeflash/code_utils/config_consts.py index e344fad8a..7fd8814d6 100644 --- a/codeflash/code_utils/config_consts.py +++ b/codeflash/code_utils/config_consts.py @@ -4,8 +4,8 @@ from typing import Any, Union MAX_TEST_RUN_ITERATIONS = 5 -OPTIMIZATION_CONTEXT_TOKEN_LIMIT = 16000 -TESTGEN_CONTEXT_TOKEN_LIMIT = 16000 +OPTIMIZATION_CONTEXT_TOKEN_LIMIT = 64000 +TESTGEN_CONTEXT_TOKEN_LIMIT = 64000 INDIVIDUAL_TESTCASE_TIMEOUT = 15 MAX_FUNCTION_TEST_SECONDS = 60 MIN_IMPROVEMENT_THRESHOLD = 0.05 From 9e904483d85b19b5a544a53bfb43f28da372461a Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 12 Feb 2026 01:02:21 -0500 Subject: [PATCH 020/100] fix: use explicit token limits in tests to decouple from global constant --- tests/test_code_context_extractor.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_code_context_extractor.py b/tests/test_code_context_extractor.py index c5009b898..f40ab1c8f 100644 --- a/tests/test_code_context_extractor.py +++ b/tests/test_code_context_extractor.py @@ -813,7 +813,7 @@ def helper_method(self): ending_line=None, ) - code_ctx = get_code_optimization_context(function_to_optimize, opt.args.project_root) + code_ctx = get_code_optimization_context(function_to_optimize, opt.args.project_root, optim_token_limit=16000) read_write_context, read_only_context = code_ctx.read_writable_code, code_ctx.read_only_context_code hashing_context = code_ctx.hashing_code_context # In this scenario, the read-only code context is too long, so the read-only docstrings are removed. @@ -1006,7 +1006,7 @@ def helper_method(self): ) # In this scenario, the read-writable code is too long, so we abort. with pytest.raises(ValueError, match="Read-writable code has exceeded token limit, cannot proceed"): - code_ctx = get_code_optimization_context(function_to_optimize, opt.args.project_root) + code_ctx = get_code_optimization_context(function_to_optimize, opt.args.project_root, optim_token_limit=16000) def test_example_class_token_limit_4(tmp_path: Path) -> None: @@ -1059,7 +1059,7 @@ def helper_method(self): # In this scenario, the read-writable code context becomes too large because the __init__ function is referencing the global x variable instead of the class attribute self.x, so we abort. with pytest.raises(ValueError, match="Read-writable code has exceeded token limit, cannot proceed"): - code_ctx = get_code_optimization_context(function_to_optimize, opt.args.project_root) + code_ctx = get_code_optimization_context(function_to_optimize, opt.args.project_root, optim_token_limit=16000) def test_example_class_token_limit_5(tmp_path: Path) -> None: From fc42548f9f49870864e54effd7395826206bce25 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 12 Feb 2026 01:03:34 -0500 Subject: [PATCH 021/100] test: update token limit tests for 64K default --- tests/test_code_context_extractor.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test_code_context_extractor.py b/tests/test_code_context_extractor.py index f40ab1c8f..6f8cd77cd 100644 --- a/tests/test_code_context_extractor.py +++ b/tests/test_code_context_extractor.py @@ -768,7 +768,7 @@ def helper_method(self): def test_example_class_token_limit_1(tmp_path: Path) -> None: docstring_filler = " ".join( - ["This is a long docstring that will be used to fill up the token limit." for _ in range(1000)] + ["This is a long docstring that will be used to fill up the token limit." for _ in range(4000)] ) code = f""" class MyClass: @@ -813,7 +813,7 @@ def helper_method(self): ending_line=None, ) - code_ctx = get_code_optimization_context(function_to_optimize, opt.args.project_root, optim_token_limit=16000) + code_ctx = get_code_optimization_context(function_to_optimize, opt.args.project_root) read_write_context, read_only_context = code_ctx.read_writable_code, code_ctx.read_only_context_code hashing_context = code_ctx.hashing_code_context # In this scenario, the read-only code context is too long, so the read-only docstrings are removed. @@ -961,7 +961,7 @@ def helper_method(self): def test_example_class_token_limit_3(tmp_path: Path) -> None: string_filler = " ".join( - ["This is a long string that will be used to fill up the token limit." for _ in range(1000)] + ["This is a long string that will be used to fill up the token limit." for _ in range(4000)] ) code = f""" class MyClass: @@ -1006,12 +1006,12 @@ def helper_method(self): ) # In this scenario, the read-writable code is too long, so we abort. with pytest.raises(ValueError, match="Read-writable code has exceeded token limit, cannot proceed"): - code_ctx = get_code_optimization_context(function_to_optimize, opt.args.project_root, optim_token_limit=16000) + code_ctx = get_code_optimization_context(function_to_optimize, opt.args.project_root) def test_example_class_token_limit_4(tmp_path: Path) -> None: string_filler = " ".join( - ["This is a long string that will be used to fill up the token limit." for _ in range(1000)] + ["This is a long string that will be used to fill up the token limit." for _ in range(4000)] ) code = f""" class MyClass: @@ -1059,7 +1059,7 @@ def helper_method(self): # In this scenario, the read-writable code context becomes too large because the __init__ function is referencing the global x variable instead of the class attribute self.x, so we abort. with pytest.raises(ValueError, match="Read-writable code has exceeded token limit, cannot proceed"): - code_ctx = get_code_optimization_context(function_to_optimize, opt.args.project_root, optim_token_limit=16000) + code_ctx = get_code_optimization_context(function_to_optimize, opt.args.project_root) def test_example_class_token_limit_5(tmp_path: Path) -> None: From 80759c905e085fddb98e06c21165baede218ec55 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 12 Feb 2026 01:05:49 -0500 Subject: [PATCH 022/100] fix: add None guard for lang_support before accessing file_extensions --- codeflash/optimization/optimizer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codeflash/optimization/optimizer.py b/codeflash/optimization/optimizer.py index 810c1758b..b22f0df9c 100644 --- a/codeflash/optimization/optimizer.py +++ b/codeflash/optimization/optimizer.py @@ -537,7 +537,7 @@ def run(self) -> None: if lang_support and not env_utils.is_ci(): resolver = lang_support.create_dependency_resolver(self.args.project_root) - if resolver is not None and file_to_funcs_to_optimize: + if resolver is not None and lang_support is not None and file_to_funcs_to_optimize: supported_exts = lang_support.file_extensions source_files = [f for f in file_to_funcs_to_optimize if f.suffix in supported_exts] with call_graph_live_display(len(source_files), project_root=self.args.project_root) as on_progress: From d7edef82b7d91c9eef8d88bbe8bc6aff6245a552 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 12 Feb 2026 01:07:41 -0500 Subject: [PATCH 023/100] refactor: batch callee counting in call_graph_summary with new count_callees_per_function method --- codeflash/cli_cmds/console.py | 14 ++++++------- codeflash/languages/base.py | 6 ++++++ codeflash/languages/python/call_graph.py | 26 ++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/codeflash/cli_cmds/console.py b/codeflash/cli_cmds/console.py index 3e1aa64d7..ddfa04771 100644 --- a/codeflash/cli_cmds/console.py +++ b/codeflash/cli_cmds/console.py @@ -327,13 +327,13 @@ def call_graph_summary(call_graph: DependencyResolver, file_to_funcs: dict[Path, total_callees = 0 with_context = 0 - for file_path, funcs in file_to_funcs.items(): - for func in funcs: - _, func_callees = call_graph.get_callees({file_path: {func.qualified_name}}) - callee_count = len(func_callees) - total_callees += callee_count - if callee_count > 0: - with_context += 1 + callee_counts = call_graph.count_callees_per_function( + {file_path: {func.qualified_name for func in funcs} for file_path, funcs in file_to_funcs.items()} + ) + for count in callee_counts.values(): + total_callees += count + if count > 0: + with_context += 1 leaf_functions = total_functions - with_context avg_callees = total_callees / total_functions diff --git a/codeflash/languages/base.py b/codeflash/languages/base.py index 76357a4d1..1e2254b1d 100644 --- a/codeflash/languages/base.py +++ b/codeflash/languages/base.py @@ -221,6 +221,12 @@ def get_callees( """Return callees for the given functions.""" ... + def count_callees_per_function( + self, file_path_to_qualified_names: dict[Path, set[str]] + ) -> dict[str, int]: + """Return the number of callees for each caller qualified name.""" + ... + def close(self) -> None: """Release resources (e.g. database connections).""" ... diff --git a/codeflash/languages/python/call_graph.py b/codeflash/languages/python/call_graph.py index bf4483d90..aea6d696a 100644 --- a/codeflash/languages/python/call_graph.py +++ b/codeflash/languages/python/call_graph.py @@ -302,6 +302,32 @@ def get_callees( return file_path_to_function_source, function_source_list + def count_callees_per_function( + self, file_path_to_qualified_names: dict[Path, set[str]] + ) -> dict[str, int]: + all_caller_keys: list[tuple[str, str]] = [] + for file_path, qualified_names in file_path_to_qualified_names.items(): + self.ensure_file_indexed(file_path) + resolved = str(file_path.resolve()) + all_caller_keys.extend((resolved, qn) for qn in qualified_names) + + if not all_caller_keys: + return {} + + counts: dict[str, int] = {} + cur = self.conn.cursor() + for caller_file, caller_qn in all_caller_keys: + row = cur.execute( + """ + SELECT COUNT(*) FROM call_edges + WHERE project_root = ? AND language = ? AND caller_file = ? AND caller_qualified_name = ? + """, + (self.project_root_str, self.language, caller_file, caller_qn), + ).fetchone() + counts[caller_qn] = row[0] if row else 0 + + return counts + def ensure_file_indexed(self, file_path: Path) -> IndexResult: resolved = str(file_path.resolve()) From c3fdf31a96affa86dd40f86b28c03732022e2a24 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 12 Feb 2026 01:11:39 -0500 Subject: [PATCH 024/100] refactor: use batch count_callees_per_function for dependency ranking and summary --- codeflash/languages/base.py | 4 +-- codeflash/languages/python/call_graph.py | 4 +-- codeflash/optimization/optimizer.py | 14 +++++----- tests/test_call_graph.py | 33 ++++++++++++++++++++++++ 4 files changed, 42 insertions(+), 13 deletions(-) diff --git a/codeflash/languages/base.py b/codeflash/languages/base.py index 1e2254b1d..7e7f5f127 100644 --- a/codeflash/languages/base.py +++ b/codeflash/languages/base.py @@ -221,9 +221,7 @@ def get_callees( """Return callees for the given functions.""" ... - def count_callees_per_function( - self, file_path_to_qualified_names: dict[Path, set[str]] - ) -> dict[str, int]: + def count_callees_per_function(self, file_path_to_qualified_names: dict[Path, set[str]]) -> dict[str, int]: """Return the number of callees for each caller qualified name.""" ... diff --git a/codeflash/languages/python/call_graph.py b/codeflash/languages/python/call_graph.py index aea6d696a..5dfa2d330 100644 --- a/codeflash/languages/python/call_graph.py +++ b/codeflash/languages/python/call_graph.py @@ -302,9 +302,7 @@ def get_callees( return file_path_to_function_source, function_source_list - def count_callees_per_function( - self, file_path_to_qualified_names: dict[Path, set[str]] - ) -> dict[str, int]: + def count_callees_per_function(self, file_path_to_qualified_names: dict[Path, set[str]]) -> dict[str, int]: all_caller_keys: list[tuple[str, str]] = [] for file_path, qualified_names in file_path_to_qualified_names.items(): self.ensure_file_indexed(file_path) diff --git a/codeflash/optimization/optimizer.py b/codeflash/optimization/optimizer.py index b22f0df9c..89530ebf3 100644 --- a/codeflash/optimization/optimizer.py +++ b/codeflash/optimization/optimizer.py @@ -469,13 +469,13 @@ def rank_all_functions_globally( def rank_by_dependency_count( self, all_functions: list[tuple[Path, FunctionToOptimize]], call_graph: DependencyResolver ) -> list[tuple[Path, FunctionToOptimize]]: - counts: list[tuple[int, int, tuple[Path, FunctionToOptimize]]] = [] - for idx, (file_path, func) in enumerate(all_functions): - _, callee_list = call_graph.get_callees({file_path: {func.qualified_name}}) - counts.append((len(callee_list), idx, (file_path, func))) - counts.sort(key=lambda x: (-x[0], x[1])) - logger.debug(f"Ranked {len(counts)} functions by dependency count (most complex first)") - return [item for _, _, item in counts] + file_to_qns: dict[Path, set[str]] = defaultdict(set) + for file_path, func in all_functions: + file_to_qns[file_path].add(func.qualified_name) + callee_counts = call_graph.count_callees_per_function(dict(file_to_qns)) + ranked = sorted(enumerate(all_functions), key=lambda x: (-callee_counts.get(x[1][1].qualified_name, 0), x[0])) + logger.debug(f"Ranked {len(ranked)} functions by dependency count (most complex first)") + return [item for _, item in ranked] def run(self) -> None: from codeflash.code_utils.checkpoint import CodeflashRunCheckpoint diff --git a/tests/test_call_graph.py b/tests/test_call_graph.py index 22c306055..d2fcc104f 100644 --- a/tests/test_call_graph.py +++ b/tests/test_call_graph.py @@ -414,6 +414,39 @@ def caller(): cg.close() +def test_count_callees_per_function(project: Path, db_path: Path) -> None: + write_file( + project, + "mod.py", + """\ +def helper_a(): + return 1 + +def helper_b(): + return 2 + +def caller_one(): + return helper_a() + helper_b() + +def caller_two(): + return helper_a() + +def leaf(): + return 42 +""", + ) + + cg = CallGraph(project, db_path=db_path) + try: + cg.build_index([project / "mod.py"]) + counts = cg.count_callees_per_function({project / "mod.py": {"caller_one", "caller_two", "leaf"}}) + assert counts["caller_one"] == 2 + assert counts["caller_two"] == 1 + assert counts["leaf"] == 0 + finally: + cg.close() + + def test_same_file_edges_not_cross_file(project: Path, db_path: Path) -> None: write_file( project, From 457278331d455ae7a7e8566a71025d04d16969d1 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 12 Feb 2026 01:14:36 -0500 Subject: [PATCH 025/100] fix: remove slots=True from dataclass for Python 3.9 compatibility --- codeflash/languages/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codeflash/languages/base.py b/codeflash/languages/base.py index 7e7f5f127..b300b1950 100644 --- a/codeflash/languages/base.py +++ b/codeflash/languages/base.py @@ -35,7 +35,7 @@ def __getattr__(name: str) -> Any: raise AttributeError(msg) -@dataclass(frozen=True, slots=True) +@dataclass(frozen=True) class IndexResult: file_path: Path cached: bool From 267dff9702c746dd6b9130bc73bfe93816702322 Mon Sep 17 00:00:00 2001 From: "codeflash-ai[bot]" <148906541+codeflash-ai[bot]@users.noreply.github.com> Date: Thu, 12 Feb 2026 06:40:52 +0000 Subject: [PATCH 026/100] Optimize call_graph_summary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The optimized code achieves a **151% speedup** (from 7.86 to 3.12 microseconds) primarily through three key optimizations: ## 1. Module-Level Import Hoisting Moving `from rich.panel import Panel` from inside `call_graph_summary()` to the top-level module imports eliminates repeated import overhead on every function call. The line profiler shows this import took ~30,000 ns in the original (0.5% of total time). While seemingly small, this overhead is completely eliminated in the optimized version. ## 2. C-Level Aggregation with Built-in `sum()` The optimization replaces Python-level accumulation loops with native `sum()` calls that execute at C speed: **Original approach** (manual accumulation): ```python total_callees = 0 with_context = 0 for count in callee_counts.values(): total_callees += count if count > 0: with_context += 1 ``` This loop incurred ~828,000 ns across 2,005 iterations (234,973 + 301,448 + 292,402 ns). **Optimized approach** (C-level sum): ```python total_callees = sum(callee_counts.values()) with_context = sum(1 for count in callee_counts.values() if count > 0) ``` The new approach completes in ~405,000 ns total (16,399 + 389,145 ns) - nearly **2x faster** for the aggregation logic alone. ## 3. Leveraging `map()` for Initial Summation Using `sum(map(len, file_to_funcs.values()))` instead of a generator expression provides a minor efficiency gain by pushing the iteration into C-level code, though the improvement here is marginal (34,533 ns → 24,396 ns). ## Performance Characteristics Based on the annotated tests, these optimizations excel when: - **Large-scale scenarios**: The `test_large_scale_many_functions_single_file` (1000 functions) and `test_large_scale_multiple_files_distribution` (1000 functions across 10 files) benefit most from reduced per-iteration overhead - **Frequent invocations**: If `call_graph_summary()` is called multiple times in a session, the eliminated import overhead compounds savings - **Non-empty function sets**: The optimization's impact is proportional to the number of callees being aggregated The changes preserve all behavior - same summary text, same Panel display, same LSP handling - while delivering substantial runtime improvements through strategic use of Python's built-in functions that leverage optimized C implementations. --- codeflash/cli_cmds/console.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/codeflash/cli_cmds/console.py b/codeflash/cli_cmds/console.py index ddfa04771..bed8bc6c3 100644 --- a/codeflash/cli_cmds/console.py +++ b/codeflash/cli_cmds/console.py @@ -23,6 +23,7 @@ from codeflash.lsp.helpers import is_LSP_enabled from codeflash.lsp.lsp_logger import enhanced_log from codeflash.lsp.lsp_message import LspCodeMessage, LspTextMessage +from rich.panel import Panel if TYPE_CHECKING: from collections.abc import Callable, Generator @@ -318,22 +319,20 @@ def update(result: IndexResult) -> None: def call_graph_summary(call_graph: DependencyResolver, file_to_funcs: dict[Path, list[FunctionToOptimize]]) -> None: - from rich.panel import Panel - - total_functions = sum(len(funcs) for funcs in file_to_funcs.values()) + total_functions = sum(map(len, file_to_funcs.values())) if not total_functions: return - total_callees = 0 - with_context = 0 + # Build the mapping expected by the dependency resolver + file_items = file_to_funcs.items() + mapping = {file_path: {func.qualified_name for func in funcs} for file_path, funcs in file_items} + + callee_counts = call_graph.count_callees_per_function(mapping) + + # Use built-in sum for C-level loops to reduce Python overhead + total_callees = sum(callee_counts.values()) + with_context = sum(1 for count in callee_counts.values() if count > 0) - callee_counts = call_graph.count_callees_per_function( - {file_path: {func.qualified_name for func in funcs} for file_path, funcs in file_to_funcs.items()} - ) - for count in callee_counts.values(): - total_callees += count - if count > 0: - with_context += 1 leaf_functions = total_functions - with_context avg_callees = total_callees / total_functions From 182c1b002dd79fc9be55daebb53386d1aedabc6d Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Thu, 12 Feb 2026 06:43:39 +0000 Subject: [PATCH 027/100] style: auto-fix linting issues --- codeflash/cli_cmds/console.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/codeflash/cli_cmds/console.py b/codeflash/cli_cmds/console.py index bed8bc6c3..305ad458b 100644 --- a/codeflash/cli_cmds/console.py +++ b/codeflash/cli_cmds/console.py @@ -8,6 +8,7 @@ from rich.console import Console from rich.logging import RichHandler +from rich.panel import Panel from rich.progress import ( BarColumn, MofNCompleteColumn, @@ -23,7 +24,6 @@ from codeflash.lsp.helpers import is_LSP_enabled from codeflash.lsp.lsp_logger import enhanced_log from codeflash.lsp.lsp_message import LspCodeMessage, LspTextMessage -from rich.panel import Panel if TYPE_CHECKING: from collections.abc import Callable, Generator @@ -333,7 +333,6 @@ def call_graph_summary(call_graph: DependencyResolver, file_to_funcs: dict[Path, total_callees = sum(callee_counts.values()) with_context = sum(1 for count in callee_counts.values() if count > 0) - leaf_functions = total_functions - with_context avg_callees = total_callees / total_functions From 4523ac2d0c12842e32331a678cea5b4b05e3065b Mon Sep 17 00:00:00 2001 From: "codeflash-ai[bot]" <148906541+codeflash-ai[bot]@users.noreply.github.com> Date: Thu, 12 Feb 2026 07:03:35 +0000 Subject: [PATCH 028/100] Optimize _analyze_imports_in_optimized_code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The optimized code achieves a **38% runtime improvement** (10.3ms → 7.42ms) by replacing the inefficient `ast.walk()` traversal with a targeted `ast.NodeVisitor` pattern. **Key Optimization:** The original code used `ast.walk(optimized_ast)` which visits **every node in the AST** (4,466 nodes in the profiled example), performing `isinstance()` checks on each one to find Import/ImportFrom nodes. This resulted in 18.77ms spent just traversing the tree (46.9% of total runtime). The optimized version introduces an `_ImportCollector` class that uses Python's `ast.NodeVisitor` pattern to selectively visit only Import and ImportFrom nodes. By defining `visit_Import()` and `visit_ImportFrom()` methods, the collector automatically skips irrelevant nodes during traversal. This reduces the collection phase to just 2.88ms (12% of runtime), saving approximately 15.89ms. **Performance Profile:** - The line profiler shows the `collector.visit()` call takes 2.88ms vs. the original loop's 18.77ms - The subsequent processing loop over collected nodes runs faster (1.69k iterations vs. 4.42k), eliminating 62% of unnecessary `isinstance()` checks - All other operations (helper preprocessing, dictionary lookups, set operations) remain essentially unchanged **Test Case Behavior:** The optimization is most effective for: - **Large ASTs with many nodes**: The `test_large_scale_many_import_statements_with_helpers` shows 62.6% speedup (662μs → 407μs) when processing 200 import statements, demonstrating the benefit of selective traversal - **Complex code with deep nesting**: ASTs with more non-import nodes see greater relative gains Smaller test cases show 30-40% slower runtimes due to the overhead of instantiating the collector class, but these are measuring microsecond differences (8-25μs) that are negligible in real-world usage where the function processes larger ASTs. **Practical Impact:** This function analyzes import statements in optimized code to map names to helper functions. Given its role in code optimization workflows, it likely processes many ASTs repeatedly. The 38% runtime reduction directly improves the optimization pipeline's throughput, especially when analyzing codebases with numerous import statements. --- .../context/unused_definition_remover.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/codeflash/context/unused_definition_remover.py b/codeflash/context/unused_definition_remover.py index 00b077f63..9883b8e84 100644 --- a/codeflash/context/unused_definition_remover.py +++ b/codeflash/context/unused_definition_remover.py @@ -638,7 +638,23 @@ def _analyze_imports_in_optimized_code( helpers_by_file_and_func[module_name].setdefault(func_name, []).append(helper) helpers_by_file[module_name].append(helper) - for node in ast.walk(optimized_ast): + # Collect only import nodes to avoid per-node isinstance checks across the whole AST + class _ImportCollector(ast.NodeVisitor): + def __init__(self) -> None: + self.nodes: list[ast.AST] = [] + + def visit_Import(self, node: ast.Import) -> None: + self.nodes.append(node) + # No need to recurse further for import nodes + + def visit_ImportFrom(self, node: ast.ImportFrom) -> None: + self.nodes.append(node) + # No need to recurse further for import-from nodes + + collector = _ImportCollector() + collector.visit(optimized_ast) + + for node in collector.nodes: if isinstance(node, ast.ImportFrom): # Handle "from module import function" statements module_name = node.module @@ -655,6 +671,7 @@ def _analyze_imports_in_optimized_code( imported_set.add(helper.qualified_name) imported_set.add(helper.fully_qualified_name) + elif isinstance(node, ast.Import): # Handle "import module" statements for alias in node.names: From 0e284ad1803c042cc4c8538c0e8365eb61cd1405 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Thu, 12 Feb 2026 07:06:28 +0000 Subject: [PATCH 029/100] style: auto-fix linting issues --- codeflash/context/unused_definition_remover.py | 1 - 1 file changed, 1 deletion(-) diff --git a/codeflash/context/unused_definition_remover.py b/codeflash/context/unused_definition_remover.py index 9883b8e84..3547623ae 100644 --- a/codeflash/context/unused_definition_remover.py +++ b/codeflash/context/unused_definition_remover.py @@ -671,7 +671,6 @@ def visit_ImportFrom(self, node: ast.ImportFrom) -> None: imported_set.add(helper.qualified_name) imported_set.add(helper.fully_qualified_name) - elif isinstance(node, ast.Import): # Handle "import module" statements for alias in node.names: From 11543f0d0b1ee93ec5c56a24032d991a23250515 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Mon, 16 Feb 2026 23:03:05 -0500 Subject: [PATCH 030/100] fix: use (file_path, qualified_name) key in count_callees_per_function Bare qualified_name keys could collide across files (e.g. `helper` in both a.py and b.py), causing counts to be silently overwritten. --- codeflash/languages/base.py | 6 ++++-- codeflash/languages/python/call_graph.py | 14 ++++++++------ codeflash/optimization/optimizer.py | 4 +++- tests/test_call_graph.py | 9 +++++---- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/codeflash/languages/base.py b/codeflash/languages/base.py index 480ea01c1..edbfe1eae 100644 --- a/codeflash/languages/base.py +++ b/codeflash/languages/base.py @@ -221,8 +221,10 @@ def get_callees( """Return callees for the given functions.""" ... - def count_callees_per_function(self, file_path_to_qualified_names: dict[Path, set[str]]) -> dict[str, int]: - """Return the number of callees for each caller qualified name.""" + def count_callees_per_function( + self, file_path_to_qualified_names: dict[Path, set[str]] + ) -> dict[tuple[Path, str], int]: + """Return the number of callees for each (file_path, qualified_name) pair.""" ... def close(self) -> None: diff --git a/codeflash/languages/python/call_graph.py b/codeflash/languages/python/call_graph.py index 5dfa2d330..8d99a26bd 100644 --- a/codeflash/languages/python/call_graph.py +++ b/codeflash/languages/python/call_graph.py @@ -302,19 +302,21 @@ def get_callees( return file_path_to_function_source, function_source_list - def count_callees_per_function(self, file_path_to_qualified_names: dict[Path, set[str]]) -> dict[str, int]: - all_caller_keys: list[tuple[str, str]] = [] + def count_callees_per_function( + self, file_path_to_qualified_names: dict[Path, set[str]] + ) -> dict[tuple[Path, str], int]: + all_caller_keys: list[tuple[Path, str, str]] = [] for file_path, qualified_names in file_path_to_qualified_names.items(): self.ensure_file_indexed(file_path) resolved = str(file_path.resolve()) - all_caller_keys.extend((resolved, qn) for qn in qualified_names) + all_caller_keys.extend((file_path, resolved, qn) for qn in qualified_names) if not all_caller_keys: return {} - counts: dict[str, int] = {} + counts: dict[tuple[Path, str], int] = {} cur = self.conn.cursor() - for caller_file, caller_qn in all_caller_keys: + for orig_path, caller_file, caller_qn in all_caller_keys: row = cur.execute( """ SELECT COUNT(*) FROM call_edges @@ -322,7 +324,7 @@ def count_callees_per_function(self, file_path_to_qualified_names: dict[Path, se """, (self.project_root_str, self.language, caller_file, caller_qn), ).fetchone() - counts[caller_qn] = row[0] if row else 0 + counts[(orig_path, caller_qn)] = row[0] if row else 0 return counts diff --git a/codeflash/optimization/optimizer.py b/codeflash/optimization/optimizer.py index 89530ebf3..682e8bb36 100644 --- a/codeflash/optimization/optimizer.py +++ b/codeflash/optimization/optimizer.py @@ -473,7 +473,9 @@ def rank_by_dependency_count( for file_path, func in all_functions: file_to_qns[file_path].add(func.qualified_name) callee_counts = call_graph.count_callees_per_function(dict(file_to_qns)) - ranked = sorted(enumerate(all_functions), key=lambda x: (-callee_counts.get(x[1][1].qualified_name, 0), x[0])) + ranked = sorted( + enumerate(all_functions), key=lambda x: (-callee_counts.get((x[1][0], x[1][1].qualified_name), 0), x[0]) + ) logger.debug(f"Ranked {len(ranked)} functions by dependency count (most complex first)") return [item for _, item in ranked] diff --git a/tests/test_call_graph.py b/tests/test_call_graph.py index d2fcc104f..9dda10e97 100644 --- a/tests/test_call_graph.py +++ b/tests/test_call_graph.py @@ -439,10 +439,11 @@ def leaf(): cg = CallGraph(project, db_path=db_path) try: cg.build_index([project / "mod.py"]) - counts = cg.count_callees_per_function({project / "mod.py": {"caller_one", "caller_two", "leaf"}}) - assert counts["caller_one"] == 2 - assert counts["caller_two"] == 1 - assert counts["leaf"] == 0 + mod_path = project / "mod.py" + counts = cg.count_callees_per_function({mod_path: {"caller_one", "caller_two", "leaf"}}) + assert counts[(mod_path, "caller_one")] == 2 + assert counts[(mod_path, "caller_two")] == 1 + assert counts[(mod_path, "leaf")] == 0 finally: cg.close() From 43d74a8f9e436d5791696586ea236c75692be280 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 18 Feb 2026 17:10:32 -0500 Subject: [PATCH 031/100] fix: use iterative DFS for function discovery to avoid RecursionError Deeply nested expression trees (e.g. large dict/list literals) at module or class level caused the recursive ast.NodeVisitor to exceed Python's default recursion limit. Replace the FunctionWithReturnStatement visitor class with an iterative stack-based traversal. --- codeflash/discovery/functions_to_optimize.py | 56 ++++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/codeflash/discovery/functions_to_optimize.py b/codeflash/discovery/functions_to_optimize.py index 86d574af1..5951b137b 100644 --- a/codeflash/discovery/functions_to_optimize.py +++ b/codeflash/discovery/functions_to_optimize.py @@ -114,32 +114,34 @@ def visit_FunctionDef(self, node: cst.FunctionDef) -> None: ) -class FunctionWithReturnStatement(ast.NodeVisitor): - def __init__(self, file_path: Path) -> None: - self.functions: list[FunctionToOptimize] = [] - self.ast_path: list[FunctionParent] = [] - self.file_path: Path = file_path - - def visit_FunctionDef(self, node: FunctionDef) -> None: - if function_has_return_statement(node) and not function_is_a_property(node): - self.functions.append( - FunctionToOptimize(function_name=node.name, file_path=self.file_path, parents=self.ast_path[:]) - ) - - def visit_AsyncFunctionDef(self, node: AsyncFunctionDef) -> None: - if function_has_return_statement(node) and not function_is_a_property(node): - self.functions.append( - FunctionToOptimize( - function_name=node.name, file_path=self.file_path, parents=self.ast_path[:], is_async=True +def find_functions_with_return_statement( + ast_module: ast.Module, file_path: Path +) -> list[FunctionToOptimize]: + results: list[FunctionToOptimize] = [] + # (node, parent_path) — iterative DFS avoids RecursionError on deeply nested ASTs + stack: list[tuple[ast.AST, list[FunctionParent]]] = [(ast_module, [])] + while stack: + node, ast_path = stack.pop() + if isinstance(node, (FunctionDef, AsyncFunctionDef)): + if function_has_return_statement(node) and not function_is_a_property(node): + results.append( + FunctionToOptimize( + function_name=node.name, + file_path=file_path, + parents=ast_path[:], + is_async=isinstance(node, AsyncFunctionDef), + ) ) - ) - - def generic_visit(self, node: ast.AST) -> None: - if isinstance(node, (FunctionDef, AsyncFunctionDef, ClassDef)): - self.ast_path.append(FunctionParent(node.name, node.__class__.__name__)) - super().generic_visit(node) - if isinstance(node, (FunctionDef, AsyncFunctionDef, ClassDef)): - self.ast_path.pop() + # Don't recurse into function bodies (matches original visitor behaviour) + continue + child_path = ( + ast_path + [FunctionParent(node.name, node.__class__.__name__)] + if isinstance(node, ClassDef) + else ast_path + ) + for child in reversed(list(ast.iter_child_nodes(node))): + stack.append((child, child_path)) + return results # ============================================================================= @@ -237,9 +239,7 @@ def _find_all_functions_in_python_file(file_path: Path) -> dict[Path, list[Funct if DEBUG_MODE: logger.exception(e) return functions - function_name_visitor = FunctionWithReturnStatement(file_path) - function_name_visitor.visit(ast_module) - functions[file_path] = function_name_visitor.functions + functions[file_path] = find_functions_with_return_statement(ast_module, file_path) return functions From 5663985712a264833fce8abae2205f68c98c9502 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Wed, 18 Feb 2026 22:13:57 +0000 Subject: [PATCH 032/100] style: auto-fix linting issues --- codeflash/discovery/functions_to_optimize.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/codeflash/discovery/functions_to_optimize.py b/codeflash/discovery/functions_to_optimize.py index 5951b137b..8821e0e9a 100644 --- a/codeflash/discovery/functions_to_optimize.py +++ b/codeflash/discovery/functions_to_optimize.py @@ -114,9 +114,7 @@ def visit_FunctionDef(self, node: cst.FunctionDef) -> None: ) -def find_functions_with_return_statement( - ast_module: ast.Module, file_path: Path -) -> list[FunctionToOptimize]: +def find_functions_with_return_statement(ast_module: ast.Module, file_path: Path) -> list[FunctionToOptimize]: results: list[FunctionToOptimize] = [] # (node, parent_path) — iterative DFS avoids RecursionError on deeply nested ASTs stack: list[tuple[ast.AST, list[FunctionParent]]] = [(ast_module, [])] @@ -135,9 +133,7 @@ def find_functions_with_return_statement( # Don't recurse into function bodies (matches original visitor behaviour) continue child_path = ( - ast_path + [FunctionParent(node.name, node.__class__.__name__)] - if isinstance(node, ClassDef) - else ast_path + [*ast_path, FunctionParent(node.name, node.__class__.__name__)] if isinstance(node, ClassDef) else ast_path ) for child in reversed(list(ast.iter_child_nodes(node))): stack.append((child, child_path)) From 890c466b1afd402568d36eef502a4b2d9592612b Mon Sep 17 00:00:00 2001 From: "codeflash-ai[bot]" <148906541+codeflash-ai[bot]@users.noreply.github.com> Date: Wed, 18 Feb 2026 22:22:40 +0000 Subject: [PATCH 033/100] Optimize find_functions_with_return_statement The optimized code achieves a **26% runtime improvement** by making the AST traversal in `function_has_return_statement` more targeted and efficient. **Key Optimization:** The critical change is in how `function_has_return_statement` traverses the AST when searching for `Return` nodes: **Original approach:** ```python stack.extend(ast.iter_child_nodes(node)) ``` This visits *all* child nodes including expressions, names, constants, and other non-statement nodes. **Optimized approach:** ```python for child in ast.iter_child_nodes(node): if isinstance(child, ast.stmt): stack.append(child) ``` This only pushes statement nodes onto the stack, since `Return` is a statement type (`ast.stmt`). **Why This Is Faster:** 1. **Reduced Node Traversal**: In typical Python functions, there are many more expression nodes (variable references, literals, operators, etc.) than statement nodes. For example, a simple `return x + y` has 1 Return statement but multiple Name and BinOp expression nodes underneath. The optimization skips all the expression-level nodes. 2. **Lower Python Overhead**: Fewer nodes in the stack means fewer loop iterations, fewer `isinstance` checks on non-Return nodes, and less list manipulation overhead. 3. **Preserved Correctness**: Since `Return` nodes are always statements in Python's AST (they inherit from `ast.stmt`), filtering to only statement nodes cannot miss any Return nodes. **Performance Impact by Test Case:** The optimization shows particularly strong gains for: - **Functions without returns** (up to 91% faster): Early termination without traversing deep expression trees - **Large codebases** (34-41% faster on tests with 1000+ functions): The cumulative effect across many function bodies - **Functions with complex expressions but no returns** (82% faster): Avoiding expensive traversal of unused expression subtrees - **Generator functions without explicit returns** (64% faster): Skipping yield expression internals The optimization maintains correctness across all test cases including nested classes, async functions, properties, and various control structures, while delivering consistent runtime improvements. --- codeflash/discovery/functions_to_optimize.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/codeflash/discovery/functions_to_optimize.py b/codeflash/discovery/functions_to_optimize.py index 8821e0e9a..bb8b2f902 100644 --- a/codeflash/discovery/functions_to_optimize.py +++ b/codeflash/discovery/functions_to_optimize.py @@ -961,7 +961,11 @@ def function_has_return_statement(function_node: FunctionDef | AsyncFunctionDef) node = stack.pop() if isinstance(node, ast.Return): return True - stack.extend(ast.iter_child_nodes(node)) + # Only push child nodes that are statements; Return nodes are statements, + # so this preserves correctness while avoiding unnecessary traversal into expr/Name/etc. + for child in ast.iter_child_nodes(node): + if isinstance(child, ast.stmt): + stack.append(child) return False From 88b0ee50cfef8273f8170ed0880e4cd8daccfb14 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 18 Feb 2026 17:24:39 -0500 Subject: [PATCH 034/100] fix: batch SQL queries and deduplicate Path.resolve() in call graph Replace per-function SQL loops in get_callees() and count_callees_per_function() with temp table JOINs, and thread resolved path strings through to avoid redundant resolve() calls. --- .codex/skills/.gitignore | 1 + .gemini/skills/.gitignore | 1 + codeflash/languages/python/call_graph.py | 108 +++++++++++++---------- 3 files changed, 65 insertions(+), 45 deletions(-) diff --git a/.codex/skills/.gitignore b/.codex/skills/.gitignore index b1cda282a..4e7af4bc6 100644 --- a/.codex/skills/.gitignore +++ b/.codex/skills/.gitignore @@ -1,2 +1,3 @@ # Managed by Tessl tessl:* +tessl__* diff --git a/.gemini/skills/.gitignore b/.gemini/skills/.gitignore index b1cda282a..4e7af4bc6 100644 --- a/.gemini/skills/.gitignore +++ b/.gemini/skills/.gitignore @@ -1,2 +1,3 @@ # Managed by Tessl tessl:* +tessl__* diff --git a/codeflash/languages/python/call_graph.py b/codeflash/languages/python/call_graph.py index 8d99a26bd..f9641d2e0 100644 --- a/codeflash/languages/python/call_graph.py +++ b/codeflash/languages/python/call_graph.py @@ -264,41 +264,44 @@ def get_callees( file_path_to_function_source: dict[Path, set[FunctionSource]] = defaultdict(set) function_source_list: list[FunctionSource] = [] - # Build list of all caller keys all_caller_keys: list[tuple[str, str]] = [] for file_path, qualified_names in file_path_to_qualified_names.items(): - self.ensure_file_indexed(file_path) resolved = str(file_path.resolve()) + self.ensure_file_indexed(file_path, resolved) all_caller_keys.extend((resolved, qn) for qn in qualified_names) if not all_caller_keys: return file_path_to_function_source, function_source_list - # Query all callees cur = self.conn.cursor() - for caller_file, caller_qn in all_caller_keys: - rows = cur.execute( - """ - SELECT callee_file, callee_qualified_name, callee_fully_qualified_name, - callee_only_function_name, callee_definition_type, callee_source_line - FROM call_edges - WHERE project_root = ? AND language = ? AND caller_file = ? AND caller_qualified_name = ? - """, - (self.project_root_str, self.language, caller_file, caller_qn), - ).fetchall() - - for callee_file, callee_qn, callee_fqn, callee_name, callee_type, callee_src in rows: - callee_path = Path(callee_file) - fs = FunctionSource( - file_path=callee_path, - qualified_name=callee_qn, - fully_qualified_name=callee_fqn, - only_function_name=callee_name, - source_code=callee_src, - definition_type=callee_type, - ) - file_path_to_function_source[callee_path].add(fs) - function_source_list.append(fs) + cur.execute("CREATE TEMP TABLE IF NOT EXISTS _caller_keys (caller_file TEXT, caller_qualified_name TEXT)") + cur.execute("DELETE FROM _caller_keys") + cur.executemany("INSERT INTO _caller_keys VALUES (?, ?)", all_caller_keys) + + rows = cur.execute( + """ + SELECT ce.callee_file, ce.callee_qualified_name, ce.callee_fully_qualified_name, + ce.callee_only_function_name, ce.callee_definition_type, ce.callee_source_line + FROM call_edges ce + INNER JOIN _caller_keys ck + ON ce.caller_file = ck.caller_file AND ce.caller_qualified_name = ck.caller_qualified_name + WHERE ce.project_root = ? AND ce.language = ? + """, + (self.project_root_str, self.language), + ).fetchall() + + for callee_file, callee_qn, callee_fqn, callee_name, callee_type, callee_src in rows: + callee_path = Path(callee_file) + fs = FunctionSource( + file_path=callee_path, + qualified_name=callee_qn, + fully_qualified_name=callee_fqn, + only_function_name=callee_name, + source_code=callee_src, + definition_type=callee_type, + ) + file_path_to_function_source[callee_path].add(fs) + function_source_list.append(fs) return file_path_to_function_source, function_source_list @@ -307,30 +310,44 @@ def count_callees_per_function( ) -> dict[tuple[Path, str], int]: all_caller_keys: list[tuple[Path, str, str]] = [] for file_path, qualified_names in file_path_to_qualified_names.items(): - self.ensure_file_indexed(file_path) resolved = str(file_path.resolve()) + self.ensure_file_indexed(file_path, resolved) all_caller_keys.extend((file_path, resolved, qn) for qn in qualified_names) if not all_caller_keys: return {} - counts: dict[tuple[Path, str], int] = {} cur = self.conn.cursor() - for orig_path, caller_file, caller_qn in all_caller_keys: - row = cur.execute( - """ - SELECT COUNT(*) FROM call_edges - WHERE project_root = ? AND language = ? AND caller_file = ? AND caller_qualified_name = ? - """, - (self.project_root_str, self.language, caller_file, caller_qn), - ).fetchone() - counts[(orig_path, caller_qn)] = row[0] if row else 0 + cur.execute("CREATE TEMP TABLE IF NOT EXISTS _count_keys (caller_file TEXT, caller_qualified_name TEXT)") + cur.execute("DELETE FROM _count_keys") + cur.executemany( + "INSERT INTO _count_keys VALUES (?, ?)", [(resolved, qn) for _, resolved, qn in all_caller_keys] + ) + + rows = cur.execute( + """ + SELECT ck.caller_file, ck.caller_qualified_name, COUNT(ce.rowid) + FROM _count_keys ck + LEFT JOIN call_edges ce + ON ce.caller_file = ck.caller_file AND ce.caller_qualified_name = ck.caller_qualified_name + AND ce.project_root = ? AND ce.language = ? + GROUP BY ck.caller_file, ck.caller_qualified_name + """, + (self.project_root_str, self.language), + ).fetchall() + + resolved_to_path: dict[str, Path] = {resolved: fp for fp, resolved, _ in all_caller_keys} + counts: dict[tuple[Path, str], int] = {} + for caller_file, caller_qn, cnt in rows: + counts[(resolved_to_path[caller_file], caller_qn)] = cnt return counts - def ensure_file_indexed(self, file_path: Path) -> IndexResult: - resolved = str(file_path.resolve()) + def ensure_file_indexed(self, file_path: Path, resolved: str | None = None) -> IndexResult: + if resolved is None: + resolved = str(file_path.resolve()) + # Always read and hash the file before checking the cache so we detect on-disk changes try: content = file_path.read_text(encoding="utf-8") except Exception: @@ -341,10 +358,11 @@ def ensure_file_indexed(self, file_path: Path) -> IndexResult: if self._is_file_cached(resolved, file_hash): return IndexResult(file_path=file_path, cached=True, num_edges=0, edges=(), cross_file_edges=0, error=False) - return self.index_file(file_path, file_hash) + return self.index_file(file_path, file_hash, resolved) - def index_file(self, file_path: Path, file_hash: str) -> IndexResult: - resolved = str(file_path.resolve()) + def index_file(self, file_path: Path, file_hash: str, resolved: str | None = None) -> IndexResult: + if resolved is None: + resolved = str(file_path.resolve()) edges, had_error = _analyze_file(file_path, self.jedi_project, self.project_root_str) if had_error: logger.debug(f"CallGraph: failed to parse {file_path}") @@ -441,8 +459,8 @@ def build_index(self, file_paths: Iterable[Path], on_progress: Callable[[IndexRe if len(to_index) >= _PARALLEL_THRESHOLD: self._build_index_parallel(to_index, on_progress) else: - for file_path, _resolved, file_hash in to_index: - result = self.index_file(file_path, file_hash) + for file_path, resolved, file_hash in to_index: + result = self.index_file(file_path, file_hash, resolved) self._report_progress(on_progress, result) def _is_file_cached(self, resolved: str, file_hash: str) -> bool: @@ -518,7 +536,7 @@ def _fallback_sequential_index( # Skip files already persisted before the failure if resolved in self.indexed_file_hashes: continue - result = self.index_file(file_path, file_hash) + result = self.index_file(file_path, file_hash, resolved) self._report_progress(on_progress, result) def close(self) -> None: From f7b04013ca683c59e9e836aff819bbe0bc7e22af Mon Sep 17 00:00:00 2001 From: "codeflash-ai[bot]" <148906541+codeflash-ai[bot]@users.noreply.github.com> Date: Wed, 18 Feb 2026 22:34:59 +0000 Subject: [PATCH 035/100] Optimize function_has_return_statement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The optimized code achieves a **146% speedup** (from 1.47ms to 595μs) by eliminating the overhead of `ast.iter_child_nodes()` and replacing it with direct field access on AST nodes. **Key optimizations:** 1. **Direct stack initialization**: Instead of starting with `[function_node]` and then traversing into its body, the stack is initialized directly with `list(function_node.body)`. This skips one iteration and avoids processing the function definition wrapper itself. 2. **Manual field traversal**: Rather than calling `ast.iter_child_nodes(node)` which is a generator that yields all child nodes, the code directly accesses `node._fields` and uses `getattr()` to inspect each field. This eliminates the generator overhead and function call costs associated with `ast.iter_child_nodes()`. 3. **Targeted statement filtering**: By checking `isinstance(child, ast.stmt)` or `isinstance(item, ast.stmt)` only on relevant fields (handling both single statements and lists of statements), the traversal focuses on statement nodes where `ast.Return` can appear, avoiding unnecessary checks on expression nodes. **Why this is faster:** - **Reduced function call overhead**: `ast.iter_child_nodes()` is a generator function that incurs call/yield overhead on every iteration. Direct attribute access via `getattr()` is faster for small numbers of fields. - **Fewer iterations**: The line profiler shows the original code's `ast.iter_child_nodes()` line hit 5,453 times (69% of runtime), while the optimized version's field iteration hits only 3,290 times (17.4% of runtime). - **Better cache locality**: Direct field access patterns may benefit from better CPU cache utilization compared to generator state management. **Test case performance:** The optimization shows dramatic improvements particularly for: - **Functions with many sequential statements** (2365% faster for 1000 statements, 1430% faster for 1000 nested functions) - **Simple functions** (234-354% faster for basic return detection) - **Moderately complex control flow** (80-125% faster for nested conditionals/loops) The speedup is consistent across all test cases, with early-return scenarios benefiting the most as the optimization allows faster discovery of the return statement before processing unnecessary nodes. --- codeflash/discovery/functions_to_optimize.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/codeflash/discovery/functions_to_optimize.py b/codeflash/discovery/functions_to_optimize.py index bb8b2f902..abad0d85e 100644 --- a/codeflash/discovery/functions_to_optimize.py +++ b/codeflash/discovery/functions_to_optimize.py @@ -956,15 +956,20 @@ def filter_files_optimized(file_path: Path, tests_root: Path, ignore_paths: list def function_has_return_statement(function_node: FunctionDef | AsyncFunctionDef) -> bool: # Custom DFS, return True as soon as a Return node is found - stack: list[ast.AST] = [function_node] + stack: list[ast.AST] = list(function_node.body) while stack: node = stack.pop() if isinstance(node, ast.Return): return True # Only push child nodes that are statements; Return nodes are statements, # so this preserves correctness while avoiding unnecessary traversal into expr/Name/etc. - for child in ast.iter_child_nodes(node): - if isinstance(child, ast.stmt): + for field in getattr(node, "_fields", ()): + child = getattr(node, field, None) + if isinstance(child, list): + for item in child: + if isinstance(item, ast.stmt): + stack.append(item) + elif isinstance(child, ast.stmt): stack.append(child) return False From 20c956c0e90b1065574df147bcac88a54a78a235 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 18 Feb 2026 17:39:36 -0500 Subject: [PATCH 036/100] feat: add codeflash-benchmark automated release to publish workflow Extend the publish workflow to handle both codeflash and codeflash-benchmark releases from a single workflow file, triggered by their respective version files. Also syncs benchmark __init__.py version to match pyproject.toml. --- .github/workflows/publish.yml | 117 +++++++++++++++++- .../codeflash_benchmark/__init__.py | 2 +- 2 files changed, 114 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 2ffe56dae..acab66d0b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -6,20 +6,48 @@ on: - main paths: - 'codeflash/version.py' + - 'codeflash-benchmark/codeflash_benchmark/__init__.py' jobs: - publish: + detect-changes: + runs-on: ubuntu-latest + outputs: + codeflash: ${{ steps.filter.outputs.codeflash }} + benchmark: ${{ steps.filter.outputs.benchmark }} + steps: + - name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 2 + + - name: Detect which packages changed + id: filter + run: | + if git diff --name-only HEAD~1 HEAD | grep -q '^codeflash/version.py$'; then + echo "codeflash=true" >> $GITHUB_OUTPUT + else + echo "codeflash=false" >> $GITHUB_OUTPUT + fi + if git diff --name-only HEAD~1 HEAD | grep -q '^codeflash-benchmark/codeflash_benchmark/__init__.py$'; then + echo "benchmark=true" >> $GITHUB_OUTPUT + else + echo "benchmark=false" >> $GITHUB_OUTPUT + fi + + publish-codeflash: + needs: detect-changes + if: needs.detect-changes.outputs.codeflash == 'true' runs-on: ubuntu-latest environment: name: pypi permissions: id-token: write - contents: write # Changed from 'read' to 'write' to allow tag creation + contents: write steps: - name: Checkout uses: actions/checkout@v5 with: - fetch-depth: 0 # Fetch all history for proper versioning + fetch-depth: 0 - name: Extract version from version.py id: extract_version @@ -76,4 +104,85 @@ jobs: prerelease: false generate_release_notes: true files: | - dist/* \ No newline at end of file + dist/* + + publish-benchmark: + needs: detect-changes + if: needs.detect-changes.outputs.benchmark == 'true' + runs-on: ubuntu-latest + environment: + name: pypi + permissions: + id-token: write + contents: write + steps: + - name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 + + - name: Extract version from __init__.py + id: extract_version + run: | + VERSION=$(grep -oP '__version__ = "\K[^"]+' codeflash-benchmark/codeflash_benchmark/__init__.py) + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "tag=benchmark-v$VERSION" >> $GITHUB_OUTPUT + echo "Extracted version: $VERSION" + + - name: Verify version matches pyproject.toml + run: | + INIT_VERSION=${{ steps.extract_version.outputs.version }} + TOML_VERSION=$(grep -oP '^version = "\K[^"]+' codeflash-benchmark/pyproject.toml) + if [ "$INIT_VERSION" != "$TOML_VERSION" ]; then + echo "::error::Version mismatch: __init__.py=$INIT_VERSION, pyproject.toml=$TOML_VERSION" + exit 1 + fi + + - name: Check if tag already exists + id: check_tag + run: | + if git rev-parse "${{ steps.extract_version.outputs.tag }}" >/dev/null 2>&1; then + echo "exists=true" >> $GITHUB_OUTPUT + echo "Tag ${{ steps.extract_version.outputs.tag }} already exists, skipping release" + else + echo "exists=false" >> $GITHUB_OUTPUT + echo "Tag ${{ steps.extract_version.outputs.tag }} does not exist, proceeding with release" + fi + + - name: Create and push git tag + if: steps.check_tag.outputs.exists == 'false' + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git tag -a "${{ steps.extract_version.outputs.tag }}" -m "Release ${{ steps.extract_version.outputs.tag }}" + git push origin "${{ steps.extract_version.outputs.tag }}" + + - name: Install uv + if: steps.check_tag.outputs.exists == 'false' + uses: astral-sh/setup-uv@v6 + + - name: Build + if: steps.check_tag.outputs.exists == 'false' + run: uv build --package codeflash-benchmark + + - name: Publish to PyPI + if: steps.check_tag.outputs.exists == 'false' + run: uv publish + + - name: Create GitHub Release + if: steps.check_tag.outputs.exists == 'false' + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ steps.extract_version.outputs.tag }} + name: codeflash-benchmark ${{ steps.extract_version.outputs.tag }} + body: | + ## What's Changed + + Release ${{ steps.extract_version.outputs.version }} of codeflash-benchmark. + + **Full Changelog**: https://github.com/${{ github.repository }}/commits/${{ steps.extract_version.outputs.tag }} + draft: false + prerelease: false + generate_release_notes: true + files: | + dist/* diff --git a/codeflash-benchmark/codeflash_benchmark/__init__.py b/codeflash-benchmark/codeflash_benchmark/__init__.py index 5ce074bab..7b85a2cc5 100644 --- a/codeflash-benchmark/codeflash_benchmark/__init__.py +++ b/codeflash-benchmark/codeflash_benchmark/__init__.py @@ -1,3 +1,3 @@ """CodeFlash Benchmark - Pytest benchmarking plugin for codeflash.ai.""" -__version__ = "0.1.0" +__version__ = "0.2.0" From a76f28f196fff1807a9f5a0c6b19d86e7ded116d Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 18 Feb 2026 17:44:03 -0500 Subject: [PATCH 037/100] chore: bump codeflash-benchmark version to 0.3.0 --- .github/workflows/publish.yml | 17 ++++----------- .../codeflash_benchmark/__init__.py | 2 +- .../codeflash_benchmark/version.py | 2 ++ codeflash-benchmark/pyproject.toml | 21 ++++++++++++++----- 4 files changed, 23 insertions(+), 19 deletions(-) create mode 100644 codeflash-benchmark/codeflash_benchmark/version.py diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index acab66d0b..541fdbe41 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -6,7 +6,7 @@ on: - main paths: - 'codeflash/version.py' - - 'codeflash-benchmark/codeflash_benchmark/__init__.py' + - 'codeflash-benchmark/codeflash_benchmark/version.py' jobs: detect-changes: @@ -28,7 +28,7 @@ jobs: else echo "codeflash=false" >> $GITHUB_OUTPUT fi - if git diff --name-only HEAD~1 HEAD | grep -q '^codeflash-benchmark/codeflash_benchmark/__init__.py$'; then + if git diff --name-only HEAD~1 HEAD | grep -q '^codeflash-benchmark/codeflash_benchmark/version.py$'; then echo "benchmark=true" >> $GITHUB_OUTPUT else echo "benchmark=false" >> $GITHUB_OUTPUT @@ -121,23 +121,14 @@ jobs: with: fetch-depth: 0 - - name: Extract version from __init__.py + - name: Extract version from version.py id: extract_version run: | - VERSION=$(grep -oP '__version__ = "\K[^"]+' codeflash-benchmark/codeflash_benchmark/__init__.py) + VERSION=$(grep -oP '__version__ = "\K[^"]+' codeflash-benchmark/codeflash_benchmark/version.py) echo "version=$VERSION" >> $GITHUB_OUTPUT echo "tag=benchmark-v$VERSION" >> $GITHUB_OUTPUT echo "Extracted version: $VERSION" - - name: Verify version matches pyproject.toml - run: | - INIT_VERSION=${{ steps.extract_version.outputs.version }} - TOML_VERSION=$(grep -oP '^version = "\K[^"]+' codeflash-benchmark/pyproject.toml) - if [ "$INIT_VERSION" != "$TOML_VERSION" ]; then - echo "::error::Version mismatch: __init__.py=$INIT_VERSION, pyproject.toml=$TOML_VERSION" - exit 1 - fi - - name: Check if tag already exists id: check_tag run: | diff --git a/codeflash-benchmark/codeflash_benchmark/__init__.py b/codeflash-benchmark/codeflash_benchmark/__init__.py index 7b85a2cc5..90bc3d848 100644 --- a/codeflash-benchmark/codeflash_benchmark/__init__.py +++ b/codeflash-benchmark/codeflash_benchmark/__init__.py @@ -1,3 +1,3 @@ """CodeFlash Benchmark - Pytest benchmarking plugin for codeflash.ai.""" -__version__ = "0.2.0" +from codeflash_benchmark.version import __version__ diff --git a/codeflash-benchmark/codeflash_benchmark/version.py b/codeflash-benchmark/codeflash_benchmark/version.py new file mode 100644 index 000000000..18606e8d2 --- /dev/null +++ b/codeflash-benchmark/codeflash_benchmark/version.py @@ -0,0 +1,2 @@ +# These version placeholders will be replaced by uv-dynamic-versioning during build. +__version__ = "0.3.0" diff --git a/codeflash-benchmark/pyproject.toml b/codeflash-benchmark/pyproject.toml index bc5e9040d..61f5bc3b7 100644 --- a/codeflash-benchmark/pyproject.toml +++ b/codeflash-benchmark/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "codeflash-benchmark" -version = "0.2.0" +dynamic = ["version"] description = "Pytest benchmarking plugin for codeflash.ai - automatic code performance optimization" authors = [{ name = "CodeFlash Inc.", email = "contact@codeflash.ai" }] requires-python = ">=3.9" @@ -25,8 +25,19 @@ Repository = "https://github.com/codeflash-ai/codeflash-benchmark" codeflash-benchmark = "codeflash_benchmark.plugin" [build-system] -requires = ["setuptools>=45", "wheel"] -build-backend = "setuptools.build_meta" +requires = ["hatchling", "uv-dynamic-versioning"] +build-backend = "hatchling.build" -[tool.setuptools] -packages = ["codeflash_benchmark"] +[tool.hatch.version] +source = "uv-dynamic-versioning" + +[tool.uv-dynamic-versioning] +enable = true +style = "pep440" +vcs = "git" + +[tool.hatch.build.hooks.version] +path = "codeflash_benchmark/version.py" +template = """# These version placeholders will be replaced by uv-dynamic-versioning during build. +__version__ = "{version}" +""" From e2b4b15bbc324c4f5b5af45b03a0bd3e1c0a229b Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Wed, 18 Feb 2026 22:48:32 +0000 Subject: [PATCH 038/100] style: auto-fix linting issues --- codeflash-benchmark/codeflash_benchmark/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codeflash-benchmark/codeflash_benchmark/__init__.py b/codeflash-benchmark/codeflash_benchmark/__init__.py index 90bc3d848..5b9dba851 100644 --- a/codeflash-benchmark/codeflash_benchmark/__init__.py +++ b/codeflash-benchmark/codeflash_benchmark/__init__.py @@ -1,3 +1,3 @@ """CodeFlash Benchmark - Pytest benchmarking plugin for codeflash.ai.""" -from codeflash_benchmark.version import __version__ +from codeflash_benchmark.version import __version__ as __version__ From 5aa115a5230a0b3f916f74316c446c08a144b30d Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 18 Feb 2026 17:56:59 -0500 Subject: [PATCH 039/100] feat: make crosshair-tool optional for Python 3.15+ crosshair-tool doesn't support Python 3.15 yet. The dependency is now conditional on python_version < 3.15, with a runtime guard that skips concolic test generation when the package is absent. --- codeflash/verification/concolic_testing.py | 7 +++++++ pyproject.toml | 2 +- uv.lock | 8 ++++---- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/codeflash/verification/concolic_testing.py b/codeflash/verification/concolic_testing.py index eda960123..05cad9f7a 100644 --- a/codeflash/verification/concolic_testing.py +++ b/codeflash/verification/concolic_testing.py @@ -1,6 +1,7 @@ from __future__ import annotations import ast +import importlib.util import subprocess import tempfile import time @@ -18,6 +19,8 @@ from codeflash.telemetry.posthog_cf import ph from codeflash.verification.verification_utils import TestConfig +CROSSHAIR_AVAILABLE = importlib.util.find_spec("crosshair") is not None + if TYPE_CHECKING: from argparse import Namespace @@ -52,6 +55,10 @@ def generate_concolic_tests( logger.debug("Skipping concolic test generation for non-Python languages (CrossHair is Python-only)") return function_to_concolic_tests, concolic_test_suite_code + if not CROSSHAIR_AVAILABLE: + logger.debug("Skipping concolic test generation (crosshair-tool is not installed)") + return function_to_concolic_tests, concolic_test_suite_code + if is_LSP_enabled(): logger.debug("Skipping concolic test generation in LSP mode") return function_to_concolic_tests, concolic_test_suite_code diff --git a/pyproject.toml b/pyproject.toml index f996d2a34..e9bd87766 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ dependencies = [ "dill>=0.3.8", "rich>=13.8.1", "lxml>=5.3.0", - "crosshair-tool>=0.0.78", + "crosshair-tool>=0.0.78; python_version < '3.15'", "coverage>=7.6.4", "line_profiler>=4.2.0", "platformdirs>=4.3.7", diff --git a/uv.lock b/uv.lock index d4f84229e..5a1f187f6 100644 --- a/uv.lock +++ b/uv.lock @@ -428,7 +428,7 @@ dependencies = [ { name = "codeflash-benchmark" }, { name = "coverage", version = "7.10.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "coverage", version = "7.13.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "crosshair-tool" }, + { name = "crosshair-tool", marker = "python_full_version < '3.15'" }, { name = "dill" }, { name = "filelock", version = "3.19.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "filelock", version = "3.21.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, @@ -528,7 +528,7 @@ requires-dist = [ { name = "click", specifier = ">=8.1.0" }, { name = "codeflash-benchmark", editable = "codeflash-benchmark" }, { name = "coverage", specifier = ">=7.6.4" }, - { name = "crosshair-tool", specifier = ">=0.0.78" }, + { name = "crosshair-tool", marker = "python_full_version < '3.15'", specifier = ">=0.0.78" }, { name = "dill", specifier = ">=0.3.8" }, { name = "filelock" }, { name = "gitpython", specifier = ">=3.1.31" }, @@ -1032,7 +1032,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -3621,7 +3621,7 @@ name = "pexpect" version = "4.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "ptyprocess" }, + { name = "ptyprocess", marker = "(python_full_version < '3.11' and sys_platform == 'emscripten') or (python_full_version < '3.11' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } wheels = [ From 35091cdb49db43f0e95a6a4d4974b8f612a896ec Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 18 Feb 2026 19:36:57 -0500 Subject: [PATCH 040/100] feat: replace rglob with os.walk and per-language directory pruning File discovery used Path.rglob per extension, traversing excluded dirs (e.g. .venv, node_modules) before filtering. Switch to a single os.walk pass with in-place dirs[:] pruning. Each language now declares its own dir_excludes patterns (exact, prefix*, *suffix) on the LanguageSupport protocol, parsed by parse_dir_excludes() at walk time. --- codeflash/discovery/functions_to_optimize.py | 80 +++++++++++++------- codeflash/languages/base.py | 8 ++ codeflash/languages/javascript/support.py | 4 + codeflash/languages/python/support.py | 11 +++ 4 files changed, 77 insertions(+), 26 deletions(-) diff --git a/codeflash/discovery/functions_to_optimize.py b/codeflash/discovery/functions_to_optimize.py index 86d574af1..ae2a6663c 100644 --- a/codeflash/discovery/functions_to_optimize.py +++ b/codeflash/discovery/functions_to_optimize.py @@ -146,6 +146,29 @@ def generic_visit(self, node: ast.AST) -> None: # Multi-language support helpers # ============================================================================= +_VCS_EXCLUDES = frozenset({".git", ".hg", ".svn"}) + + +def parse_dir_excludes( + patterns: frozenset[str], +) -> tuple[frozenset[str], tuple[str, ...], tuple[str, ...]]: + """Split glob patterns into exact names, prefixes, and suffixes. + + Patterns ending with ``*`` become prefix matches, patterns starting with ``*`` + become suffix matches, and plain strings become exact matches. + """ + exact: set[str] = set() + prefixes: list[str] = [] + suffixes: list[str] = [] + for p in patterns: + if p.endswith("*"): + prefixes.append(p[:-1]) + elif p.startswith("*"): + suffixes.append(p[1:]) + else: + exact.add(p) + return frozenset(exact), tuple(prefixes), tuple(suffixes) + def get_files_for_language( module_root_path: Path, ignore_paths: list[Path] | None = None, language: Language | None = None @@ -167,34 +190,39 @@ def get_files_for_language( if language is not None: support = get_language_support(language) extensions = support.file_extensions + all_patterns = support.dir_excludes | _VCS_EXCLUDES else: extensions = tuple(get_supported_extensions()) - - # Default directory patterns to always exclude for JS/TS - js_ts_default_excludes = { - "node_modules", - "dist", - "build", - ".next", - ".nuxt", - "coverage", - ".cache", - ".turbo", - ".vercel", - "__pycache__", - } - - files = [] - for ext in extensions: - pattern = f"*{ext}" - for file_path in module_root_path.rglob(pattern): - # Check explicit ignore paths - if any(file_path.is_relative_to(ignore_path) for ignore_path in ignore_paths): - continue - # Check default JS/TS excludes in path parts - if any(part in js_ts_default_excludes for part in file_path.parts): - continue - files.append(file_path) + all_patterns: frozenset[str] = _VCS_EXCLUDES + for lang in Language: + if is_language_supported(lang): + all_patterns = all_patterns | get_language_support(lang).dir_excludes + + dir_excludes, prefixes, suffixes = parse_dir_excludes(all_patterns) + + ignore_dirs: set[str] = set() + ignore_files: set[Path] = set() + for p in ignore_paths: + if p.is_file(): + ignore_files.add(p) + else: + ignore_dirs.add(str(p)) + + files: list[Path] = [] + for dirpath, dirnames, filenames in os.walk(module_root_path): + dirnames[:] = [ + d + for d in dirnames + if d not in dir_excludes + and not (prefixes and d.startswith(prefixes)) + and not (suffixes and d.endswith(suffixes)) + and str(Path(dirpath) / d) not in ignore_dirs + ] + for fname in filenames: + if fname.endswith(extensions): + fpath = Path(dirpath, fname) + if fpath not in ignore_files: + files.append(fpath) return files diff --git a/codeflash/languages/base.py b/codeflash/languages/base.py index 4253798bc..699c49244 100644 --- a/codeflash/languages/base.py +++ b/codeflash/languages/base.py @@ -254,6 +254,14 @@ def comment_prefix(self) -> str: """Like # or //.""" ... + @property + def dir_excludes(self) -> frozenset[str]: + """Directory name patterns to skip during file discovery. + + Supports glob wildcards: "name" for exact, "prefix*" for startswith, "*suffix" for endswith. + """ + ... + # === Discovery === def discover_functions( diff --git a/codeflash/languages/javascript/support.py b/codeflash/languages/javascript/support.py index 724dc066e..77c6a3a80 100644 --- a/codeflash/languages/javascript/support.py +++ b/codeflash/languages/javascript/support.py @@ -63,6 +63,10 @@ def test_framework(self) -> str: def comment_prefix(self) -> str: return "//" + @property + def dir_excludes(self) -> frozenset[str]: + return frozenset({"node_modules", "dist", "build", ".next", ".nuxt", "coverage", ".cache", ".turbo", ".vercel"}) + # === Discovery === def discover_functions( diff --git a/codeflash/languages/python/support.py b/codeflash/languages/python/support.py index 51624adf0..d07390e5b 100644 --- a/codeflash/languages/python/support.py +++ b/codeflash/languages/python/support.py @@ -75,6 +75,17 @@ def test_framework(self) -> str: def comment_prefix(self) -> str: return "#" + @property + def dir_excludes(self) -> frozenset[str]: + return frozenset({ + "__pycache__", ".venv", "venv", ".tox", ".nox", ".eggs", + ".mypy_cache", ".ruff_cache", ".pytest_cache", ".hypothesis", + "htmlcov", ".pytype", ".pyre", ".pybuilder", + ".ipynb_checkpoints", ".codeflash", ".cache", ".complexipy_cache", + "build", "dist", "sdist", + ".coverage*", ".pyright*", "*.egg-info", + }) + # === Discovery === def discover_functions( From d950bb1c64a2317e06c8dd2e127f33794311ab34 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 00:41:12 +0000 Subject: [PATCH 041/100] style: auto-fix formatting and resolve mypy no-redef error Co-Authored-By: Claude Opus 4.6 --- codeflash/discovery/functions_to_optimize.py | 7 ++-- codeflash/languages/python/support.py | 36 +++++++++++++++----- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/codeflash/discovery/functions_to_optimize.py b/codeflash/discovery/functions_to_optimize.py index ae2a6663c..44ece2cbe 100644 --- a/codeflash/discovery/functions_to_optimize.py +++ b/codeflash/discovery/functions_to_optimize.py @@ -149,9 +149,7 @@ def generic_visit(self, node: ast.AST) -> None: _VCS_EXCLUDES = frozenset({".git", ".hg", ".svn"}) -def parse_dir_excludes( - patterns: frozenset[str], -) -> tuple[frozenset[str], tuple[str, ...], tuple[str, ...]]: +def parse_dir_excludes(patterns: frozenset[str]) -> tuple[frozenset[str], tuple[str, ...], tuple[str, ...]]: """Split glob patterns into exact names, prefixes, and suffixes. Patterns ending with ``*`` become prefix matches, patterns starting with ``*`` @@ -187,13 +185,14 @@ def get_files_for_language( if ignore_paths is None: ignore_paths = [] + all_patterns: frozenset[str] if language is not None: support = get_language_support(language) extensions = support.file_extensions all_patterns = support.dir_excludes | _VCS_EXCLUDES else: extensions = tuple(get_supported_extensions()) - all_patterns: frozenset[str] = _VCS_EXCLUDES + all_patterns = _VCS_EXCLUDES for lang in Language: if is_language_supported(lang): all_patterns = all_patterns | get_language_support(lang).dir_excludes diff --git a/codeflash/languages/python/support.py b/codeflash/languages/python/support.py index d07390e5b..ddff51b8f 100644 --- a/codeflash/languages/python/support.py +++ b/codeflash/languages/python/support.py @@ -77,14 +77,34 @@ def comment_prefix(self) -> str: @property def dir_excludes(self) -> frozenset[str]: - return frozenset({ - "__pycache__", ".venv", "venv", ".tox", ".nox", ".eggs", - ".mypy_cache", ".ruff_cache", ".pytest_cache", ".hypothesis", - "htmlcov", ".pytype", ".pyre", ".pybuilder", - ".ipynb_checkpoints", ".codeflash", ".cache", ".complexipy_cache", - "build", "dist", "sdist", - ".coverage*", ".pyright*", "*.egg-info", - }) + return frozenset( + { + "__pycache__", + ".venv", + "venv", + ".tox", + ".nox", + ".eggs", + ".mypy_cache", + ".ruff_cache", + ".pytest_cache", + ".hypothesis", + "htmlcov", + ".pytype", + ".pyre", + ".pybuilder", + ".ipynb_checkpoints", + ".codeflash", + ".cache", + ".complexipy_cache", + "build", + "dist", + "sdist", + ".coverage*", + ".pyright*", + "*.egg-info", + } + ) # === Discovery === From 4473430fd94d944f87ff301d2e6dcbd47712021f Mon Sep 17 00:00:00 2001 From: Kevin Turcios <106575910+KRRT7@users.noreply.github.com> Date: Wed, 18 Feb 2026 19:52:17 -0500 Subject: [PATCH 042/100] Update codeflash/discovery/functions_to_optimize.py Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> --- codeflash/discovery/functions_to_optimize.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/codeflash/discovery/functions_to_optimize.py b/codeflash/discovery/functions_to_optimize.py index 44ece2cbe..49bfad8de 100644 --- a/codeflash/discovery/functions_to_optimize.py +++ b/codeflash/discovery/functions_to_optimize.py @@ -202,6 +202,8 @@ def get_files_for_language( ignore_dirs: set[str] = set() ignore_files: set[Path] = set() for p in ignore_paths: + p = Path(p) if not isinstance(p, Path) else p + if p.is_file(): if p.is_file(): ignore_files.add(p) else: From aa5db4cbc36869517b87a628ac7c02c8280b70c6 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 00:54:39 +0000 Subject: [PATCH 043/100] style: remove duplicate if statement causing syntax error --- codeflash/discovery/functions_to_optimize.py | 1 - 1 file changed, 1 deletion(-) diff --git a/codeflash/discovery/functions_to_optimize.py b/codeflash/discovery/functions_to_optimize.py index 49bfad8de..ed18ed53b 100644 --- a/codeflash/discovery/functions_to_optimize.py +++ b/codeflash/discovery/functions_to_optimize.py @@ -203,7 +203,6 @@ def get_files_for_language( ignore_files: set[Path] = set() for p in ignore_paths: p = Path(p) if not isinstance(p, Path) else p - if p.is_file(): if p.is_file(): ignore_files.add(p) else: From 14f4324d465c38f094490bff274881829372ccdf Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 18 Feb 2026 20:18:45 -0500 Subject: [PATCH 044/100] chore: update tessl tiles and upgrade dependencies Remove codeflash-specific tessl tiles, add new pypi tiles from pyproject.toml, and run uv sync --upgrade to bump dependencies. --- tessl.json | 27 +- uv.lock | 791 ++++++++++++++++++++++++++++------------------------- 2 files changed, 427 insertions(+), 391 deletions(-) diff --git a/tessl.json b/tessl.json index d766df3ba..638d2b2cf 100644 --- a/tessl.json +++ b/tessl.json @@ -20,7 +20,7 @@ "version": "0.13.0" }, "tessl/pypi-pydantic": { - "version": "1.10.0" + "version": "2.11.0" }, "tessl/pypi-humanize": { "version": "4.13.0" @@ -35,7 +35,7 @@ "version": "3.4.0" }, "tessl/pypi-sentry-sdk": { - "version": "1.45.0" + "version": "2.36.0" }, "tessl/pypi-parameterized": { "version": "0.9.0" @@ -44,10 +44,10 @@ "version": "0.4.0" }, "tessl/pypi-rich": { - "version": "13.9.0" + "version": "14.1.0" }, "tessl/pypi-lxml": { - "version": "5.4.0" + "version": "6.0.0" }, "tessl/pypi-crosshair-tool": { "version": "0.0.0" @@ -64,17 +64,20 @@ "tessl/pypi-filelock": { "version": "3.19.0" }, - "codeflash/codeflash-rules": { - "version": "0.1.0" + "tessl/pypi-ipython": { + "version": "9.5.0" }, - "codeflash/codeflash-docs": { - "version": "0.1.0" + "tessl/pypi-mypy": { + "version": "1.17.0" }, - "codeflash/codeflash-skills": { - "version": "0.2.0" + "tessl/pypi-ty": { + "version": "0.0.0" + }, + "tessl/pypi-types-jsonschema": { + "version": "3.2.0" }, - "tessl-labs/tessl-skill-eval-scenarios": { - "version": "0.0.5" + "tessl/pypi-uv": { + "version": "0.8.0" } } } diff --git a/uv.lock b/uv.lock index 5a1f187f6..21221c10b 100644 --- a/uv.lock +++ b/uv.lock @@ -200,7 +200,7 @@ dependencies = [ { name = "mypy-extensions", marker = "python_full_version >= '3.10'" }, { name = "packaging", marker = "python_full_version >= '3.10'" }, { name = "pathspec", marker = "python_full_version >= '3.10'" }, - { name = "platformdirs", version = "4.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "platformdirs", version = "4.9.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "pytokens", marker = "python_full_version >= '3.10'" }, { name = "tomli", marker = "python_full_version == '3.10.*'" }, { name = "typing-extensions", marker = "python_full_version == '3.10.*'" }, @@ -252,16 +252,49 @@ wheels = [ name = "cattrs" version = "25.3.0" source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.9.2' and python_full_version < '3.10'", + "python_full_version < '3.9.2'", +] dependencies = [ - { name = "attrs" }, - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "typing-extensions" }, + { name = "attrs", marker = "python_full_version < '3.10'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.10'" }, + { name = "typing-extensions", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6e/00/2432bb2d445b39b5407f0a90e01b9a271475eea7caf913d7a86bcb956385/cattrs-25.3.0.tar.gz", hash = "sha256:1ac88d9e5eda10436c4517e390a4142d88638fe682c436c93db7ce4a277b884a", size = 509321, upload-time = "2025-10-07T12:26:08.737Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d8/2b/a40e1488fdfa02d3f9a653a61a5935ea08b3c2225ee818db6a76c7ba9695/cattrs-25.3.0-py3-none-any.whl", hash = "sha256:9896e84e0a5bf723bc7b4b68f4481785367ce07a8a02e7e9ee6eb2819bc306ff", size = 70738, upload-time = "2025-10-07T12:26:06.603Z" }, ] +[[package]] +name = "cattrs" +version = "26.1.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.14' and sys_platform == 'win32'", + "python_full_version >= '3.14' and sys_platform == 'emscripten'", + "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version == '3.13.*' and sys_platform == 'win32'", + "python_full_version == '3.13.*' and sys_platform == 'emscripten'", + "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version == '3.12.*' and sys_platform == 'win32'", + "python_full_version == '3.11.*' and sys_platform == 'win32'", + "python_full_version == '3.12.*' and sys_platform == 'emscripten'", + "python_full_version == '3.11.*' and sys_platform == 'emscripten'", + "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version == '3.10.*'", +] +dependencies = [ + { name = "attrs", marker = "python_full_version >= '3.10'" }, + { name = "exceptiongroup", marker = "python_full_version == '3.10.*'" }, + { name = "typing-extensions", marker = "python_full_version >= '3.10'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a0/ec/ba18945e7d6e55a58364d9fb2e46049c1c2998b3d805f19b703f14e81057/cattrs-26.1.0.tar.gz", hash = "sha256:fa239e0f0ec0715ba34852ce813986dfed1e12117e209b816ab87401271cdd40", size = 495672, upload-time = "2026-02-18T22:15:19.406Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/80/56/60547f7801b97c67e97491dc3d9ade9fbccbd0325058fd3dfcb2f5d98d90/cattrs-26.1.0-py3-none-any.whl", hash = "sha256:d1e0804c42639494d469d08d4f26d6b9de9b8ab26b446db7b5f8c2e97f7c3096", size = 73054, upload-time = "2026-02-18T22:15:17.958Z" }, +] + [[package]] name = "certifi" version = "2026.1.4" @@ -431,7 +464,7 @@ dependencies = [ { name = "crosshair-tool", marker = "python_full_version < '3.15'" }, { name = "dill" }, { name = "filelock", version = "3.19.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "filelock", version = "3.21.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "filelock", version = "3.24.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "gitpython" }, { name = "humanize", version = "4.13.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "humanize", version = "4.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, @@ -446,9 +479,9 @@ dependencies = [ { name = "lxml" }, { name = "parameterized" }, { name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "platformdirs", version = "4.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "platformdirs", version = "4.9.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "posthog", version = "6.9.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "posthog", version = "7.8.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "posthog", version = "7.9.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "pydantic" }, { name = "pygls" }, { name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, @@ -503,14 +536,14 @@ tests = [ { name = "jax", version = "0.6.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, { name = "jax", version = "0.9.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "numba", version = "0.60.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "numba", version = "0.63.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "numba", version = "0.64.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, - { name = "numpy", version = "2.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "pandas", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "pandas", version = "3.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "pandas", version = "3.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "pyarrow", version = "21.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "pyarrow", version = "23.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "pyarrow", version = "23.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "pyrsistent" }, { name = "scipy", version = "1.13.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, @@ -520,7 +553,7 @@ tests = [ { name = "torch", version = "2.10.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "xarray", version = "2024.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "xarray", version = "2025.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, - { name = "xarray", version = "2026.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "xarray", version = "2026.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] [package.metadata] @@ -1032,7 +1065,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -1063,7 +1096,7 @@ wheels = [ [[package]] name = "filelock" -version = "3.21.2" +version = "3.24.3" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.14' and sys_platform == 'win32'", @@ -1080,9 +1113,9 @@ resolution-markers = [ "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version == '3.10.*'", ] -sdist = { url = "https://files.pythonhosted.org/packages/73/71/74364ff065ca78914d8bd90b312fe78ddc5e11372d38bc9cb7104f887ce1/filelock-3.21.2.tar.gz", hash = "sha256:cfd218cfccf8b947fce7837da312ec3359d10ef2a47c8602edd59e0bacffb708", size = 31486, upload-time = "2026-02-13T01:27:15.223Z" } +sdist = { url = "https://files.pythonhosted.org/packages/73/92/a8e2479937ff39185d20dd6a851c1a63e55849e447a55e798cc2e1f49c65/filelock-3.24.3.tar.gz", hash = "sha256:011a5644dc937c22699943ebbfc46e969cdde3e171470a6e40b9533e5a72affa", size = 37935, upload-time = "2026-02-19T00:48:20.543Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/73/3a18f1e1276810e81477c431009b55eeccebbd7301d28a350b77aacf3c33/filelock-3.21.2-py3-none-any.whl", hash = "sha256:d6cd4dbef3e1bb63bc16500fc5aa100f16e405bbff3fb4231711851be50c1560", size = 21479, upload-time = "2026-02-13T01:27:13.611Z" }, + { url = "https://files.pythonhosted.org/packages/9c/0f/5d0c71a1aefeb08efff26272149e07ab922b64f46c63363756224bd6872e/filelock-3.24.3-py3-none-any.whl", hash = "sha256:426e9a4660391f7f8a810d71b0555bce9008b0a1cc342ab1f6947d37639e002d", size = 24331, upload-time = "2026-02-19T00:48:18.465Z" }, ] [[package]] @@ -1308,7 +1341,7 @@ resolution-markers = [ ] dependencies = [ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, - { name = "numpy", version = "2.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4d/6a/0d79de0b025aa85dc8864de8e97659c94cf3d23148394a954dc5ca52f8c8/h5py-3.15.1.tar.gz", hash = "sha256:c86e3ed45c4473564de55aa83b6fc9e5ead86578773dfbd93047380042e26b69", size = 426236, upload-time = "2025-10-16T10:35:27.404Z" } wheels = [ @@ -1708,7 +1741,7 @@ resolution-markers = [ dependencies = [ { name = "jaxlib", version = "0.9.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "ml-dtypes", marker = "python_full_version >= '3.11'" }, - { name = "numpy", version = "2.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "opt-einsum", marker = "python_full_version >= '3.11'" }, { name = "scipy", version = "1.17.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] @@ -1806,7 +1839,7 @@ resolution-markers = [ ] dependencies = [ { name = "ml-dtypes", marker = "python_full_version >= '3.11'" }, - { name = "numpy", version = "2.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "scipy", version = "1.17.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] wheels = [ @@ -1947,7 +1980,7 @@ dependencies = [ { name = "h5py", version = "3.15.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "ml-dtypes", marker = "python_full_version >= '3.11'" }, { name = "namex", marker = "python_full_version >= '3.11'" }, - { name = "numpy", version = "2.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "optree", marker = "python_full_version >= '3.11'" }, { name = "packaging", marker = "python_full_version >= '3.11'" }, { name = "rich", marker = "python_full_version >= '3.11'" }, @@ -2053,99 +2086,99 @@ wheels = [ [[package]] name = "librt" -version = "0.8.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/3f/4ca7dd7819bf8ff303aca39c3c60e5320e46e766ab7f7dd627d3b9c11bdf/librt-0.8.0.tar.gz", hash = "sha256:cb74cdcbc0103fc988e04e5c58b0b31e8e5dd2babb9182b6f9490488eb36324b", size = 177306, upload-time = "2026-02-12T14:53:54.743Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/e9/018cfd60629e0404e6917943789800aa2231defbea540a17b90cc4547b97/librt-0.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:db63cf3586a24241e89ca1ce0b56baaec9d371a328bd186c529b27c914c9a1ef", size = 65690, upload-time = "2026-02-12T14:51:57.761Z" }, - { url = "https://files.pythonhosted.org/packages/b5/80/8d39980860e4d1c9497ee50e5cd7c4766d8cfd90d105578eae418e8ffcbc/librt-0.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ba9d9e60651615bc614be5e21a82cdb7b1769a029369cf4b4d861e4f19686fb6", size = 68373, upload-time = "2026-02-12T14:51:59.013Z" }, - { url = "https://files.pythonhosted.org/packages/2d/76/6e6f7a443af63977e421bd542551fec4072d9eaba02e671b05b238fe73bc/librt-0.8.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cb4b3ad543084ed79f186741470b251b9d269cd8b03556f15a8d1a99a64b7de5", size = 197091, upload-time = "2026-02-12T14:52:00.642Z" }, - { url = "https://files.pythonhosted.org/packages/14/40/fa064181c231334c9f4cb69eb338132d39510c8928e84beba34b861d0a71/librt-0.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d2720335020219197380ccfa5c895f079ac364b4c429e96952cd6509934d8eb", size = 207350, upload-time = "2026-02-12T14:52:02.32Z" }, - { url = "https://files.pythonhosted.org/packages/50/49/e7f8438dd226305e3e5955d495114ad01448e6a6ffc0303289b4153b5fc5/librt-0.8.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9726305d3e53419d27fc8cdfcd3f9571f0ceae22fa6b5ea1b3662c2e538f833e", size = 219962, upload-time = "2026-02-12T14:52:03.884Z" }, - { url = "https://files.pythonhosted.org/packages/1f/2c/74086fc5d52e77107a3cc80a9a3209be6ad1c9b6bc99969d8d9bbf9fdfe4/librt-0.8.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cc3d107f603b5ee7a79b6aa6f166551b99b32fb4a5303c4dfcb4222fc6a0335e", size = 212939, upload-time = "2026-02-12T14:52:05.537Z" }, - { url = "https://files.pythonhosted.org/packages/c8/ae/d6917c0ebec9bc2e0293903d6a5ccc7cdb64c228e529e96520b277318f25/librt-0.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:41064a0c07b4cc7a81355ccc305cb097d6027002209ffca51306e65ee8293630", size = 221393, upload-time = "2026-02-12T14:52:07.164Z" }, - { url = "https://files.pythonhosted.org/packages/04/97/15df8270f524ce09ad5c19cbbe0e8f95067582507149a6c90594e7795370/librt-0.8.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c6e4c10761ddbc0d67d2f6e2753daf99908db85d8b901729bf2bf5eaa60e0567", size = 216721, upload-time = "2026-02-12T14:52:08.857Z" }, - { url = "https://files.pythonhosted.org/packages/c4/52/17cbcf9b7a1bae5016d9d3561bc7169b32c3bd216c47d934d3f270602c0c/librt-0.8.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:ba581acad5ac8f33e2ff1746e8a57e001b47c6721873121bf8bbcf7ba8bd3aa4", size = 214790, upload-time = "2026-02-12T14:52:10.033Z" }, - { url = "https://files.pythonhosted.org/packages/2a/2d/010a236e8dc4d717dd545c46fd036dcced2c7ede71ef85cf55325809ff92/librt-0.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bdab762e2c0b48bab76f1a08acb3f4c77afd2123bedac59446aeaaeed3d086cf", size = 237384, upload-time = "2026-02-12T14:52:11.244Z" }, - { url = "https://files.pythonhosted.org/packages/38/14/f1c0eff3df8760dee761029efb72991c554d9f3282f1048e8c3d0eb60997/librt-0.8.0-cp310-cp310-win32.whl", hash = "sha256:6a3146c63220d814c4a2c7d6a1eacc8d5c14aed0ff85115c1dfea868080cd18f", size = 54289, upload-time = "2026-02-12T14:52:12.798Z" }, - { url = "https://files.pythonhosted.org/packages/2f/0b/2684d473e64890882729f91866ed97ccc0a751a0afc3b4bf1a7b57094dbb/librt-0.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:bbebd2bba5c6ae02907df49150e55870fdd7440d727b6192c46b6f754723dde9", size = 61347, upload-time = "2026-02-12T14:52:13.793Z" }, - { url = "https://files.pythonhosted.org/packages/51/e9/42af181c89b65abfd557c1b017cba5b82098eef7bf26d1649d82ce93ccc7/librt-0.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0ce33a9778e294507f3a0e3468eccb6a698b5166df7db85661543eca1cfc5369", size = 65314, upload-time = "2026-02-12T14:52:14.778Z" }, - { url = "https://files.pythonhosted.org/packages/9d/4a/15a847fca119dc0334a4b8012b1e15fdc5fc19d505b71e227eaf1bcdba09/librt-0.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8070aa3368559de81061ef752770d03ca1f5fc9467d4d512d405bd0483bfffe6", size = 68015, upload-time = "2026-02-12T14:52:15.797Z" }, - { url = "https://files.pythonhosted.org/packages/e1/87/ffc8dbd6ab68dd91b736c88529411a6729649d2b74b887f91f3aaff8d992/librt-0.8.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:20f73d4fecba969efc15cdefd030e382502d56bb6f1fc66b580cce582836c9fa", size = 194508, upload-time = "2026-02-12T14:52:16.835Z" }, - { url = "https://files.pythonhosted.org/packages/89/92/a7355cea28d6c48ff6ff5083ac4a2a866fb9b07b786aa70d1f1116680cd5/librt-0.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a512c88900bdb1d448882f5623a0b1ad27ba81a9bd75dacfe17080b72272ca1f", size = 205630, upload-time = "2026-02-12T14:52:18.58Z" }, - { url = "https://files.pythonhosted.org/packages/ac/5e/54509038d7ac527828db95b8ba1c8f5d2649bc32fd8f39b1718ec9957dce/librt-0.8.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:015e2dde6e096d27c10238bf9f6492ba6c65822dfb69d2bf74c41a8e88b7ddef", size = 218289, upload-time = "2026-02-12T14:52:20.134Z" }, - { url = "https://files.pythonhosted.org/packages/6d/17/0ee0d13685cefee6d6f2d47bb643ddad3c62387e2882139794e6a5f1288a/librt-0.8.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1c25a131013eadd3c600686a0c0333eb2896483cbc7f65baa6a7ee761017aef9", size = 211508, upload-time = "2026-02-12T14:52:21.413Z" }, - { url = "https://files.pythonhosted.org/packages/4b/a8/1714ef6e9325582e3727de3be27e4c1b2f428ea411d09f1396374180f130/librt-0.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:21b14464bee0b604d80a638cf1ee3148d84ca4cc163dcdcecb46060c1b3605e4", size = 219129, upload-time = "2026-02-12T14:52:22.61Z" }, - { url = "https://files.pythonhosted.org/packages/89/d3/2d9fe353edff91cdc0ece179348054a6fa61f3de992c44b9477cb973509b/librt-0.8.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:05a3dd3f116747f7e1a2b475ccdc6fb637fd4987126d109e03013a79d40bf9e6", size = 213126, upload-time = "2026-02-12T14:52:23.819Z" }, - { url = "https://files.pythonhosted.org/packages/ad/8e/9f5c60444880f6ad50e3ff7475e5529e787797e7f3ad5432241633733b92/librt-0.8.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:fa37f99bff354ff191c6bcdffbc9d7cdd4fc37faccfc9be0ef3a4fd5613977da", size = 212279, upload-time = "2026-02-12T14:52:25.034Z" }, - { url = "https://files.pythonhosted.org/packages/fe/eb/d4a2cfa647da3022ae977f50d7eda1d91f70d7d1883cf958a4b6ef689eab/librt-0.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1566dbb9d1eb0987264c9b9460d212e809ba908d2f4a3999383a84d765f2f3f1", size = 234654, upload-time = "2026-02-12T14:52:26.204Z" }, - { url = "https://files.pythonhosted.org/packages/6a/31/26b978861c7983b036a3aea08bdbb2ec32bbaab1ad1d57c5e022be59afc1/librt-0.8.0-cp311-cp311-win32.whl", hash = "sha256:70defb797c4d5402166787a6b3c66dfb3fa7f93d118c0509ffafa35a392f4258", size = 54603, upload-time = "2026-02-12T14:52:27.342Z" }, - { url = "https://files.pythonhosted.org/packages/d0/78/f194ed7c48dacf875677e749c5d0d1d69a9daa7c994314a39466237fb1be/librt-0.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:db953b675079884ffda33d1dca7189fb961b6d372153750beb81880384300817", size = 61730, upload-time = "2026-02-12T14:52:28.31Z" }, - { url = "https://files.pythonhosted.org/packages/97/ee/ad71095478d02137b6f49469dc808c595cfe89b50985f6b39c5345f0faab/librt-0.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:75d1a8cab20b2043f03f7aab730551e9e440adc034d776f15f6f8d582b0a5ad4", size = 52274, upload-time = "2026-02-12T14:52:29.345Z" }, - { url = "https://files.pythonhosted.org/packages/fb/53/f3bc0c4921adb0d4a5afa0656f2c0fbe20e18e3e0295e12985b9a5dc3f55/librt-0.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:17269dd2745dbe8e42475acb28e419ad92dfa38214224b1b01020b8cac70b645", size = 66511, upload-time = "2026-02-12T14:52:30.34Z" }, - { url = "https://files.pythonhosted.org/packages/89/4b/4c96357432007c25a1b5e363045373a6c39481e49f6ba05234bb59a839c1/librt-0.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f4617cef654fca552f00ce5ffdf4f4b68770f18950e4246ce94629b789b92467", size = 68628, upload-time = "2026-02-12T14:52:31.491Z" }, - { url = "https://files.pythonhosted.org/packages/47/16/52d75374d1012e8fc709216b5eaa25f471370e2a2331b8be00f18670a6c7/librt-0.8.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5cb11061a736a9db45e3c1293cfcb1e3caf205912dfa085734ba750f2197ff9a", size = 198941, upload-time = "2026-02-12T14:52:32.489Z" }, - { url = "https://files.pythonhosted.org/packages/fc/11/d5dd89e5a2228567b1228d8602d896736247424484db086eea6b8010bcba/librt-0.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4bb00bd71b448f16749909b08a0ff16f58b079e2261c2e1000f2bbb2a4f0a45", size = 210009, upload-time = "2026-02-12T14:52:33.634Z" }, - { url = "https://files.pythonhosted.org/packages/49/d8/fc1a92a77c3020ee08ce2dc48aed4b42ab7c30fb43ce488d388673b0f164/librt-0.8.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:95a719a049f0eefaf1952673223cf00d442952273cbd20cf2ed7ec423a0ef58d", size = 224461, upload-time = "2026-02-12T14:52:34.868Z" }, - { url = "https://files.pythonhosted.org/packages/7f/98/eb923e8b028cece924c246104aa800cf72e02d023a8ad4ca87135b05a2fe/librt-0.8.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bd32add59b58fba3439d48d6f36ac695830388e3da3e92e4fc26d2d02670d19c", size = 217538, upload-time = "2026-02-12T14:52:36.078Z" }, - { url = "https://files.pythonhosted.org/packages/fd/67/24e80ab170674a1d8ee9f9a83081dca4635519dbd0473b8321deecddb5be/librt-0.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4f764b2424cb04524ff7a486b9c391e93f93dc1bd8305b2136d25e582e99aa2f", size = 225110, upload-time = "2026-02-12T14:52:37.301Z" }, - { url = "https://files.pythonhosted.org/packages/d8/c7/6fbdcbd1a6e5243c7989c21d68ab967c153b391351174b4729e359d9977f/librt-0.8.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f04ca50e847abc486fa8f4107250566441e693779a5374ba211e96e238f298b9", size = 217758, upload-time = "2026-02-12T14:52:38.89Z" }, - { url = "https://files.pythonhosted.org/packages/4b/bd/4d6b36669db086e3d747434430073e14def032dd58ad97959bf7e2d06c67/librt-0.8.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:9ab3a3475a55b89b87ffd7e6665838e8458e0b596c22e0177e0f961434ec474a", size = 218384, upload-time = "2026-02-12T14:52:40.637Z" }, - { url = "https://files.pythonhosted.org/packages/50/2d/afe966beb0a8f179b132f3e95c8dd90738a23e9ebdba10f89a3f192f9366/librt-0.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3e36a8da17134ffc29373775d88c04832f9ecfab1880470661813e6c7991ef79", size = 241187, upload-time = "2026-02-12T14:52:43.55Z" }, - { url = "https://files.pythonhosted.org/packages/02/d0/6172ea4af2b538462785ab1a68e52d5c99cfb9866a7caf00fdf388299734/librt-0.8.0-cp312-cp312-win32.whl", hash = "sha256:4eb5e06ebcc668677ed6389164f52f13f71737fc8be471101fa8b4ce77baeb0c", size = 54914, upload-time = "2026-02-12T14:52:44.676Z" }, - { url = "https://files.pythonhosted.org/packages/d4/cb/ceb6ed6175612a4337ad49fb01ef594712b934b4bc88ce8a63554832eb44/librt-0.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:0a33335eb59921e77c9acc05d0e654e4e32e45b014a4d61517897c11591094f8", size = 62020, upload-time = "2026-02-12T14:52:45.676Z" }, - { url = "https://files.pythonhosted.org/packages/f1/7e/61701acbc67da74ce06ddc7ba9483e81c70f44236b2d00f6a4bfee1aacbf/librt-0.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:24a01c13a2a9bdad20997a4443ebe6e329df063d1978bbe2ebbf637878a46d1e", size = 52443, upload-time = "2026-02-12T14:52:47.218Z" }, - { url = "https://files.pythonhosted.org/packages/6d/32/3edb0bcb4113a9c8bdcd1750663a54565d255027657a5df9d90f13ee07fa/librt-0.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7f820210e21e3a8bf8fde2ae3c3d10106d4de9ead28cbfdf6d0f0f41f5b12fa1", size = 66522, upload-time = "2026-02-12T14:52:48.219Z" }, - { url = "https://files.pythonhosted.org/packages/30/ab/e8c3d05e281f5d405ebdcc5bc8ab36df23e1a4b40ac9da8c3eb9928b72b9/librt-0.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4831c44b8919e75ca0dfb52052897c1ef59fdae19d3589893fbd068f1e41afbf", size = 68658, upload-time = "2026-02-12T14:52:50.351Z" }, - { url = "https://files.pythonhosted.org/packages/7c/d3/74a206c47b7748bbc8c43942de3ed67de4c231156e148b4f9250869593df/librt-0.8.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:88c6e75540f1f10f5e0fc5e87b4b6c290f0e90d1db8c6734f670840494764af8", size = 199287, upload-time = "2026-02-12T14:52:51.938Z" }, - { url = "https://files.pythonhosted.org/packages/fa/29/ef98a9131cf12cb95771d24e4c411fda96c89dc78b09c2de4704877ebee4/librt-0.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9646178cd794704d722306c2c920c221abbf080fede3ba539d5afdec16c46dad", size = 210293, upload-time = "2026-02-12T14:52:53.128Z" }, - { url = "https://files.pythonhosted.org/packages/5b/3e/89b4968cb08c53d4c2d8b02517081dfe4b9e07a959ec143d333d76899f6c/librt-0.8.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e1af31a710e17891d9adf0dbd9a5fcd94901a3922a96499abdbf7ce658f4e01", size = 224801, upload-time = "2026-02-12T14:52:54.367Z" }, - { url = "https://files.pythonhosted.org/packages/6d/28/f38526d501f9513f8b48d78e6be4a241e15dd4b000056dc8b3f06ee9ce5d/librt-0.8.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:507e94f4bec00b2f590fbe55f48cd518a208e2474a3b90a60aa8f29136ddbada", size = 218090, upload-time = "2026-02-12T14:52:55.758Z" }, - { url = "https://files.pythonhosted.org/packages/02/ec/64e29887c5009c24dc9c397116c680caffc50286f62bd99c39e3875a2854/librt-0.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f1178e0de0c271231a660fbef9be6acdfa1d596803464706862bef6644cc1cae", size = 225483, upload-time = "2026-02-12T14:52:57.375Z" }, - { url = "https://files.pythonhosted.org/packages/ee/16/7850bdbc9f1a32d3feff2708d90c56fc0490b13f1012e438532781aa598c/librt-0.8.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:71fc517efc14f75c2f74b1f0a5d5eb4a8e06aa135c34d18eaf3522f4a53cd62d", size = 218226, upload-time = "2026-02-12T14:52:58.534Z" }, - { url = "https://files.pythonhosted.org/packages/1c/4a/166bffc992d65ddefa7c47052010a87c059b44a458ebaf8f5eba384b0533/librt-0.8.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:0583aef7e9a720dd40f26a2ad5a1bf2ccbb90059dac2b32ac516df232c701db3", size = 218755, upload-time = "2026-02-12T14:52:59.701Z" }, - { url = "https://files.pythonhosted.org/packages/da/5d/9aeee038bcc72a9cfaaee934463fe9280a73c5440d36bd3175069d2cb97b/librt-0.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5d0f76fc73480d42285c609c0ea74d79856c160fa828ff9aceab574ea4ecfd7b", size = 241617, upload-time = "2026-02-12T14:53:00.966Z" }, - { url = "https://files.pythonhosted.org/packages/64/ff/2bec6b0296b9d0402aa6ec8540aa19ebcb875d669c37800cb43d10d9c3a3/librt-0.8.0-cp313-cp313-win32.whl", hash = "sha256:e79dbc8f57de360f0ed987dc7de7be814b4803ef0e8fc6d3ff86e16798c99935", size = 54966, upload-time = "2026-02-12T14:53:02.042Z" }, - { url = "https://files.pythonhosted.org/packages/08/8d/bf44633b0182996b2c7ea69a03a5c529683fa1f6b8e45c03fe874ff40d56/librt-0.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:25b3e667cbfc9000c4740b282df599ebd91dbdcc1aa6785050e4c1d6be5329ab", size = 62000, upload-time = "2026-02-12T14:53:03.822Z" }, - { url = "https://files.pythonhosted.org/packages/5c/fd/c6472b8e0eac0925001f75e366cf5500bcb975357a65ef1f6b5749389d3a/librt-0.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:e9a3a38eb4134ad33122a6d575e6324831f930a771d951a15ce232e0237412c2", size = 52496, upload-time = "2026-02-12T14:53:04.889Z" }, - { url = "https://files.pythonhosted.org/packages/e0/13/79ebfe30cd273d7c0ce37a5f14dc489c5fb8b722a008983db2cfd57270bb/librt-0.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:421765e8c6b18e64d21c8ead315708a56fc24f44075059702e421d164575fdda", size = 66078, upload-time = "2026-02-12T14:53:06.085Z" }, - { url = "https://files.pythonhosted.org/packages/4b/8f/d11eca40b62a8d5e759239a80636386ef88adecb10d1a050b38cc0da9f9e/librt-0.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:48f84830a8f8ad7918afd743fd7c4eb558728bceab7b0e38fd5a5cf78206a556", size = 68309, upload-time = "2026-02-12T14:53:07.121Z" }, - { url = "https://files.pythonhosted.org/packages/9c/b4/f12ee70a3596db40ff3c88ec9eaa4e323f3b92f77505b4d900746706ec6a/librt-0.8.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9f09d4884f882baa39a7e36bbf3eae124c4ca2a223efb91e567381d1c55c6b06", size = 196804, upload-time = "2026-02-12T14:53:08.164Z" }, - { url = "https://files.pythonhosted.org/packages/8b/7e/70dbbdc0271fd626abe1671ad117bcd61a9a88cdc6a10ccfbfc703db1873/librt-0.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:693697133c3b32aa9b27f040e3691be210e9ac4d905061859a9ed519b1d5a376", size = 206915, upload-time = "2026-02-12T14:53:09.333Z" }, - { url = "https://files.pythonhosted.org/packages/79/13/6b9e05a635d4327608d06b3c1702166e3b3e78315846373446cf90d7b0bf/librt-0.8.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5512aae4648152abaf4d48b59890503fcbe86e85abc12fb9b096fe948bdd816", size = 221200, upload-time = "2026-02-12T14:53:10.68Z" }, - { url = "https://files.pythonhosted.org/packages/35/6c/e19a3ac53e9414de43a73d7507d2d766cd22d8ca763d29a4e072d628db42/librt-0.8.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:995d24caa6bbb34bcdd4a41df98ac6d1af637cfa8975cb0790e47d6623e70e3e", size = 214640, upload-time = "2026-02-12T14:53:12.342Z" }, - { url = "https://files.pythonhosted.org/packages/30/f0/23a78464788619e8c70f090cfd099cce4973eed142c4dccb99fc322283fd/librt-0.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b9aef96d7593584e31ef6ac1eb9775355b0099fee7651fae3a15bc8657b67b52", size = 221980, upload-time = "2026-02-12T14:53:13.603Z" }, - { url = "https://files.pythonhosted.org/packages/03/32/38e21420c5d7aa8a8bd2c7a7d5252ab174a5a8aaec8b5551968979b747bf/librt-0.8.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:4f6e975377fbc4c9567cb33ea9ab826031b6c7ec0515bfae66a4fb110d40d6da", size = 215146, upload-time = "2026-02-12T14:53:14.8Z" }, - { url = "https://files.pythonhosted.org/packages/bb/00/bd9ecf38b1824c25240b3ad982fb62c80f0a969e6679091ba2b3afb2b510/librt-0.8.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:daae5e955764be8fd70a93e9e5133c75297f8bce1e802e1d3683b98f77e1c5ab", size = 215203, upload-time = "2026-02-12T14:53:16.087Z" }, - { url = "https://files.pythonhosted.org/packages/b9/60/7559bcc5279d37810b98d4a52616febd7b8eef04391714fd6bdf629598b1/librt-0.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7bd68cebf3131bb920d5984f75fe302d758db33264e44b45ad139385662d7bc3", size = 237937, upload-time = "2026-02-12T14:53:17.236Z" }, - { url = "https://files.pythonhosted.org/packages/41/cc/be3e7da88f1abbe2642672af1dc00a0bccece11ca60241b1883f3018d8d5/librt-0.8.0-cp314-cp314-win32.whl", hash = "sha256:1e6811cac1dcb27ca4c74e0ca4a5917a8e06db0d8408d30daee3a41724bfde7a", size = 50685, upload-time = "2026-02-12T14:53:18.888Z" }, - { url = "https://files.pythonhosted.org/packages/38/27/e381d0df182a8f61ef1f6025d8b138b3318cc9d18ad4d5f47c3bf7492523/librt-0.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:178707cda89d910c3b28bf5aa5f69d3d4734e0f6ae102f753ad79edef83a83c7", size = 57872, upload-time = "2026-02-12T14:53:19.942Z" }, - { url = "https://files.pythonhosted.org/packages/c5/0c/ca9dfdf00554a44dea7d555001248269a4bab569e1590a91391feb863fa4/librt-0.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:3e8b77b5f54d0937b26512774916041756c9eb3e66f1031971e626eea49d0bf4", size = 48056, upload-time = "2026-02-12T14:53:21.473Z" }, - { url = "https://files.pythonhosted.org/packages/f2/ed/6cc9c4ad24f90c8e782193c7b4a857408fd49540800613d1356c63567d7b/librt-0.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:789911e8fa40a2e82f41120c936b1965f3213c67f5a483fc5a41f5839a05dcbb", size = 68307, upload-time = "2026-02-12T14:53:22.498Z" }, - { url = "https://files.pythonhosted.org/packages/84/d8/0e94292c6b3e00b6eeea39dd44d5703d1ec29b6dafce7eea19dc8f1aedbd/librt-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2b37437e7e4ef5e15a297b36ba9e577f73e29564131d86dd75875705e97402b5", size = 70999, upload-time = "2026-02-12T14:53:23.603Z" }, - { url = "https://files.pythonhosted.org/packages/0e/f4/6be1afcbdeedbdbbf54a7c9d73ad43e1bf36897cebf3978308cd64922e02/librt-0.8.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:671a6152edf3b924d98a5ed5e6982ec9cb30894085482acadce0975f031d4c5c", size = 220782, upload-time = "2026-02-12T14:53:25.133Z" }, - { url = "https://files.pythonhosted.org/packages/f0/8d/f306e8caa93cfaf5c6c9e0d940908d75dc6af4fd856baa5535c922ee02b1/librt-0.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8992ca186a1678107b0af3d0c9303d8c7305981b9914989b9788319ed4d89546", size = 235420, upload-time = "2026-02-12T14:53:27.047Z" }, - { url = "https://files.pythonhosted.org/packages/d6/f2/65d86bd462e9c351326564ca805e8457442149f348496e25ccd94583ffa2/librt-0.8.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:001e5330093d887b8b9165823eca6c5c4db183fe4edea4fdc0680bbac5f46944", size = 246452, upload-time = "2026-02-12T14:53:28.341Z" }, - { url = "https://files.pythonhosted.org/packages/03/94/39c88b503b4cb3fcbdeb3caa29672b6b44ebee8dcc8a54d49839ac280f3f/librt-0.8.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d920789eca7ef71df7f31fd547ec0d3002e04d77f30ba6881e08a630e7b2c30e", size = 238891, upload-time = "2026-02-12T14:53:29.625Z" }, - { url = "https://files.pythonhosted.org/packages/e3/c6/6c0d68190893d01b71b9569b07a1c811e280c0065a791249921c83dc0290/librt-0.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:82fb4602d1b3e303a58bfe6165992b5a78d823ec646445356c332cd5f5bbaa61", size = 250249, upload-time = "2026-02-12T14:53:30.93Z" }, - { url = "https://files.pythonhosted.org/packages/52/7a/f715ed9e039035d0ea637579c3c0155ab3709a7046bc408c0fb05d337121/librt-0.8.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:4d3e38797eb482485b486898f89415a6ab163bc291476bd95712e42cf4383c05", size = 240642, upload-time = "2026-02-12T14:53:32.174Z" }, - { url = "https://files.pythonhosted.org/packages/c2/3c/609000a333debf5992efe087edc6467c1fdbdddca5b610355569bbea9589/librt-0.8.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:a905091a13e0884701226860836d0386b88c72ce5c2fdfba6618e14c72be9f25", size = 239621, upload-time = "2026-02-12T14:53:33.39Z" }, - { url = "https://files.pythonhosted.org/packages/b9/df/87b0673d5c395a8f34f38569c116c93142d4dc7e04af2510620772d6bd4f/librt-0.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:375eda7acfce1f15f5ed56cfc960669eefa1ec8732e3e9087c3c4c3f2066759c", size = 262986, upload-time = "2026-02-12T14:53:34.617Z" }, - { url = "https://files.pythonhosted.org/packages/09/7f/6bbbe9dcda649684773aaea78b87fff4d7e59550fbc2877faa83612087a3/librt-0.8.0-cp314-cp314t-win32.whl", hash = "sha256:2ccdd20d9a72c562ffb73098ac411de351b53a6fbb3390903b2d33078ef90447", size = 51328, upload-time = "2026-02-12T14:53:36.15Z" }, - { url = "https://files.pythonhosted.org/packages/bb/f3/e1981ab6fa9b41be0396648b5850267888a752d025313a9e929c4856208e/librt-0.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:25e82d920d4d62ad741592fcf8d0f3bda0e3fc388a184cb7d2f566c681c5f7b9", size = 58719, upload-time = "2026-02-12T14:53:37.183Z" }, - { url = "https://files.pythonhosted.org/packages/94/d1/433b3c06e78f23486fe4fdd19bc134657eb30997d2054b0dbf52bbf3382e/librt-0.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:92249938ab744a5890580d3cb2b22042f0dce71cdaa7c1369823df62bedf7cbc", size = 48753, upload-time = "2026-02-12T14:53:38.539Z" }, - { url = "https://files.pythonhosted.org/packages/c5/dd/e0c82032d11fbc535ddbd4b955104fbe8e5202c0c42d982125a74e30f802/librt-0.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4b705f85311ee76acec5ee70806990a51f0deb519ea0c29c1d1652d79127604d", size = 65982, upload-time = "2026-02-12T14:53:39.597Z" }, - { url = "https://files.pythonhosted.org/packages/11/a2/55de2f768ce1f80029211bbbbedf7b22032145730b1aae92bb118a2bde40/librt-0.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7ce0a8cb67e702dcb06342b2aaaa3da9fb0ddc670417879adfa088b44cf7b3b6", size = 68638, upload-time = "2026-02-12T14:53:40.727Z" }, - { url = "https://files.pythonhosted.org/packages/52/fc/ae3b63d02b84f5afc06b822264d1b9d411f6286c58d8d9caa49d9cc0c68c/librt-0.8.0-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:aaadec87f45a3612b6818d1db5fbfe93630669b7ee5d6bdb6427ae08a1aa2141", size = 196099, upload-time = "2026-02-12T14:53:42.297Z" }, - { url = "https://files.pythonhosted.org/packages/2c/3a/c9dc547bbaaef571d5dbd8249674c4baf7ecb689e2b25c8ff6227d85c751/librt-0.8.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56901f1eec031396f230db71c59a01d450715cbbef9856bf636726994331195d", size = 206678, upload-time = "2026-02-12T14:53:43.652Z" }, - { url = "https://files.pythonhosted.org/packages/df/97/ccab8bea6d5d49f22df87b237fb43f194e05b46e3892ede5785824ecdc48/librt-0.8.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b055bb3abaf69abed25743d8fc1ab691e4f51a912ee0a6f9a6c84f4bbddb283d", size = 219308, upload-time = "2026-02-12T14:53:44.896Z" }, - { url = "https://files.pythonhosted.org/packages/65/2b/bf86e2a084a49b25030bd2848956e34ec2faa18c5e29e9c829f9c52dceb8/librt-0.8.0-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1ef3bd856373cf8e7382402731f43bfe978a8613b4039e49e166e1e0dc590216", size = 212212, upload-time = "2026-02-12T14:53:46.166Z" }, - { url = "https://files.pythonhosted.org/packages/17/8d/d297a8bbf20b896b114d4751e2aa0539f97923ec9c91ded2ee17bdfd043d/librt-0.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2e0ffe88ebb5962f8fb0ddcbaaff30f1ea06a79501069310e1e030eafb1ad787", size = 220670, upload-time = "2026-02-12T14:53:47.412Z" }, - { url = "https://files.pythonhosted.org/packages/d5/50/21feb3c235e4c4c538aa6f5a45a9b736f6ff868d0733fb97bdec486a9bf8/librt-0.8.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:82e61cd1c563745ad495387c3b65806bfd453badb4adbc019df3389dddee1bf6", size = 216182, upload-time = "2026-02-12T14:53:48.683Z" }, - { url = "https://files.pythonhosted.org/packages/29/5c/1fdaafb7062a9587a59bb01d6fac70355f0c84caa4fa14d67d847a6cd2e6/librt-0.8.0-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:667e2513cf69bfd1e1ed9a00d6c736d5108714ec071192afb737987955888a25", size = 214133, upload-time = "2026-02-12T14:53:49.983Z" }, - { url = "https://files.pythonhosted.org/packages/57/a6/001e085e16c77cfc5d7cc74c8c05dc80733251b362b3167e33c832813ad8/librt-0.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6b6caff69e25d80c269b1952be8493b4d94ef745f438fa619d7931066bdd26de", size = 236650, upload-time = "2026-02-12T14:53:51.263Z" }, - { url = "https://files.pythonhosted.org/packages/00/03/516075b2c0dac3ff6c88221f8e4f86dc6576a6e90e694558e0b71217427b/librt-0.8.0-cp39-cp39-win32.whl", hash = "sha256:02a9fe85410cc9bef045e7cb7fd26fdde6669e6d173f99df659aa7f6335961e9", size = 54369, upload-time = "2026-02-12T14:53:52.514Z" }, - { url = "https://files.pythonhosted.org/packages/bd/c9/710ab8320072000439d1b57b5ed63f6b1dc2f61345aafaff53df9ae9dc15/librt-0.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:de076eaba208d16efb5962f99539867f8e2c73480988cb513fcf1b5dbb0c9dcf", size = 61505, upload-time = "2026-02-12T14:53:53.658Z" }, +version = "0.8.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/56/9c/b4b0c54d84da4a94b37bd44151e46d5e583c9534c7e02250b961b1b6d8a8/librt-0.8.1.tar.gz", hash = "sha256:be46a14693955b3bd96014ccbdb8339ee8c9346fbe11c1b78901b55125f14c73", size = 177471, upload-time = "2026-02-17T16:13:06.101Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/5f/63f5fa395c7a8a93558c0904ba8f1c8d1b997ca6a3de61bc7659970d66bf/librt-0.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:81fd938344fecb9373ba1b155968c8a329491d2ce38e7ddb76f30ffb938f12dc", size = 65697, upload-time = "2026-02-17T16:11:06.903Z" }, + { url = "https://files.pythonhosted.org/packages/ff/e0/0472cf37267b5920eff2f292ccfaede1886288ce35b7f3203d8de00abfe6/librt-0.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5db05697c82b3a2ec53f6e72b2ed373132b0c2e05135f0696784e97d7f5d48e7", size = 68376, upload-time = "2026-02-17T16:11:08.395Z" }, + { url = "https://files.pythonhosted.org/packages/c8/be/8bd1359fdcd27ab897cd5963294fa4a7c83b20a8564678e4fd12157e56a5/librt-0.8.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d56bc4011975f7460bea7b33e1ff425d2f1adf419935ff6707273c77f8a4ada6", size = 197084, upload-time = "2026-02-17T16:11:09.774Z" }, + { url = "https://files.pythonhosted.org/packages/e2/fe/163e33fdd091d0c2b102f8a60cc0a61fd730ad44e32617cd161e7cd67a01/librt-0.8.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cdc0f588ff4b663ea96c26d2a230c525c6fc62b28314edaaaca8ed5af931ad0", size = 207337, upload-time = "2026-02-17T16:11:11.311Z" }, + { url = "https://files.pythonhosted.org/packages/01/99/f85130582f05dcf0c8902f3d629270231d2f4afdfc567f8305a952ac7f14/librt-0.8.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:97c2b54ff6717a7a563b72627990bec60d8029df17df423f0ed37d56a17a176b", size = 219980, upload-time = "2026-02-17T16:11:12.499Z" }, + { url = "https://files.pythonhosted.org/packages/6f/54/cb5e4d03659e043a26c74e08206412ac9a3742f0477d96f9761a55313b5f/librt-0.8.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8f1125e6bbf2f1657d9a2f3ccc4a2c9b0c8b176965bb565dd4d86be67eddb4b6", size = 212921, upload-time = "2026-02-17T16:11:14.484Z" }, + { url = "https://files.pythonhosted.org/packages/b1/81/a3a01e4240579c30f3487f6fed01eb4bc8ef0616da5b4ebac27ca19775f3/librt-0.8.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8f4bb453f408137d7581be309b2fbc6868a80e7ef60c88e689078ee3a296ae71", size = 221381, upload-time = "2026-02-17T16:11:17.459Z" }, + { url = "https://files.pythonhosted.org/packages/08/b0/fc2d54b4b1c6fb81e77288ff31ff25a2c1e62eaef4424a984f228839717b/librt-0.8.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c336d61d2fe74a3195edc1646d53ff1cddd3a9600b09fa6ab75e5514ba4862a7", size = 216714, upload-time = "2026-02-17T16:11:19.197Z" }, + { url = "https://files.pythonhosted.org/packages/96/96/85daa73ffbd87e1fb287d7af6553ada66bf25a2a6b0de4764344a05469f6/librt-0.8.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:eb5656019db7c4deacf0c1a55a898c5bb8f989be904597fcb5232a2f4828fa05", size = 214777, upload-time = "2026-02-17T16:11:20.443Z" }, + { url = "https://files.pythonhosted.org/packages/12/9c/c3aa7a2360383f4bf4f04d98195f2739a579128720c603f4807f006a4225/librt-0.8.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c25d9e338d5bed46c1632f851babf3d13c78f49a225462017cf5e11e845c5891", size = 237398, upload-time = "2026-02-17T16:11:22.083Z" }, + { url = "https://files.pythonhosted.org/packages/61/19/d350ea89e5274665185dabc4bbb9c3536c3411f862881d316c8b8e00eb66/librt-0.8.1-cp310-cp310-win32.whl", hash = "sha256:aaab0e307e344cb28d800957ef3ec16605146ef0e59e059a60a176d19543d1b7", size = 54285, upload-time = "2026-02-17T16:11:23.27Z" }, + { url = "https://files.pythonhosted.org/packages/4f/d6/45d587d3d41c112e9543a0093d883eb57a24a03e41561c127818aa2a6bcc/librt-0.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:56e04c14b696300d47b3bc5f1d10a00e86ae978886d0cee14e5714fafb5df5d2", size = 61352, upload-time = "2026-02-17T16:11:24.207Z" }, + { url = "https://files.pythonhosted.org/packages/1d/01/0e748af5e4fee180cf7cd12bd12b0513ad23b045dccb2a83191bde82d168/librt-0.8.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:681dc2451d6d846794a828c16c22dc452d924e9f700a485b7ecb887a30aad1fd", size = 65315, upload-time = "2026-02-17T16:11:25.152Z" }, + { url = "https://files.pythonhosted.org/packages/9d/4d/7184806efda571887c798d573ca4134c80ac8642dcdd32f12c31b939c595/librt-0.8.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3b4350b13cc0e6f5bec8fa7caf29a8fb8cdc051a3bae45cfbfd7ce64f009965", size = 68021, upload-time = "2026-02-17T16:11:26.129Z" }, + { url = "https://files.pythonhosted.org/packages/ae/88/c3c52d2a5d5101f28d3dc89298444626e7874aa904eed498464c2af17627/librt-0.8.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ac1e7817fd0ed3d14fd7c5df91daed84c48e4c2a11ee99c0547f9f62fdae13da", size = 194500, upload-time = "2026-02-17T16:11:27.177Z" }, + { url = "https://files.pythonhosted.org/packages/d6/5d/6fb0a25b6a8906e85b2c3b87bee1d6ed31510be7605b06772f9374ca5cb3/librt-0.8.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:747328be0c5b7075cde86a0e09d7a9196029800ba75a1689332348e998fb85c0", size = 205622, upload-time = "2026-02-17T16:11:28.242Z" }, + { url = "https://files.pythonhosted.org/packages/b2/a6/8006ae81227105476a45691f5831499e4d936b1c049b0c1feb17c11b02d1/librt-0.8.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f0af2bd2bc204fa27f3d6711d0f360e6b8c684a035206257a81673ab924aa11e", size = 218304, upload-time = "2026-02-17T16:11:29.344Z" }, + { url = "https://files.pythonhosted.org/packages/ee/19/60e07886ad16670aae57ef44dada41912c90906a6fe9f2b9abac21374748/librt-0.8.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d480de377f5b687b6b1bc0c0407426da556e2a757633cc7e4d2e1a057aa688f3", size = 211493, upload-time = "2026-02-17T16:11:30.445Z" }, + { url = "https://files.pythonhosted.org/packages/9c/cf/f666c89d0e861d05600438213feeb818c7514d3315bae3648b1fc145d2b6/librt-0.8.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d0ee06b5b5291f609ddb37b9750985b27bc567791bc87c76a569b3feed8481ac", size = 219129, upload-time = "2026-02-17T16:11:32.021Z" }, + { url = "https://files.pythonhosted.org/packages/8f/ef/f1bea01e40b4a879364c031476c82a0dc69ce068daad67ab96302fed2d45/librt-0.8.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9e2c6f77b9ad48ce5603b83b7da9ee3e36b3ab425353f695cba13200c5d96596", size = 213113, upload-time = "2026-02-17T16:11:33.192Z" }, + { url = "https://files.pythonhosted.org/packages/9b/80/cdab544370cc6bc1b72ea369525f547a59e6938ef6863a11ab3cd24759af/librt-0.8.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:439352ba9373f11cb8e1933da194dcc6206daf779ff8df0ed69c5e39113e6a99", size = 212269, upload-time = "2026-02-17T16:11:34.373Z" }, + { url = "https://files.pythonhosted.org/packages/9d/9c/48d6ed8dac595654f15eceab2035131c136d1ae9a1e3548e777bb6dbb95d/librt-0.8.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:82210adabbc331dbb65d7868b105185464ef13f56f7f76688565ad79f648b0fe", size = 234673, upload-time = "2026-02-17T16:11:36.063Z" }, + { url = "https://files.pythonhosted.org/packages/16/01/35b68b1db517f27a01be4467593292eb5315def8900afad29fabf56304ba/librt-0.8.1-cp311-cp311-win32.whl", hash = "sha256:52c224e14614b750c0a6d97368e16804a98c684657c7518752c356834fff83bb", size = 54597, upload-time = "2026-02-17T16:11:37.544Z" }, + { url = "https://files.pythonhosted.org/packages/71/02/796fe8f02822235966693f257bf2c79f40e11337337a657a8cfebba5febc/librt-0.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:c00e5c884f528c9932d278d5c9cbbea38a6b81eb62c02e06ae53751a83a4d52b", size = 61733, upload-time = "2026-02-17T16:11:38.691Z" }, + { url = "https://files.pythonhosted.org/packages/28/ad/232e13d61f879a42a4e7117d65e4984bb28371a34bb6fb9ca54ec2c8f54e/librt-0.8.1-cp311-cp311-win_arm64.whl", hash = "sha256:f7cdf7f26c2286ffb02e46d7bac56c94655540b26347673bea15fa52a6af17e9", size = 52273, upload-time = "2026-02-17T16:11:40.308Z" }, + { url = "https://files.pythonhosted.org/packages/95/21/d39b0a87ac52fc98f621fb6f8060efb017a767ebbbac2f99fbcbc9ddc0d7/librt-0.8.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a28f2612ab566b17f3698b0da021ff9960610301607c9a5e8eaca62f5e1c350a", size = 66516, upload-time = "2026-02-17T16:11:41.604Z" }, + { url = "https://files.pythonhosted.org/packages/69/f1/46375e71441c43e8ae335905e069f1c54febee63a146278bcee8782c84fd/librt-0.8.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:60a78b694c9aee2a0f1aaeaa7d101cf713e92e8423a941d2897f4fa37908dab9", size = 68634, upload-time = "2026-02-17T16:11:43.268Z" }, + { url = "https://files.pythonhosted.org/packages/0a/33/c510de7f93bf1fa19e13423a606d8189a02624a800710f6e6a0a0f0784b3/librt-0.8.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:758509ea3f1eba2a57558e7e98f4659d0ea7670bff49673b0dde18a3c7e6c0eb", size = 198941, upload-time = "2026-02-17T16:11:44.28Z" }, + { url = "https://files.pythonhosted.org/packages/dd/36/e725903416409a533d92398e88ce665476f275081d0d7d42f9c4951999e5/librt-0.8.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:039b9f2c506bd0ab0f8725aa5ba339c6f0cd19d3b514b50d134789809c24285d", size = 209991, upload-time = "2026-02-17T16:11:45.462Z" }, + { url = "https://files.pythonhosted.org/packages/30/7a/8d908a152e1875c9f8eac96c97a480df425e657cdb47854b9efaa4998889/librt-0.8.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bb54f1205a3a6ab41a6fd71dfcdcbd278670d3a90ca502a30d9da583105b6f7", size = 224476, upload-time = "2026-02-17T16:11:46.542Z" }, + { url = "https://files.pythonhosted.org/packages/a8/b8/a22c34f2c485b8903a06f3fe3315341fe6876ef3599792344669db98fcff/librt-0.8.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:05bd41cdee35b0c59c259f870f6da532a2c5ca57db95b5f23689fcb5c9e42440", size = 217518, upload-time = "2026-02-17T16:11:47.746Z" }, + { url = "https://files.pythonhosted.org/packages/79/6f/5c6fea00357e4f82ba44f81dbfb027921f1ab10e320d4a64e1c408d035d9/librt-0.8.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adfab487facf03f0d0857b8710cf82d0704a309d8ffc33b03d9302b4c64e91a9", size = 225116, upload-time = "2026-02-17T16:11:49.298Z" }, + { url = "https://files.pythonhosted.org/packages/f2/a0/95ced4e7b1267fe1e2720a111685bcddf0e781f7e9e0ce59d751c44dcfe5/librt-0.8.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:153188fe98a72f206042be10a2c6026139852805215ed9539186312d50a8e972", size = 217751, upload-time = "2026-02-17T16:11:50.49Z" }, + { url = "https://files.pythonhosted.org/packages/93/c2/0517281cb4d4101c27ab59472924e67f55e375bc46bedae94ac6dc6e1902/librt-0.8.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:dd3c41254ee98604b08bd5b3af5bf0a89740d4ee0711de95b65166bf44091921", size = 218378, upload-time = "2026-02-17T16:11:51.783Z" }, + { url = "https://files.pythonhosted.org/packages/43/e8/37b3ac108e8976888e559a7b227d0ceac03c384cfd3e7a1c2ee248dbae79/librt-0.8.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e0d138c7ae532908cbb342162b2611dbd4d90c941cd25ab82084aaf71d2c0bd0", size = 241199, upload-time = "2026-02-17T16:11:53.561Z" }, + { url = "https://files.pythonhosted.org/packages/4b/5b/35812d041c53967fedf551a39399271bbe4257e681236a2cf1a69c8e7fa1/librt-0.8.1-cp312-cp312-win32.whl", hash = "sha256:43353b943613c5d9c49a25aaffdba46f888ec354e71e3529a00cca3f04d66a7a", size = 54917, upload-time = "2026-02-17T16:11:54.758Z" }, + { url = "https://files.pythonhosted.org/packages/de/d1/fa5d5331b862b9775aaf2a100f5ef86854e5d4407f71bddf102f4421e034/librt-0.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:ff8baf1f8d3f4b6b7257fcb75a501f2a5499d0dda57645baa09d4d0d34b19444", size = 62017, upload-time = "2026-02-17T16:11:55.748Z" }, + { url = "https://files.pythonhosted.org/packages/c7/7c/c614252f9acda59b01a66e2ddfd243ed1c7e1deab0293332dfbccf862808/librt-0.8.1-cp312-cp312-win_arm64.whl", hash = "sha256:0f2ae3725904f7377e11cc37722d5d401e8b3d5851fb9273d7f4fe04f6b3d37d", size = 52441, upload-time = "2026-02-17T16:11:56.801Z" }, + { url = "https://files.pythonhosted.org/packages/c5/3c/f614c8e4eaac7cbf2bbdf9528790b21d89e277ee20d57dc6e559c626105f/librt-0.8.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7e6bad1cd94f6764e1e21950542f818a09316645337fd5ab9a7acc45d99a8f35", size = 66529, upload-time = "2026-02-17T16:11:57.809Z" }, + { url = "https://files.pythonhosted.org/packages/ab/96/5836544a45100ae411eda07d29e3d99448e5258b6e9c8059deb92945f5c2/librt-0.8.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cf450f498c30af55551ba4f66b9123b7185362ec8b625a773b3d39aa1a717583", size = 68669, upload-time = "2026-02-17T16:11:58.843Z" }, + { url = "https://files.pythonhosted.org/packages/06/53/f0b992b57af6d5531bf4677d75c44f095f2366a1741fb695ee462ae04b05/librt-0.8.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:eca45e982fa074090057132e30585a7e8674e9e885d402eae85633e9f449ce6c", size = 199279, upload-time = "2026-02-17T16:11:59.862Z" }, + { url = "https://files.pythonhosted.org/packages/f3/ad/4848cc16e268d14280d8168aee4f31cea92bbd2b79ce33d3e166f2b4e4fc/librt-0.8.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c3811485fccfda840861905b8c70bba5ec094e02825598bb9d4ca3936857a04", size = 210288, upload-time = "2026-02-17T16:12:00.954Z" }, + { url = "https://files.pythonhosted.org/packages/52/05/27fdc2e95de26273d83b96742d8d3b7345f2ea2bdbd2405cc504644f2096/librt-0.8.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e4af413908f77294605e28cfd98063f54b2c790561383971d2f52d113d9c363", size = 224809, upload-time = "2026-02-17T16:12:02.108Z" }, + { url = "https://files.pythonhosted.org/packages/7a/d0/78200a45ba3240cb042bc597d6f2accba9193a2c57d0356268cbbe2d0925/librt-0.8.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5212a5bd7fae98dae95710032902edcd2ec4dc994e883294f75c857b83f9aba0", size = 218075, upload-time = "2026-02-17T16:12:03.631Z" }, + { url = "https://files.pythonhosted.org/packages/af/72/a210839fa74c90474897124c064ffca07f8d4b347b6574d309686aae7ca6/librt-0.8.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e692aa2d1d604e6ca12d35e51fdc36f4cda6345e28e36374579f7ef3611b3012", size = 225486, upload-time = "2026-02-17T16:12:04.725Z" }, + { url = "https://files.pythonhosted.org/packages/a3/c1/a03cc63722339ddbf087485f253493e2b013039f5b707e8e6016141130fa/librt-0.8.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4be2a5c926b9770c9e08e717f05737a269b9d0ebc5d2f0060f0fe3fe9ce47acb", size = 218219, upload-time = "2026-02-17T16:12:05.828Z" }, + { url = "https://files.pythonhosted.org/packages/58/f5/fff6108af0acf941c6f274a946aea0e484bd10cd2dc37610287ce49388c5/librt-0.8.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fd1a720332ea335ceb544cf0a03f81df92abd4bb887679fd1e460976b0e6214b", size = 218750, upload-time = "2026-02-17T16:12:07.09Z" }, + { url = "https://files.pythonhosted.org/packages/71/67/5a387bfef30ec1e4b4f30562c8586566faf87e47d696768c19feb49e3646/librt-0.8.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2af9e01e0ef80d95ae3c720be101227edae5f2fe7e3dc63d8857fadfc5a1d", size = 241624, upload-time = "2026-02-17T16:12:08.43Z" }, + { url = "https://files.pythonhosted.org/packages/d4/be/24f8502db11d405232ac1162eb98069ca49c3306c1d75c6ccc61d9af8789/librt-0.8.1-cp313-cp313-win32.whl", hash = "sha256:086a32dbb71336627e78cc1d6ee305a68d038ef7d4c39aaff41ae8c9aa46e91a", size = 54969, upload-time = "2026-02-17T16:12:09.633Z" }, + { url = "https://files.pythonhosted.org/packages/5c/73/c9fdf6cb2a529c1a092ce769a12d88c8cca991194dfe641b6af12fa964d2/librt-0.8.1-cp313-cp313-win_amd64.whl", hash = "sha256:e11769a1dbda4da7b00a76cfffa67aa47cfa66921d2724539eee4b9ede780b79", size = 62000, upload-time = "2026-02-17T16:12:10.632Z" }, + { url = "https://files.pythonhosted.org/packages/d3/97/68f80ca3ac4924f250cdfa6e20142a803e5e50fca96ef5148c52ee8c10ea/librt-0.8.1-cp313-cp313-win_arm64.whl", hash = "sha256:924817ab3141aca17893386ee13261f1d100d1ef410d70afe4389f2359fea4f0", size = 52495, upload-time = "2026-02-17T16:12:11.633Z" }, + { url = "https://files.pythonhosted.org/packages/c9/6a/907ef6800f7bca71b525a05f1839b21f708c09043b1c6aa77b6b827b3996/librt-0.8.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6cfa7fe54fd4d1f47130017351a959fe5804bda7a0bc7e07a2cdbc3fdd28d34f", size = 66081, upload-time = "2026-02-17T16:12:12.766Z" }, + { url = "https://files.pythonhosted.org/packages/1b/18/25e991cd5640c9fb0f8d91b18797b29066b792f17bf8493da183bf5caabe/librt-0.8.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:228c2409c079f8c11fb2e5d7b277077f694cb93443eb760e00b3b83cb8b3176c", size = 68309, upload-time = "2026-02-17T16:12:13.756Z" }, + { url = "https://files.pythonhosted.org/packages/a4/36/46820d03f058cfb5a9de5940640ba03165ed8aded69e0733c417bb04df34/librt-0.8.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7aae78ab5e3206181780e56912d1b9bb9f90a7249ce12f0e8bf531d0462dd0fc", size = 196804, upload-time = "2026-02-17T16:12:14.818Z" }, + { url = "https://files.pythonhosted.org/packages/59/18/5dd0d3b87b8ff9c061849fbdb347758d1f724b9a82241aa908e0ec54ccd0/librt-0.8.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:172d57ec04346b047ca6af181e1ea4858086c80bdf455f61994c4aa6fc3f866c", size = 206907, upload-time = "2026-02-17T16:12:16.513Z" }, + { url = "https://files.pythonhosted.org/packages/d1/96/ef04902aad1424fd7299b62d1890e803e6ab4018c3044dca5922319c4b97/librt-0.8.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6b1977c4ea97ce5eb7755a78fae68d87e4102e4aaf54985e8b56806849cc06a3", size = 221217, upload-time = "2026-02-17T16:12:17.906Z" }, + { url = "https://files.pythonhosted.org/packages/6d/ff/7e01f2dda84a8f5d280637a2e5827210a8acca9a567a54507ef1c75b342d/librt-0.8.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:10c42e1f6fd06733ef65ae7bebce2872bcafd8d6e6b0a08fe0a05a23b044fb14", size = 214622, upload-time = "2026-02-17T16:12:19.108Z" }, + { url = "https://files.pythonhosted.org/packages/1e/8c/5b093d08a13946034fed57619742f790faf77058558b14ca36a6e331161e/librt-0.8.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4c8dfa264b9193c4ee19113c985c95f876fae5e51f731494fc4e0cf594990ba7", size = 221987, upload-time = "2026-02-17T16:12:20.331Z" }, + { url = "https://files.pythonhosted.org/packages/d3/cc/86b0b3b151d40920ad45a94ce0171dec1aebba8a9d72bb3fa00c73ab25dd/librt-0.8.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:01170b6729a438f0dedc4a26ed342e3dc4f02d1000b4b19f980e1877f0c297e6", size = 215132, upload-time = "2026-02-17T16:12:21.54Z" }, + { url = "https://files.pythonhosted.org/packages/fc/be/8588164a46edf1e69858d952654e216a9a91174688eeefb9efbb38a9c799/librt-0.8.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:7b02679a0d783bdae30d443025b94465d8c3dc512f32f5b5031f93f57ac32071", size = 215195, upload-time = "2026-02-17T16:12:23.073Z" }, + { url = "https://files.pythonhosted.org/packages/f5/f2/0b9279bea735c734d69344ecfe056c1ba211694a72df10f568745c899c76/librt-0.8.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:190b109bb69592a3401fe1ffdea41a2e73370ace2ffdc4a0e8e2b39cdea81b78", size = 237946, upload-time = "2026-02-17T16:12:24.275Z" }, + { url = "https://files.pythonhosted.org/packages/e9/cc/5f2a34fbc8aeb35314a3641f9956fa9051a947424652fad9882be7a97949/librt-0.8.1-cp314-cp314-win32.whl", hash = "sha256:e70a57ecf89a0f64c24e37f38d3fe217a58169d2fe6ed6d70554964042474023", size = 50689, upload-time = "2026-02-17T16:12:25.766Z" }, + { url = "https://files.pythonhosted.org/packages/a0/76/cd4d010ab2147339ca2b93e959c3686e964edc6de66ddacc935c325883d7/librt-0.8.1-cp314-cp314-win_amd64.whl", hash = "sha256:7e2f3edca35664499fbb36e4770650c4bd4a08abc1f4458eab9df4ec56389730", size = 57875, upload-time = "2026-02-17T16:12:27.465Z" }, + { url = "https://files.pythonhosted.org/packages/84/0f/2143cb3c3ca48bd3379dcd11817163ca50781927c4537345d608b5045998/librt-0.8.1-cp314-cp314-win_arm64.whl", hash = "sha256:0d2f82168e55ddefd27c01c654ce52379c0750ddc31ee86b4b266bcf4d65f2a3", size = 48058, upload-time = "2026-02-17T16:12:28.556Z" }, + { url = "https://files.pythonhosted.org/packages/d2/0e/9b23a87e37baf00311c3efe6b48d6b6c168c29902dfc3f04c338372fd7db/librt-0.8.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2c74a2da57a094bd48d03fa5d196da83d2815678385d2978657499063709abe1", size = 68313, upload-time = "2026-02-17T16:12:29.659Z" }, + { url = "https://files.pythonhosted.org/packages/db/9a/859c41e5a4f1c84200a7d2b92f586aa27133c8243b6cac9926f6e54d01b9/librt-0.8.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a355d99c4c0d8e5b770313b8b247411ed40949ca44e33e46a4789b9293a907ee", size = 70994, upload-time = "2026-02-17T16:12:31.516Z" }, + { url = "https://files.pythonhosted.org/packages/4c/28/10605366ee599ed34223ac2bf66404c6fb59399f47108215d16d5ad751a8/librt-0.8.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2eb345e8b33fb748227409c9f1233d4df354d6e54091f0e8fc53acdb2ffedeb7", size = 220770, upload-time = "2026-02-17T16:12:33.294Z" }, + { url = "https://files.pythonhosted.org/packages/af/8d/16ed8fd452dafae9c48d17a6bc1ee3e818fd40ef718d149a8eff2c9f4ea2/librt-0.8.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9be2f15e53ce4e83cc08adc29b26fb5978db62ef2a366fbdf716c8a6c8901040", size = 235409, upload-time = "2026-02-17T16:12:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/89/1b/7bdf3e49349c134b25db816e4a3db6b94a47ac69d7d46b1e682c2c4949be/librt-0.8.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:785ae29c1f5c6e7c2cde2c7c0e148147f4503da3abc5d44d482068da5322fd9e", size = 246473, upload-time = "2026-02-17T16:12:36.656Z" }, + { url = "https://files.pythonhosted.org/packages/4e/8a/91fab8e4fd2a24930a17188c7af5380eb27b203d72101c9cc000dbdfd95a/librt-0.8.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1d3a7da44baf692f0c6aeb5b2a09c5e6fc7a703bca9ffa337ddd2e2da53f7732", size = 238866, upload-time = "2026-02-17T16:12:37.849Z" }, + { url = "https://files.pythonhosted.org/packages/b9/e0/c45a098843fc7c07e18a7f8a24ca8496aecbf7bdcd54980c6ca1aaa79a8e/librt-0.8.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5fc48998000cbc39ec0d5311312dda93ecf92b39aaf184c5e817d5d440b29624", size = 250248, upload-time = "2026-02-17T16:12:39.445Z" }, + { url = "https://files.pythonhosted.org/packages/82/30/07627de23036640c952cce0c1fe78972e77d7d2f8fd54fa5ef4554ff4a56/librt-0.8.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e96baa6820280077a78244b2e06e416480ed859bbd8e5d641cf5742919d8beb4", size = 240629, upload-time = "2026-02-17T16:12:40.889Z" }, + { url = "https://files.pythonhosted.org/packages/fb/c1/55bfe1ee3542eba055616f9098eaf6eddb966efb0ca0f44eaa4aba327307/librt-0.8.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:31362dbfe297b23590530007062c32c6f6176f6099646bb2c95ab1b00a57c382", size = 239615, upload-time = "2026-02-17T16:12:42.446Z" }, + { url = "https://files.pythonhosted.org/packages/2b/39/191d3d28abc26c9099b19852e6c99f7f6d400b82fa5a4e80291bd3803e19/librt-0.8.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cc3656283d11540ab0ea01978378e73e10002145117055e03722417aeab30994", size = 263001, upload-time = "2026-02-17T16:12:43.627Z" }, + { url = "https://files.pythonhosted.org/packages/b9/eb/7697f60fbe7042ab4e88f4ee6af496b7f222fffb0a4e3593ef1f29f81652/librt-0.8.1-cp314-cp314t-win32.whl", hash = "sha256:738f08021b3142c2918c03692608baed43bc51144c29e35807682f8070ee2a3a", size = 51328, upload-time = "2026-02-17T16:12:45.148Z" }, + { url = "https://files.pythonhosted.org/packages/7c/72/34bf2eb7a15414a23e5e70ecb9440c1d3179f393d9349338a91e2781c0fb/librt-0.8.1-cp314-cp314t-win_amd64.whl", hash = "sha256:89815a22daf9c51884fb5dbe4f1ef65ee6a146e0b6a8df05f753e2e4a9359bf4", size = 58722, upload-time = "2026-02-17T16:12:46.85Z" }, + { url = "https://files.pythonhosted.org/packages/b2/c8/d148e041732d631fc76036f8b30fae4e77b027a1e95b7a84bb522481a940/librt-0.8.1-cp314-cp314t-win_arm64.whl", hash = "sha256:bf512a71a23504ed08103a13c941f763db13fb11177beb3d9244c98c29fb4a61", size = 48755, upload-time = "2026-02-17T16:12:47.943Z" }, + { url = "https://files.pythonhosted.org/packages/01/1f/c7d8b66a3ca3ca3ed8ded4b32c96ee58a45920ebbbaa934355c74adcc33e/librt-0.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3dff3d3ca8db20e783b1bc7de49c0a2ab0b8387f31236d6a026597d07fcd68ac", size = 65990, upload-time = "2026-02-17T16:12:48.972Z" }, + { url = "https://files.pythonhosted.org/packages/56/be/ee9ba1730052313d08457f19beaa1b878619978863fba09b40aed5b5c123/librt-0.8.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:08eec3a1fc435f0d09c87b6bf1ec798986a3544f446b864e4099633a56fcd9ed", size = 68640, upload-time = "2026-02-17T16:12:50.24Z" }, + { url = "https://files.pythonhosted.org/packages/81/27/b7309298b96f7690cec3ceee38004c1a7f60fcd96d952d3ac344a1e3e8b3/librt-0.8.1-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e3f0a41487fd5fad7e760b9e8a90e251e27c2816fbc2cff36a22a0e6bcbbd9dd", size = 196099, upload-time = "2026-02-17T16:12:52.788Z" }, + { url = "https://files.pythonhosted.org/packages/10/48/160a5aacdcb21824b10a52378c39e88c46a29bb31efdaf3910dd1f9b670e/librt-0.8.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bacdb58d9939d95cc557b4dbaa86527c9db2ac1ed76a18bc8d26f6dc8647d851", size = 206663, upload-time = "2026-02-17T16:12:55.017Z" }, + { url = "https://files.pythonhosted.org/packages/ee/65/33dd1d8caabb7c6805d87d095b143417dc96b0277c06ffa0508361422c82/librt-0.8.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6d7ab1f01aa753188605b09a51faa44a3327400b00b8cce424c71910fc0a128", size = 219318, upload-time = "2026-02-17T16:12:56.145Z" }, + { url = "https://files.pythonhosted.org/packages/09/d4/353805aa6181c7950a2462bd6e855366eeca21a501f375228d72a51547df/librt-0.8.1-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4998009e7cb9e896569f4be7004f09d0ed70d386fa99d42b6d363f6d200501ac", size = 212191, upload-time = "2026-02-17T16:12:57.326Z" }, + { url = "https://files.pythonhosted.org/packages/06/08/725b3f304d61eba56c713c251fb833a06d84bf93381caad5152366f5d2bb/librt-0.8.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2cc68eeeef5e906839c7bb0815748b5b0a974ec27125beefc0f942715785b551", size = 220672, upload-time = "2026-02-17T16:12:58.497Z" }, + { url = "https://files.pythonhosted.org/packages/0e/55/e8cdf04145872b3b97cb9b68287b22d1c08348227063f305aec11a3e6ce7/librt-0.8.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0bf69d79a23f4f40b8673a947a234baeeb133b5078b483b7297c5916539cf5d5", size = 216172, upload-time = "2026-02-17T16:12:59.751Z" }, + { url = "https://files.pythonhosted.org/packages/8f/d8/23b1c6592d2422dd6829c672f45b1f1c257f219926b0d216fedb572d0184/librt-0.8.1-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:22b46eabd76c1986ee7d231b0765ad387d7673bbd996aa0d0d054b38ac65d8f6", size = 214116, upload-time = "2026-02-17T16:13:01.056Z" }, + { url = "https://files.pythonhosted.org/packages/c9/92/2b44fd3cc3313f44e43bdbb41343735b568fa675fa351642b408ee48d418/librt-0.8.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:237796479f4d0637d6b9cbcb926ff424a97735e68ade6facf402df4ec93375ed", size = 236664, upload-time = "2026-02-17T16:13:02.314Z" }, + { url = "https://files.pythonhosted.org/packages/00/23/92313ecdab80e142d8ea10e8dfa6297694359dbaacc9e81679bdc8cbceb6/librt-0.8.1-cp39-cp39-win32.whl", hash = "sha256:4beb04b8c66c6ae62f8c1e0b2f097c1ebad9295c929a8d5286c05eae7c2fc7dc", size = 54368, upload-time = "2026-02-17T16:13:03.549Z" }, + { url = "https://files.pythonhosted.org/packages/68/36/18f6e768afad6b55a690d38427c53251b69b7ba8795512730fd2508b31a9/librt-0.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:64548cde61b692dc0dc379f4b5f59a2f582c2ebe7890d09c1ae3b9e66fa015b7", size = 61507, upload-time = "2026-02-17T16:13:04.556Z" }, ] [[package]] @@ -2280,7 +2313,8 @@ version = "2025.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, - { name = "cattrs" }, + { name = "cattrs", version = "25.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "cattrs", version = "26.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e9/26/67b84e6ec1402f0e6764ef3d2a0aaf9a79522cc1d37738f4e5bb0b21521a/lsprotocol-2025.0.0.tar.gz", hash = "sha256:e879da2b9301e82cfc3e60d805630487ac2f7ab17492f4f5ba5aaba94fe56c29", size = 74896, upload-time = "2025-06-17T21:30:18.156Z" } wheels = [ @@ -2643,7 +2677,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, - { name = "numpy", version = "2.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0e/4a/c27b42ed9b1c7d13d9ba8b6905dece787d6259152f2309338aed29b2447b/ml_dtypes-0.5.4.tar.gz", hash = "sha256:8ab06a50fb9bf9666dd0fe5dfb4676fa2b0ac0f31ecff72a6c3af8e22c063453", size = 692314, upload-time = "2025-11-17T22:32:31.031Z" } wheels = [ @@ -2852,7 +2886,7 @@ wheels = [ [[package]] name = "numba" -version = "0.63.1" +version = "0.64.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.14' and sys_platform == 'win32'", @@ -2872,30 +2906,30 @@ resolution-markers = [ dependencies = [ { name = "llvmlite", version = "0.46.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, - { name = "numpy", version = "2.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/dc/60/0145d479b2209bd8fdae5f44201eceb8ce5a23e0ed54c71f57db24618665/numba-0.63.1.tar.gz", hash = "sha256:b320aa675d0e3b17b40364935ea52a7b1c670c9037c39cf92c49502a75902f4b", size = 2761666, upload-time = "2025-12-10T02:57:39.002Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5e/ce/5283d4ffa568f795bb0fd61ee1f0efc0c6094b94209259167fc8d4276bde/numba-0.63.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c6d6bf5bf00f7db629305caaec82a2ffb8abe2bf45eaad0d0738dc7de4113779", size = 2680810, upload-time = "2025-12-10T02:56:55.269Z" }, - { url = "https://files.pythonhosted.org/packages/0f/72/a8bda517e26d912633b32626333339b7c769ea73a5c688365ea5f88fd07e/numba-0.63.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:08653d0dfc9cc9c4c9a8fba29ceb1f2d5340c3b86c4a7e5e07e42b643bc6a2f4", size = 3739735, upload-time = "2025-12-10T02:56:57.922Z" }, - { url = "https://files.pythonhosted.org/packages/ca/17/1913b7c1173b2db30fb7a9696892a7c4c59aeee777a9af6859e9e01bac51/numba-0.63.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f09eebf5650246ce2a4e9a8d38270e2d4b0b0ae978103bafb38ed7adc5ea906e", size = 3446707, upload-time = "2025-12-10T02:56:59.837Z" }, - { url = "https://files.pythonhosted.org/packages/b4/77/703db56c3061e9fdad5e79c91452947fdeb2ec0bdfe4affe9b144e7025e0/numba-0.63.1-cp310-cp310-win_amd64.whl", hash = "sha256:f8bba17421d865d8c0f7be2142754ebce53e009daba41c44cf6909207d1a8d7d", size = 2747374, upload-time = "2025-12-10T02:57:07.908Z" }, - { url = "https://files.pythonhosted.org/packages/70/90/5f8614c165d2e256fbc6c57028519db6f32e4982475a372bbe550ea0454c/numba-0.63.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b33db00f18ccc790ee9911ce03fcdfe9d5124637d1ecc266f5ae0df06e02fec3", size = 2680501, upload-time = "2025-12-10T02:57:09.797Z" }, - { url = "https://files.pythonhosted.org/packages/dc/9d/d0afc4cf915edd8eadd9b2ab5b696242886ee4f97720d9322650d66a88c6/numba-0.63.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7d31ea186a78a7c0f6b1b2a3fe68057fdb291b045c52d86232b5383b6cf4fc25", size = 3744945, upload-time = "2025-12-10T02:57:11.697Z" }, - { url = "https://files.pythonhosted.org/packages/05/a9/d82f38f2ab73f3be6f838a826b545b80339762ee8969c16a8bf1d39395a8/numba-0.63.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ed3bb2fbdb651d6aac394388130a7001aab6f4541837123a4b4ab8b02716530c", size = 3450827, upload-time = "2025-12-10T02:57:13.709Z" }, - { url = "https://files.pythonhosted.org/packages/18/3f/a9b106e93c5bd7434e65f044bae0d204e20aa7f7f85d72ceb872c7c04216/numba-0.63.1-cp311-cp311-win_amd64.whl", hash = "sha256:1ecbff7688f044b1601be70113e2fb1835367ee0b28ffa8f3adf3a05418c5c87", size = 2747262, upload-time = "2025-12-10T02:57:15.664Z" }, - { url = "https://files.pythonhosted.org/packages/14/9c/c0974cd3d00ff70d30e8ff90522ba5fbb2bcee168a867d2321d8d0457676/numba-0.63.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2819cd52afa5d8d04e057bdfd54367575105f8829350d8fb5e4066fb7591cc71", size = 2680981, upload-time = "2025-12-10T02:57:17.579Z" }, - { url = "https://files.pythonhosted.org/packages/cb/70/ea2bc45205f206b7a24ee68a159f5097c9ca7e6466806e7c213587e0c2b1/numba-0.63.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5cfd45dbd3d409e713b1ccfdc2ee72ca82006860254429f4ef01867fdba5845f", size = 3801656, upload-time = "2025-12-10T02:57:19.106Z" }, - { url = "https://files.pythonhosted.org/packages/0d/82/4f4ba4fd0f99825cbf3cdefd682ca3678be1702b63362011de6e5f71f831/numba-0.63.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:69a599df6976c03b7ecf15d05302696f79f7e6d10d620367407517943355bcb0", size = 3501857, upload-time = "2025-12-10T02:57:20.721Z" }, - { url = "https://files.pythonhosted.org/packages/af/fd/6540456efa90b5f6604a86ff50dabefb187e43557e9081adcad3be44f048/numba-0.63.1-cp312-cp312-win_amd64.whl", hash = "sha256:bbad8c63e4fc7eb3cdb2c2da52178e180419f7969f9a685f283b313a70b92af3", size = 2750282, upload-time = "2025-12-10T02:57:22.474Z" }, - { url = "https://files.pythonhosted.org/packages/57/f7/e19e6eff445bec52dde5bed1ebb162925a8e6f988164f1ae4b3475a73680/numba-0.63.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:0bd4fd820ef7442dcc07da184c3f54bb41d2bdb7b35bacf3448e73d081f730dc", size = 2680954, upload-time = "2025-12-10T02:57:24.145Z" }, - { url = "https://files.pythonhosted.org/packages/e9/6c/1e222edba1e20e6b113912caa9b1665b5809433cbcb042dfd133c6f1fd38/numba-0.63.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:53de693abe4be3bd4dee38e1c55f01c55ff644a6a3696a3670589e6e4c39cde2", size = 3809736, upload-time = "2025-12-10T02:57:25.836Z" }, - { url = "https://files.pythonhosted.org/packages/76/0a/590bad11a8b3feeac30a24d01198d46bdb76ad15c70d3a530691ce3cae58/numba-0.63.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:81227821a72a763c3d4ac290abbb4371d855b59fdf85d5af22a47c0e86bf8c7e", size = 3508854, upload-time = "2025-12-10T02:57:27.438Z" }, - { url = "https://files.pythonhosted.org/packages/4e/f5/3800384a24eed1e4d524669cdbc0b9b8a628800bb1e90d7bd676e5f22581/numba-0.63.1-cp313-cp313-win_amd64.whl", hash = "sha256:eb227b07c2ac37b09432a9bda5142047a2d1055646e089d4a240a2643e508102", size = 2750228, upload-time = "2025-12-10T02:57:30.36Z" }, - { url = "https://files.pythonhosted.org/packages/36/2f/53be2aa8a55ee2608ebe1231789cbb217f6ece7f5e1c685d2f0752e95a5b/numba-0.63.1-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:f180883e5508940cc83de8a8bea37fc6dd20fbe4e5558d4659b8b9bef5ff4731", size = 2681153, upload-time = "2025-12-10T02:57:32.016Z" }, - { url = "https://files.pythonhosted.org/packages/13/91/53e59c86759a0648282368d42ba732c29524a745fd555ed1fb1df83febbe/numba-0.63.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0938764afa82a47c0e895637a6c55547a42c9e1d35cac42285b1fa60a8b02bb", size = 3778718, upload-time = "2025-12-10T02:57:33.764Z" }, - { url = "https://files.pythonhosted.org/packages/6c/0c/2be19eba50b0b7636f6d1f69dfb2825530537708a234ba1ff34afc640138/numba-0.63.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f90a929fa5094e062d4e0368ede1f4497d5e40f800e80aa5222c4734236a2894", size = 3478712, upload-time = "2025-12-10T02:57:35.518Z" }, - { url = "https://files.pythonhosted.org/packages/0d/5f/4d0c9e756732577a52211f31da13a3d943d185f7fb90723f56d79c696caa/numba-0.63.1-cp314-cp314-win_amd64.whl", hash = "sha256:8d6d5ce85f572ed4e1a135dbb8c0114538f9dd0e3657eeb0bb64ab204cbe2a8f", size = 2752161, upload-time = "2025-12-10T02:57:37.12Z" }, + { name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/23/c9/a0fb41787d01d621046138da30f6c2100d80857bf34b3390dd68040f27a3/numba-0.64.0.tar.gz", hash = "sha256:95e7300af648baa3308127b1955b52ce6d11889d16e8cfe637b4f85d2fca52b1", size = 2765679, upload-time = "2026-02-18T18:41:20.974Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/5e/604fed821cd7e3426bb3bc99a7ed6ac0bcb489f4cd93052256437d082f95/numba-0.64.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cc09b79440952e3098eeebea4bf6e8d2355fb7f12734fcd9fc5039f0dca90727", size = 2683250, upload-time = "2026-02-18T18:40:45.829Z" }, + { url = "https://files.pythonhosted.org/packages/4f/9f/9275a723d050b5f1a9b1c7fb7dbfce324fef301a8e50c5f88338569db06c/numba-0.64.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1afe3a80b8c2f376b211fb7a49e536ef9eafc92436afc95a2f41ea5392f8cc65", size = 3742168, upload-time = "2026-02-18T18:40:48.066Z" }, + { url = "https://files.pythonhosted.org/packages/e2/d1/97ca7dddaa36b16f4c46319bdb6b4913ba15d0245317d0d8ccde7b2d7d92/numba-0.64.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23804194b93b8cd416c6444b5fbc4956082a45fed2d25436ef49c594666e7f7e", size = 3449103, upload-time = "2026-02-18T18:40:49.905Z" }, + { url = "https://files.pythonhosted.org/packages/52/0a/b9e137ad78415373e3353564500e8bf29dbce3c0d73633bb384d4e5d7537/numba-0.64.0-cp310-cp310-win_amd64.whl", hash = "sha256:e2a9fe998bb2cf848960b34db02c2c3b5e02cf82c07a26d9eef3494069740278", size = 2749950, upload-time = "2026-02-18T18:40:51.536Z" }, + { url = "https://files.pythonhosted.org/packages/89/a3/1a4286a1c16136c8896d8e2090d950e79b3ec626d3a8dc9620f6234d5a38/numba-0.64.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:766156ee4b8afeeb2b2e23c81307c5d19031f18d5ce76ae2c5fb1429e72fa92b", size = 2682938, upload-time = "2026-02-18T18:40:52.897Z" }, + { url = "https://files.pythonhosted.org/packages/19/16/aa6e3ba3cd45435c117d1101b278b646444ed05b7c712af631b91353f573/numba-0.64.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d17071b4ffc9d39b75d8e6c101a36f0c81b646123859898c9799cb31807c8f78", size = 3747376, upload-time = "2026-02-18T18:40:54.925Z" }, + { url = "https://files.pythonhosted.org/packages/c0/f1/dd2f25e18d75fdf897f730b78c5a7b00cc4450f2405564dbebfaf359f21f/numba-0.64.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4ead5630434133bac87fa67526eacb264535e4e9a2d5ec780e0b4fc381a7d275", size = 3453292, upload-time = "2026-02-18T18:40:56.818Z" }, + { url = "https://files.pythonhosted.org/packages/31/29/e09d5630578a50a2b3fa154990b6b839cf95327aa0709e2d50d0b6816cd1/numba-0.64.0-cp311-cp311-win_amd64.whl", hash = "sha256:f2b1fd93e7aaac07d6fbaed059c00679f591f2423885c206d8c1b55d65ca3f2d", size = 2749824, upload-time = "2026-02-18T18:40:58.392Z" }, + { url = "https://files.pythonhosted.org/packages/70/a6/9fc52cb4f0d5e6d8b5f4d81615bc01012e3cf24e1052a60f17a68deb8092/numba-0.64.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:69440a8e8bc1a81028446f06b363e28635aa67bd51b1e498023f03b812e0ce68", size = 2683418, upload-time = "2026-02-18T18:40:59.886Z" }, + { url = "https://files.pythonhosted.org/packages/9b/89/1a74ea99b180b7a5587b0301ed1b183a2937c4b4b67f7994689b5d36fc34/numba-0.64.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f13721011f693ba558b8dd4e4db7f2640462bba1b855bdc804be45bbeb55031a", size = 3804087, upload-time = "2026-02-18T18:41:01.699Z" }, + { url = "https://files.pythonhosted.org/packages/91/e1/583c647404b15f807410510fec1eb9b80cb8474165940b7749f026f21cbc/numba-0.64.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e0b180b1133f2b5d8b3f09d96b6d7a9e51a7da5dda3c09e998b5bcfac85d222c", size = 3504309, upload-time = "2026-02-18T18:41:03.252Z" }, + { url = "https://files.pythonhosted.org/packages/85/23/0fce5789b8a5035e7ace21216a468143f3144e02013252116616c58339aa/numba-0.64.0-cp312-cp312-win_amd64.whl", hash = "sha256:e63dc94023b47894849b8b106db28ccb98b49d5498b98878fac1a38f83ac007a", size = 2752740, upload-time = "2026-02-18T18:41:05.097Z" }, + { url = "https://files.pythonhosted.org/packages/52/80/2734de90f9300a6e2503b35ee50d9599926b90cbb7ac54f9e40074cd07f1/numba-0.64.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:3bab2c872194dcd985f1153b70782ec0fbbe348fffef340264eacd3a76d59fd6", size = 2683392, upload-time = "2026-02-18T18:41:06.563Z" }, + { url = "https://files.pythonhosted.org/packages/42/e8/14b5853ebefd5b37723ef365c5318a30ce0702d39057eaa8d7d76392859d/numba-0.64.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:703a246c60832cad231d2e73c1182f25bf3cc8b699759ec8fe58a2dbc689a70c", size = 3812245, upload-time = "2026-02-18T18:41:07.963Z" }, + { url = "https://files.pythonhosted.org/packages/8a/a2/f60dc6c96d19b7185144265a5fbf01c14993d37ff4cd324b09d0212aa7ce/numba-0.64.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7e2e49a7900ee971d32af7609adc0cfe6aa7477c6f6cccdf6d8138538cf7756f", size = 3511328, upload-time = "2026-02-18T18:41:09.504Z" }, + { url = "https://files.pythonhosted.org/packages/9c/2a/fe7003ea7e7237ee7014f8eaeeb7b0d228a2db22572ca85bab2648cf52cb/numba-0.64.0-cp313-cp313-win_amd64.whl", hash = "sha256:396f43c3f77e78d7ec84cdfc6b04969c78f8f169351b3c4db814b97e7acf4245", size = 2752668, upload-time = "2026-02-18T18:41:11.455Z" }, + { url = "https://files.pythonhosted.org/packages/3d/8a/77d26afe0988c592dd97cb8d4e80bfb3dfc7dbdacfca7d74a7c5c81dd8c2/numba-0.64.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:f565d55eaeff382cbc86c63c8c610347453af3d1e7afb2b6569aac1c9b5c93ce", size = 2683590, upload-time = "2026-02-18T18:41:12.897Z" }, + { url = "https://files.pythonhosted.org/packages/8e/4b/600b8b7cdbc7f9cebee9ea3d13bb70052a79baf28944024ffcb59f0712e3/numba-0.64.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9b55169b18892c783f85e9ad9e6f5297a6d12967e4414e6b71361086025ff0bb", size = 3781163, upload-time = "2026-02-18T18:41:15.377Z" }, + { url = "https://files.pythonhosted.org/packages/ff/73/53f2d32bfa45b7175e9944f6b816d8c32840178c3eee9325033db5bf838e/numba-0.64.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:196bcafa02c9dd1707e068434f6d5cedde0feb787e3432f7f1f0e993cc336c4c", size = 3481172, upload-time = "2026-02-18T18:41:17.281Z" }, + { url = "https://files.pythonhosted.org/packages/b5/00/aebd2f7f1e11e38814bb96e95a27580817a7b340608d3ac085fdbab83174/numba-0.64.0-cp314-cp314-win_amd64.whl", hash = "sha256:213e9acbe7f1c05090592e79020315c1749dd52517b90e94c517dca3f014d4a1", size = 2754700, upload-time = "2026-02-18T18:41:19.277Z" }, ] [[package]] @@ -3021,7 +3055,7 @@ wheels = [ [[package]] name = "numpy" -version = "2.3.5" +version = "2.4.2" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.14' and sys_platform == 'win32'", @@ -3037,81 +3071,79 @@ resolution-markers = [ "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] -sdist = { url = "https://files.pythonhosted.org/packages/76/65/21b3bc86aac7b8f2862db1e808f1ea22b028e30a225a34a5ede9bf8678f2/numpy-2.3.5.tar.gz", hash = "sha256:784db1dcdab56bf0517743e746dfb0f885fc68d948aba86eeec2cba234bdf1c0", size = 20584950, upload-time = "2025-11-16T22:52:42.067Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/43/77/84dd1d2e34d7e2792a236ba180b5e8fcc1e3e414e761ce0253f63d7f572e/numpy-2.3.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:de5672f4a7b200c15a4127042170a694d4df43c992948f5e1af57f0174beed10", size = 17034641, upload-time = "2025-11-16T22:49:19.336Z" }, - { url = "https://files.pythonhosted.org/packages/2a/ea/25e26fa5837106cde46ae7d0b667e20f69cbbc0efd64cba8221411ab26ae/numpy-2.3.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:acfd89508504a19ed06ef963ad544ec6664518c863436306153e13e94605c218", size = 12528324, upload-time = "2025-11-16T22:49:22.582Z" }, - { url = "https://files.pythonhosted.org/packages/4d/1a/e85f0eea4cf03d6a0228f5c0256b53f2df4bc794706e7df019fc622e47f1/numpy-2.3.5-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:ffe22d2b05504f786c867c8395de703937f934272eb67586817b46188b4ded6d", size = 5356872, upload-time = "2025-11-16T22:49:25.408Z" }, - { url = "https://files.pythonhosted.org/packages/5c/bb/35ef04afd567f4c989c2060cde39211e4ac5357155c1833bcd1166055c61/numpy-2.3.5-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:872a5cf366aec6bb1147336480fef14c9164b154aeb6542327de4970282cd2f5", size = 6893148, upload-time = "2025-11-16T22:49:27.549Z" }, - { url = "https://files.pythonhosted.org/packages/f2/2b/05bbeb06e2dff5eab512dfc678b1cc5ee94d8ac5956a0885c64b6b26252b/numpy-2.3.5-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3095bdb8dd297e5920b010e96134ed91d852d81d490e787beca7e35ae1d89cf7", size = 14557282, upload-time = "2025-11-16T22:49:30.964Z" }, - { url = "https://files.pythonhosted.org/packages/65/fb/2b23769462b34398d9326081fad5655198fcf18966fcb1f1e49db44fbf31/numpy-2.3.5-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8cba086a43d54ca804ce711b2a940b16e452807acebe7852ff327f1ecd49b0d4", size = 16897903, upload-time = "2025-11-16T22:49:34.191Z" }, - { url = "https://files.pythonhosted.org/packages/ac/14/085f4cf05fc3f1e8aa95e85404e984ffca9b2275a5dc2b1aae18a67538b8/numpy-2.3.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6cf9b429b21df6b99f4dee7a1218b8b7ffbbe7df8764dc0bd60ce8a0708fed1e", size = 16341672, upload-time = "2025-11-16T22:49:37.2Z" }, - { url = "https://files.pythonhosted.org/packages/6f/3b/1f73994904142b2aa290449b3bb99772477b5fd94d787093e4f24f5af763/numpy-2.3.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:396084a36abdb603546b119d96528c2f6263921c50df3c8fd7cb28873a237748", size = 18838896, upload-time = "2025-11-16T22:49:39.727Z" }, - { url = "https://files.pythonhosted.org/packages/cd/b9/cf6649b2124f288309ffc353070792caf42ad69047dcc60da85ee85fea58/numpy-2.3.5-cp311-cp311-win32.whl", hash = "sha256:b0c7088a73aef3d687c4deef8452a3ac7c1be4e29ed8bf3b366c8111128ac60c", size = 6563608, upload-time = "2025-11-16T22:49:42.079Z" }, - { url = "https://files.pythonhosted.org/packages/aa/44/9fe81ae1dcc29c531843852e2874080dc441338574ccc4306b39e2ff6e59/numpy-2.3.5-cp311-cp311-win_amd64.whl", hash = "sha256:a414504bef8945eae5f2d7cb7be2d4af77c5d1cb5e20b296c2c25b61dff2900c", size = 13078442, upload-time = "2025-11-16T22:49:43.99Z" }, - { url = "https://files.pythonhosted.org/packages/6d/a7/f99a41553d2da82a20a2f22e93c94f928e4490bb447c9ff3c4ff230581d3/numpy-2.3.5-cp311-cp311-win_arm64.whl", hash = "sha256:0cd00b7b36e35398fa2d16af7b907b65304ef8bb4817a550e06e5012929830fa", size = 10458555, upload-time = "2025-11-16T22:49:47.092Z" }, - { url = "https://files.pythonhosted.org/packages/44/37/e669fe6cbb2b96c62f6bbedc6a81c0f3b7362f6a59230b23caa673a85721/numpy-2.3.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:74ae7b798248fe62021dbf3c914245ad45d1a6b0cb4a29ecb4b31d0bfbc4cc3e", size = 16733873, upload-time = "2025-11-16T22:49:49.84Z" }, - { url = "https://files.pythonhosted.org/packages/c5/65/df0db6c097892c9380851ab9e44b52d4f7ba576b833996e0080181c0c439/numpy-2.3.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee3888d9ff7c14604052b2ca5535a30216aa0a58e948cdd3eeb8d3415f638769", size = 12259838, upload-time = "2025-11-16T22:49:52.863Z" }, - { url = "https://files.pythonhosted.org/packages/5b/e1/1ee06e70eb2136797abe847d386e7c0e830b67ad1d43f364dd04fa50d338/numpy-2.3.5-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:612a95a17655e213502f60cfb9bf9408efdc9eb1d5f50535cc6eb365d11b42b5", size = 5088378, upload-time = "2025-11-16T22:49:55.055Z" }, - { url = "https://files.pythonhosted.org/packages/6d/9c/1ca85fb86708724275103b81ec4cf1ac1d08f465368acfc8da7ab545bdae/numpy-2.3.5-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3101e5177d114a593d79dd79658650fe28b5a0d8abeb8ce6f437c0e6df5be1a4", size = 6628559, upload-time = "2025-11-16T22:49:57.371Z" }, - { url = "https://files.pythonhosted.org/packages/74/78/fcd41e5a0ce4f3f7b003da85825acddae6d7ecb60cf25194741b036ca7d6/numpy-2.3.5-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b973c57ff8e184109db042c842423ff4f60446239bd585a5131cc47f06f789d", size = 14250702, upload-time = "2025-11-16T22:49:59.632Z" }, - { url = "https://files.pythonhosted.org/packages/b6/23/2a1b231b8ff672b4c450dac27164a8b2ca7d9b7144f9c02d2396518352eb/numpy-2.3.5-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0d8163f43acde9a73c2a33605353a4f1bc4798745a8b1d73183b28e5b435ae28", size = 16606086, upload-time = "2025-11-16T22:50:02.127Z" }, - { url = "https://files.pythonhosted.org/packages/a0/c5/5ad26fbfbe2012e190cc7d5003e4d874b88bb18861d0829edc140a713021/numpy-2.3.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:51c1e14eb1e154ebd80e860722f9e6ed6ec89714ad2db2d3aa33c31d7c12179b", size = 16025985, upload-time = "2025-11-16T22:50:04.536Z" }, - { url = "https://files.pythonhosted.org/packages/d2/fa/dd48e225c46c819288148d9d060b047fd2a6fb1eb37eae25112ee4cb4453/numpy-2.3.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b46b4ec24f7293f23adcd2d146960559aaf8020213de8ad1909dba6c013bf89c", size = 18542976, upload-time = "2025-11-16T22:50:07.557Z" }, - { url = "https://files.pythonhosted.org/packages/05/79/ccbd23a75862d95af03d28b5c6901a1b7da4803181513d52f3b86ed9446e/numpy-2.3.5-cp312-cp312-win32.whl", hash = "sha256:3997b5b3c9a771e157f9aae01dd579ee35ad7109be18db0e85dbdbe1de06e952", size = 6285274, upload-time = "2025-11-16T22:50:10.746Z" }, - { url = "https://files.pythonhosted.org/packages/2d/57/8aeaf160312f7f489dea47ab61e430b5cb051f59a98ae68b7133ce8fa06a/numpy-2.3.5-cp312-cp312-win_amd64.whl", hash = "sha256:86945f2ee6d10cdfd67bcb4069c1662dd711f7e2a4343db5cecec06b87cf31aa", size = 12782922, upload-time = "2025-11-16T22:50:12.811Z" }, - { url = "https://files.pythonhosted.org/packages/78/a6/aae5cc2ca78c45e64b9ef22f089141d661516856cf7c8a54ba434576900d/numpy-2.3.5-cp312-cp312-win_arm64.whl", hash = "sha256:f28620fe26bee16243be2b7b874da327312240a7cdc38b769a697578d2100013", size = 10194667, upload-time = "2025-11-16T22:50:16.16Z" }, - { url = "https://files.pythonhosted.org/packages/db/69/9cde09f36da4b5a505341180a3f2e6fadc352fd4d2b7096ce9778db83f1a/numpy-2.3.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d0f23b44f57077c1ede8c5f26b30f706498b4862d3ff0a7298b8411dd2f043ff", size = 16728251, upload-time = "2025-11-16T22:50:19.013Z" }, - { url = "https://files.pythonhosted.org/packages/79/fb/f505c95ceddd7027347b067689db71ca80bd5ecc926f913f1a23e65cf09b/numpy-2.3.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:aa5bc7c5d59d831d9773d1170acac7893ce3a5e130540605770ade83280e7188", size = 12254652, upload-time = "2025-11-16T22:50:21.487Z" }, - { url = "https://files.pythonhosted.org/packages/78/da/8c7738060ca9c31b30e9301ee0cf6c5ffdbf889d9593285a1cead337f9a5/numpy-2.3.5-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:ccc933afd4d20aad3c00bcef049cb40049f7f196e0397f1109dba6fed63267b0", size = 5083172, upload-time = "2025-11-16T22:50:24.562Z" }, - { url = "https://files.pythonhosted.org/packages/a4/b4/ee5bb2537fb9430fd2ef30a616c3672b991a4129bb1c7dcc42aa0abbe5d7/numpy-2.3.5-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:afaffc4393205524af9dfa400fa250143a6c3bc646c08c9f5e25a9f4b4d6a903", size = 6622990, upload-time = "2025-11-16T22:50:26.47Z" }, - { url = "https://files.pythonhosted.org/packages/95/03/dc0723a013c7d7c19de5ef29e932c3081df1c14ba582b8b86b5de9db7f0f/numpy-2.3.5-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c75442b2209b8470d6d5d8b1c25714270686f14c749028d2199c54e29f20b4d", size = 14248902, upload-time = "2025-11-16T22:50:28.861Z" }, - { url = "https://files.pythonhosted.org/packages/f5/10/ca162f45a102738958dcec8023062dad0cbc17d1ab99d68c4e4a6c45fb2b/numpy-2.3.5-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11e06aa0af8c0f05104d56450d6093ee639e15f24ecf62d417329d06e522e017", size = 16597430, upload-time = "2025-11-16T22:50:31.56Z" }, - { url = "https://files.pythonhosted.org/packages/2a/51/c1e29be863588db58175175f057286900b4b3327a1351e706d5e0f8dd679/numpy-2.3.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ed89927b86296067b4f81f108a2271d8926467a8868e554eaf370fc27fa3ccaf", size = 16024551, upload-time = "2025-11-16T22:50:34.242Z" }, - { url = "https://files.pythonhosted.org/packages/83/68/8236589d4dbb87253d28259d04d9b814ec0ecce7cb1c7fed29729f4c3a78/numpy-2.3.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51c55fe3451421f3a6ef9a9c1439e82101c57a2c9eab9feb196a62b1a10b58ce", size = 18533275, upload-time = "2025-11-16T22:50:37.651Z" }, - { url = "https://files.pythonhosted.org/packages/40/56/2932d75b6f13465239e3b7b7e511be27f1b8161ca2510854f0b6e521c395/numpy-2.3.5-cp313-cp313-win32.whl", hash = "sha256:1978155dd49972084bd6ef388d66ab70f0c323ddee6f693d539376498720fb7e", size = 6277637, upload-time = "2025-11-16T22:50:40.11Z" }, - { url = "https://files.pythonhosted.org/packages/0c/88/e2eaa6cffb115b85ed7c7c87775cb8bcf0816816bc98ca8dbfa2ee33fe6e/numpy-2.3.5-cp313-cp313-win_amd64.whl", hash = "sha256:00dc4e846108a382c5869e77c6ed514394bdeb3403461d25a829711041217d5b", size = 12779090, upload-time = "2025-11-16T22:50:42.503Z" }, - { url = "https://files.pythonhosted.org/packages/8f/88/3f41e13a44ebd4034ee17baa384acac29ba6a4fcc2aca95f6f08ca0447d1/numpy-2.3.5-cp313-cp313-win_arm64.whl", hash = "sha256:0472f11f6ec23a74a906a00b48a4dcf3849209696dff7c189714511268d103ae", size = 10194710, upload-time = "2025-11-16T22:50:44.971Z" }, - { url = "https://files.pythonhosted.org/packages/13/cb/71744144e13389d577f867f745b7df2d8489463654a918eea2eeb166dfc9/numpy-2.3.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:414802f3b97f3c1eef41e530aaba3b3c1620649871d8cb38c6eaff034c2e16bd", size = 16827292, upload-time = "2025-11-16T22:50:47.715Z" }, - { url = "https://files.pythonhosted.org/packages/71/80/ba9dc6f2a4398e7f42b708a7fdc841bb638d353be255655498edbf9a15a8/numpy-2.3.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5ee6609ac3604fa7780e30a03e5e241a7956f8e2fcfe547d51e3afa5247ac47f", size = 12378897, upload-time = "2025-11-16T22:50:51.327Z" }, - { url = "https://files.pythonhosted.org/packages/2e/6d/db2151b9f64264bcceccd51741aa39b50150de9b602d98ecfe7e0c4bff39/numpy-2.3.5-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:86d835afea1eaa143012a2d7a3f45a3adce2d7adc8b4961f0b362214d800846a", size = 5207391, upload-time = "2025-11-16T22:50:54.542Z" }, - { url = "https://files.pythonhosted.org/packages/80/ae/429bacace5ccad48a14c4ae5332f6aa8ab9f69524193511d60ccdfdc65fa/numpy-2.3.5-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:30bc11310e8153ca664b14c5f1b73e94bd0503681fcf136a163de856f3a50139", size = 6721275, upload-time = "2025-11-16T22:50:56.794Z" }, - { url = "https://files.pythonhosted.org/packages/74/5b/1919abf32d8722646a38cd527bc3771eb229a32724ee6ba340ead9b92249/numpy-2.3.5-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1062fde1dcf469571705945b0f221b73928f34a20c904ffb45db101907c3454e", size = 14306855, upload-time = "2025-11-16T22:50:59.208Z" }, - { url = "https://files.pythonhosted.org/packages/a5/87/6831980559434973bebc30cd9c1f21e541a0f2b0c280d43d3afd909b66d0/numpy-2.3.5-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce581db493ea1a96c0556360ede6607496e8bf9b3a8efa66e06477267bc831e9", size = 16657359, upload-time = "2025-11-16T22:51:01.991Z" }, - { url = "https://files.pythonhosted.org/packages/dd/91/c797f544491ee99fd00495f12ebb7802c440c1915811d72ac5b4479a3356/numpy-2.3.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:cc8920d2ec5fa99875b670bb86ddeb21e295cb07aa331810d9e486e0b969d946", size = 16093374, upload-time = "2025-11-16T22:51:05.291Z" }, - { url = "https://files.pythonhosted.org/packages/74/a6/54da03253afcbe7a72785ec4da9c69fb7a17710141ff9ac5fcb2e32dbe64/numpy-2.3.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:9ee2197ef8c4f0dfe405d835f3b6a14f5fee7782b5de51ba06fb65fc9b36e9f1", size = 18594587, upload-time = "2025-11-16T22:51:08.585Z" }, - { url = "https://files.pythonhosted.org/packages/80/e9/aff53abbdd41b0ecca94285f325aff42357c6b5abc482a3fcb4994290b18/numpy-2.3.5-cp313-cp313t-win32.whl", hash = "sha256:70b37199913c1bd300ff6e2693316c6f869c7ee16378faf10e4f5e3275b299c3", size = 6405940, upload-time = "2025-11-16T22:51:11.541Z" }, - { url = "https://files.pythonhosted.org/packages/d5/81/50613fec9d4de5480de18d4f8ef59ad7e344d497edbef3cfd80f24f98461/numpy-2.3.5-cp313-cp313t-win_amd64.whl", hash = "sha256:b501b5fa195cc9e24fe102f21ec0a44dffc231d2af79950b451e0d99cea02234", size = 12920341, upload-time = "2025-11-16T22:51:14.312Z" }, - { url = "https://files.pythonhosted.org/packages/bb/ab/08fd63b9a74303947f34f0bd7c5903b9c5532c2d287bead5bdf4c556c486/numpy-2.3.5-cp313-cp313t-win_arm64.whl", hash = "sha256:a80afd79f45f3c4a7d341f13acbe058d1ca8ac017c165d3fa0d3de6bc1a079d7", size = 10262507, upload-time = "2025-11-16T22:51:16.846Z" }, - { url = "https://files.pythonhosted.org/packages/ba/97/1a914559c19e32d6b2e233cf9a6a114e67c856d35b1d6babca571a3e880f/numpy-2.3.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:bf06bc2af43fa8d32d30fae16ad965663e966b1a3202ed407b84c989c3221e82", size = 16735706, upload-time = "2025-11-16T22:51:19.558Z" }, - { url = "https://files.pythonhosted.org/packages/57/d4/51233b1c1b13ecd796311216ae417796b88b0616cfd8a33ae4536330748a/numpy-2.3.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:052e8c42e0c49d2575621c158934920524f6c5da05a1d3b9bab5d8e259e045f0", size = 12264507, upload-time = "2025-11-16T22:51:22.492Z" }, - { url = "https://files.pythonhosted.org/packages/45/98/2fe46c5c2675b8306d0b4a3ec3494273e93e1226a490f766e84298576956/numpy-2.3.5-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:1ed1ec893cff7040a02c8aa1c8611b94d395590d553f6b53629a4461dc7f7b63", size = 5093049, upload-time = "2025-11-16T22:51:25.171Z" }, - { url = "https://files.pythonhosted.org/packages/ce/0e/0698378989bb0ac5f1660c81c78ab1fe5476c1a521ca9ee9d0710ce54099/numpy-2.3.5-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:2dcd0808a421a482a080f89859a18beb0b3d1e905b81e617a188bd80422d62e9", size = 6626603, upload-time = "2025-11-16T22:51:27Z" }, - { url = "https://files.pythonhosted.org/packages/5e/a6/9ca0eecc489640615642a6cbc0ca9e10df70df38c4d43f5a928ff18d8827/numpy-2.3.5-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:727fd05b57df37dc0bcf1a27767a3d9a78cbbc92822445f32cc3436ba797337b", size = 14262696, upload-time = "2025-11-16T22:51:29.402Z" }, - { url = "https://files.pythonhosted.org/packages/c8/f6/07ec185b90ec9d7217a00eeeed7383b73d7e709dae2a9a021b051542a708/numpy-2.3.5-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fffe29a1ef00883599d1dc2c51aa2e5d80afe49523c261a74933df395c15c520", size = 16597350, upload-time = "2025-11-16T22:51:32.167Z" }, - { url = "https://files.pythonhosted.org/packages/75/37/164071d1dde6a1a84c9b8e5b414fa127981bad47adf3a6b7e23917e52190/numpy-2.3.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8f7f0e05112916223d3f438f293abf0727e1181b5983f413dfa2fefc4098245c", size = 16040190, upload-time = "2025-11-16T22:51:35.403Z" }, - { url = "https://files.pythonhosted.org/packages/08/3c/f18b82a406b04859eb026d204e4e1773eb41c5be58410f41ffa511d114ae/numpy-2.3.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2e2eb32ddb9ccb817d620ac1d8dae7c3f641c1e5f55f531a33e8ab97960a75b8", size = 18536749, upload-time = "2025-11-16T22:51:39.698Z" }, - { url = "https://files.pythonhosted.org/packages/40/79/f82f572bf44cf0023a2fe8588768e23e1592585020d638999f15158609e1/numpy-2.3.5-cp314-cp314-win32.whl", hash = "sha256:66f85ce62c70b843bab1fb14a05d5737741e74e28c7b8b5a064de10142fad248", size = 6335432, upload-time = "2025-11-16T22:51:42.476Z" }, - { url = "https://files.pythonhosted.org/packages/a3/2e/235b4d96619931192c91660805e5e49242389742a7a82c27665021db690c/numpy-2.3.5-cp314-cp314-win_amd64.whl", hash = "sha256:e6a0bc88393d65807d751a614207b7129a310ca4fe76a74e5c7da5fa5671417e", size = 12919388, upload-time = "2025-11-16T22:51:45.275Z" }, - { url = "https://files.pythonhosted.org/packages/07/2b/29fd75ce45d22a39c61aad74f3d718e7ab67ccf839ca8b60866054eb15f8/numpy-2.3.5-cp314-cp314-win_arm64.whl", hash = "sha256:aeffcab3d4b43712bb7a60b65f6044d444e75e563ff6180af8f98dd4b905dfd2", size = 10476651, upload-time = "2025-11-16T22:51:47.749Z" }, - { url = "https://files.pythonhosted.org/packages/17/e1/f6a721234ebd4d87084cfa68d081bcba2f5cfe1974f7de4e0e8b9b2a2ba1/numpy-2.3.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:17531366a2e3a9e30762c000f2c43a9aaa05728712e25c11ce1dbe700c53ad41", size = 16834503, upload-time = "2025-11-16T22:51:50.443Z" }, - { url = "https://files.pythonhosted.org/packages/5c/1c/baf7ffdc3af9c356e1c135e57ab7cf8d247931b9554f55c467efe2c69eff/numpy-2.3.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d21644de1b609825ede2f48be98dfde4656aefc713654eeee280e37cadc4e0ad", size = 12381612, upload-time = "2025-11-16T22:51:53.609Z" }, - { url = "https://files.pythonhosted.org/packages/74/91/f7f0295151407ddc9ba34e699013c32c3c91944f9b35fcf9281163dc1468/numpy-2.3.5-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:c804e3a5aba5460c73955c955bdbd5c08c354954e9270a2c1565f62e866bdc39", size = 5210042, upload-time = "2025-11-16T22:51:56.213Z" }, - { url = "https://files.pythonhosted.org/packages/2e/3b/78aebf345104ec50dd50a4d06ddeb46a9ff5261c33bcc58b1c4f12f85ec2/numpy-2.3.5-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:cc0a57f895b96ec78969c34f682c602bf8da1a0270b09bc65673df2e7638ec20", size = 6724502, upload-time = "2025-11-16T22:51:58.584Z" }, - { url = "https://files.pythonhosted.org/packages/02/c6/7c34b528740512e57ef1b7c8337ab0b4f0bddf34c723b8996c675bc2bc91/numpy-2.3.5-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:900218e456384ea676e24ea6a0417f030a3b07306d29d7ad843957b40a9d8d52", size = 14308962, upload-time = "2025-11-16T22:52:01.698Z" }, - { url = "https://files.pythonhosted.org/packages/80/35/09d433c5262bc32d725bafc619e095b6a6651caf94027a03da624146f655/numpy-2.3.5-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:09a1bea522b25109bf8e6f3027bd810f7c1085c64a0c7ce050c1676ad0ba010b", size = 16655054, upload-time = "2025-11-16T22:52:04.267Z" }, - { url = "https://files.pythonhosted.org/packages/7a/ab/6a7b259703c09a88804fa2430b43d6457b692378f6b74b356155283566ac/numpy-2.3.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:04822c00b5fd0323c8166d66c701dc31b7fbd252c100acd708c48f763968d6a3", size = 16091613, upload-time = "2025-11-16T22:52:08.651Z" }, - { url = "https://files.pythonhosted.org/packages/c2/88/330da2071e8771e60d1038166ff9d73f29da37b01ec3eb43cb1427464e10/numpy-2.3.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d6889ec4ec662a1a37eb4b4fb26b6100841804dac55bd9df579e326cdc146227", size = 18591147, upload-time = "2025-11-16T22:52:11.453Z" }, - { url = "https://files.pythonhosted.org/packages/51/41/851c4b4082402d9ea860c3626db5d5df47164a712cb23b54be028b184c1c/numpy-2.3.5-cp314-cp314t-win32.whl", hash = "sha256:93eebbcf1aafdf7e2ddd44c2923e2672e1010bddc014138b229e49725b4d6be5", size = 6479806, upload-time = "2025-11-16T22:52:14.641Z" }, - { url = "https://files.pythonhosted.org/packages/90/30/d48bde1dfd93332fa557cff1972fbc039e055a52021fbef4c2c4b1eefd17/numpy-2.3.5-cp314-cp314t-win_amd64.whl", hash = "sha256:c8a9958e88b65c3b27e22ca2a076311636850b612d6bbfb76e8d156aacde2aaf", size = 13105760, upload-time = "2025-11-16T22:52:17.975Z" }, - { url = "https://files.pythonhosted.org/packages/2d/fd/4b5eb0b3e888d86aee4d198c23acec7d214baaf17ea93c1adec94c9518b9/numpy-2.3.5-cp314-cp314t-win_arm64.whl", hash = "sha256:6203fdf9f3dc5bdaed7319ad8698e685c7a3be10819f41d32a0723e611733b42", size = 10545459, upload-time = "2025-11-16T22:52:20.55Z" }, - { url = "https://files.pythonhosted.org/packages/c6/65/f9dea8e109371ade9c782b4e4756a82edf9d3366bca495d84d79859a0b79/numpy-2.3.5-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f0963b55cdd70fad460fa4c1341f12f976bb26cb66021a5580329bd498988310", size = 16910689, upload-time = "2025-11-16T22:52:23.247Z" }, - { url = "https://files.pythonhosted.org/packages/00/4f/edb00032a8fb92ec0a679d3830368355da91a69cab6f3e9c21b64d0bb986/numpy-2.3.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f4255143f5160d0de972d28c8f9665d882b5f61309d8362fdd3e103cf7bf010c", size = 12457053, upload-time = "2025-11-16T22:52:26.367Z" }, - { url = "https://files.pythonhosted.org/packages/16/a4/e8a53b5abd500a63836a29ebe145fc1ab1f2eefe1cfe59276020373ae0aa/numpy-2.3.5-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:a4b9159734b326535f4dd01d947f919c6eefd2d9827466a696c44ced82dfbc18", size = 5285635, upload-time = "2025-11-16T22:52:29.266Z" }, - { url = "https://files.pythonhosted.org/packages/a3/2f/37eeb9014d9c8b3e9c55bc599c68263ca44fdbc12a93e45a21d1d56df737/numpy-2.3.5-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:2feae0d2c91d46e59fcd62784a3a83b3fb677fead592ce51b5a6fbb4f95965ff", size = 6801770, upload-time = "2025-11-16T22:52:31.421Z" }, - { url = "https://files.pythonhosted.org/packages/7d/e4/68d2f474df2cb671b2b6c2986a02e520671295647dad82484cde80ca427b/numpy-2.3.5-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ffac52f28a7849ad7576293c0cb7b9f08304e8f7d738a8cb8a90ec4c55a998eb", size = 14391768, upload-time = "2025-11-16T22:52:33.593Z" }, - { url = "https://files.pythonhosted.org/packages/b8/50/94ccd8a2b141cb50651fddd4f6a48874acb3c91c8f0842b08a6afc4b0b21/numpy-2.3.5-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63c0e9e7eea69588479ebf4a8a270d5ac22763cc5854e9a7eae952a3908103f7", size = 16729263, upload-time = "2025-11-16T22:52:36.369Z" }, - { url = "https://files.pythonhosted.org/packages/2d/ee/346fa473e666fe14c52fcdd19ec2424157290a032d4c41f98127bfb31ac7/numpy-2.3.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f16417ec91f12f814b10bafe79ef77e70113a2f5f7018640e7425ff979253425", size = 12967213, upload-time = "2025-11-16T22:52:39.38Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/57/fd/0005efbd0af48e55eb3c7208af93f2862d4b1a56cd78e84309a2d959208d/numpy-2.4.2.tar.gz", hash = "sha256:659a6107e31a83c4e33f763942275fd278b21d095094044eb35569e86a21ddae", size = 20723651, upload-time = "2026-01-31T23:13:10.135Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d3/44/71852273146957899753e69986246d6a176061ea183407e95418c2aa4d9a/numpy-2.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e7e88598032542bd49af7c4747541422884219056c268823ef6e5e89851c8825", size = 16955478, upload-time = "2026-01-31T23:10:25.623Z" }, + { url = "https://files.pythonhosted.org/packages/74/41/5d17d4058bd0cd96bcbd4d9ff0fb2e21f52702aab9a72e4a594efa18692f/numpy-2.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7edc794af8b36ca37ef5fcb5e0d128c7e0595c7b96a2318d1badb6fcd8ee86b1", size = 14965467, upload-time = "2026-01-31T23:10:28.186Z" }, + { url = "https://files.pythonhosted.org/packages/49/48/fb1ce8136c19452ed15f033f8aee91d5defe515094e330ce368a0647846f/numpy-2.4.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:6e9f61981ace1360e42737e2bae58b27bf28a1b27e781721047d84bd754d32e7", size = 5475172, upload-time = "2026-01-31T23:10:30.848Z" }, + { url = "https://files.pythonhosted.org/packages/40/a9/3feb49f17bbd1300dd2570432961f5c8a4ffeff1db6f02c7273bd020a4c9/numpy-2.4.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:cb7bbb88aa74908950d979eeaa24dbdf1a865e3c7e45ff0121d8f70387b55f73", size = 6805145, upload-time = "2026-01-31T23:10:32.352Z" }, + { url = "https://files.pythonhosted.org/packages/3f/39/fdf35cbd6d6e2fcad42fcf85ac04a85a0d0fbfbf34b30721c98d602fd70a/numpy-2.4.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4f069069931240b3fc703f1e23df63443dbd6390614c8c44a87d96cd0ec81eb1", size = 15966084, upload-time = "2026-01-31T23:10:34.502Z" }, + { url = "https://files.pythonhosted.org/packages/1b/46/6fa4ea94f1ddf969b2ee941290cca6f1bfac92b53c76ae5f44afe17ceb69/numpy-2.4.2-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c02ef4401a506fb60b411467ad501e1429a3487abca4664871d9ae0b46c8ba32", size = 16899477, upload-time = "2026-01-31T23:10:37.075Z" }, + { url = "https://files.pythonhosted.org/packages/09/a1/2a424e162b1a14a5bd860a464ab4e07513916a64ab1683fae262f735ccd2/numpy-2.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2653de5c24910e49c2b106499803124dde62a5a1fe0eedeaecf4309a5f639390", size = 17323429, upload-time = "2026-01-31T23:10:39.704Z" }, + { url = "https://files.pythonhosted.org/packages/ce/a2/73014149ff250628df72c58204822ac01d768697913881aacf839ff78680/numpy-2.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1ae241bbfc6ae276f94a170b14785e561cb5e7f626b6688cf076af4110887413", size = 18635109, upload-time = "2026-01-31T23:10:41.924Z" }, + { url = "https://files.pythonhosted.org/packages/6c/0c/73e8be2f1accd56df74abc1c5e18527822067dced5ec0861b5bb882c2ce0/numpy-2.4.2-cp311-cp311-win32.whl", hash = "sha256:df1b10187212b198dd45fa943d8985a3c8cf854aed4923796e0e019e113a1bda", size = 6237915, upload-time = "2026-01-31T23:10:45.26Z" }, + { url = "https://files.pythonhosted.org/packages/76/ae/e0265e0163cf127c24c3969d29f1c4c64551a1e375d95a13d32eab25d364/numpy-2.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:b9c618d56a29c9cb1c4da979e9899be7578d2e0b3c24d52079c166324c9e8695", size = 12607972, upload-time = "2026-01-31T23:10:47.021Z" }, + { url = "https://files.pythonhosted.org/packages/29/a5/c43029af9b8014d6ea157f192652c50042e8911f4300f8f6ed3336bf437f/numpy-2.4.2-cp311-cp311-win_arm64.whl", hash = "sha256:47c5a6ed21d9452b10227e5e8a0e1c22979811cad7dcc19d8e3e2fb8fa03f1a3", size = 10485763, upload-time = "2026-01-31T23:10:50.087Z" }, + { url = "https://files.pythonhosted.org/packages/51/6e/6f394c9c77668153e14d4da83bcc247beb5952f6ead7699a1a2992613bea/numpy-2.4.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:21982668592194c609de53ba4933a7471880ccbaadcc52352694a59ecc860b3a", size = 16667963, upload-time = "2026-01-31T23:10:52.147Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f8/55483431f2b2fd015ae6ed4fe62288823ce908437ed49db5a03d15151678/numpy-2.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40397bda92382fcec844066efb11f13e1c9a3e2a8e8f318fb72ed8b6db9f60f1", size = 14693571, upload-time = "2026-01-31T23:10:54.789Z" }, + { url = "https://files.pythonhosted.org/packages/2f/20/18026832b1845cdc82248208dd929ca14c9d8f2bac391f67440707fff27c/numpy-2.4.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:b3a24467af63c67829bfaa61eecf18d5432d4f11992688537be59ecd6ad32f5e", size = 5203469, upload-time = "2026-01-31T23:10:57.343Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/2eb97c8a77daaba34eaa3fa7241a14ac5f51c46a6bd5911361b644c4a1e2/numpy-2.4.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:805cc8de9fd6e7a22da5aed858e0ab16be5a4db6c873dde1d7451c541553aa27", size = 6550820, upload-time = "2026-01-31T23:10:59.429Z" }, + { url = "https://files.pythonhosted.org/packages/b1/91/b97fdfd12dc75b02c44e26c6638241cc004d4079a0321a69c62f51470c4c/numpy-2.4.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d82351358ffbcdcd7b686b90742a9b86632d6c1c051016484fa0b326a0a1548", size = 15663067, upload-time = "2026-01-31T23:11:01.291Z" }, + { url = "https://files.pythonhosted.org/packages/f5/c6/a18e59f3f0b8071cc85cbc8d80cd02d68aa9710170b2553a117203d46936/numpy-2.4.2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e35d3e0144137d9fdae62912e869136164534d64a169f86438bc9561b6ad49f", size = 16619782, upload-time = "2026-01-31T23:11:03.669Z" }, + { url = "https://files.pythonhosted.org/packages/b7/83/9751502164601a79e18847309f5ceec0b1446d7b6aa12305759b72cf98b2/numpy-2.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adb6ed2ad29b9e15321d167d152ee909ec73395901b70936f029c3bc6d7f4460", size = 17013128, upload-time = "2026-01-31T23:11:05.913Z" }, + { url = "https://files.pythonhosted.org/packages/61/c4/c4066322256ec740acc1c8923a10047818691d2f8aec254798f3dd90f5f2/numpy-2.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8906e71fd8afcb76580404e2a950caef2685df3d2a57fe82a86ac8d33cc007ba", size = 18345324, upload-time = "2026-01-31T23:11:08.248Z" }, + { url = "https://files.pythonhosted.org/packages/ab/af/6157aa6da728fa4525a755bfad486ae7e3f76d4c1864138003eb84328497/numpy-2.4.2-cp312-cp312-win32.whl", hash = "sha256:ec055f6dae239a6299cace477b479cca2fc125c5675482daf1dd886933a1076f", size = 5960282, upload-time = "2026-01-31T23:11:10.497Z" }, + { url = "https://files.pythonhosted.org/packages/92/0f/7ceaaeaacb40567071e94dbf2c9480c0ae453d5bb4f52bea3892c39dc83c/numpy-2.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:209fae046e62d0ce6435fcfe3b1a10537e858249b3d9b05829e2a05218296a85", size = 12314210, upload-time = "2026-01-31T23:11:12.176Z" }, + { url = "https://files.pythonhosted.org/packages/2f/a3/56c5c604fae6dd40fa2ed3040d005fca97e91bd320d232ac9931d77ba13c/numpy-2.4.2-cp312-cp312-win_arm64.whl", hash = "sha256:fbde1b0c6e81d56f5dccd95dd4a711d9b95df1ae4009a60887e56b27e8d903fa", size = 10220171, upload-time = "2026-01-31T23:11:14.684Z" }, + { url = "https://files.pythonhosted.org/packages/a1/22/815b9fe25d1d7ae7d492152adbc7226d3eff731dffc38fe970589fcaaa38/numpy-2.4.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:25f2059807faea4b077a2b6837391b5d830864b3543627f381821c646f31a63c", size = 16663696, upload-time = "2026-01-31T23:11:17.516Z" }, + { url = "https://files.pythonhosted.org/packages/09/f0/817d03a03f93ba9c6c8993de509277d84e69f9453601915e4a69554102a1/numpy-2.4.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bd3a7a9f5847d2fb8c2c6d1c862fa109c31a9abeca1a3c2bd5a64572955b2979", size = 14688322, upload-time = "2026-01-31T23:11:19.883Z" }, + { url = "https://files.pythonhosted.org/packages/da/b4/f805ab79293c728b9a99438775ce51885fd4f31b76178767cfc718701a39/numpy-2.4.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8e4549f8a3c6d13d55041925e912bfd834285ef1dd64d6bc7d542583355e2e98", size = 5198157, upload-time = "2026-01-31T23:11:22.375Z" }, + { url = "https://files.pythonhosted.org/packages/74/09/826e4289844eccdcd64aac27d13b0fd3f32039915dd5b9ba01baae1f436c/numpy-2.4.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:aea4f66ff44dfddf8c2cffd66ba6538c5ec67d389285292fe428cb2c738c8aef", size = 6546330, upload-time = "2026-01-31T23:11:23.958Z" }, + { url = "https://files.pythonhosted.org/packages/19/fb/cbfdbfa3057a10aea5422c558ac57538e6acc87ec1669e666d32ac198da7/numpy-2.4.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3cd545784805de05aafe1dde61752ea49a359ccba9760c1e5d1c88a93bbf2b7", size = 15660968, upload-time = "2026-01-31T23:11:25.713Z" }, + { url = "https://files.pythonhosted.org/packages/04/dc/46066ce18d01645541f0186877377b9371b8fa8017fa8262002b4ef22612/numpy-2.4.2-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0d9b7c93578baafcbc5f0b83eaf17b79d345c6f36917ba0c67f45226911d499", size = 16607311, upload-time = "2026-01-31T23:11:28.117Z" }, + { url = "https://files.pythonhosted.org/packages/14/d9/4b5adfc39a43fa6bf918c6d544bc60c05236cc2f6339847fc5b35e6cb5b0/numpy-2.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f74f0f7779cc7ae07d1810aab8ac6b1464c3eafb9e283a40da7309d5e6e48fbb", size = 17012850, upload-time = "2026-01-31T23:11:30.888Z" }, + { url = "https://files.pythonhosted.org/packages/b7/20/adb6e6adde6d0130046e6fdfb7675cc62bc2f6b7b02239a09eb58435753d/numpy-2.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c7ac672d699bf36275c035e16b65539931347d68b70667d28984c9fb34e07fa7", size = 18334210, upload-time = "2026-01-31T23:11:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/78/0e/0a73b3dff26803a8c02baa76398015ea2a5434d9b8265a7898a6028c1591/numpy-2.4.2-cp313-cp313-win32.whl", hash = "sha256:8e9afaeb0beff068b4d9cd20d322ba0ee1cecfb0b08db145e4ab4dd44a6b5110", size = 5958199, upload-time = "2026-01-31T23:11:35.385Z" }, + { url = "https://files.pythonhosted.org/packages/43/bc/6352f343522fcb2c04dbaf94cb30cca6fd32c1a750c06ad6231b4293708c/numpy-2.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:7df2de1e4fba69a51c06c28f5a3de36731eb9639feb8e1cf7e4a7b0daf4cf622", size = 12310848, upload-time = "2026-01-31T23:11:38.001Z" }, + { url = "https://files.pythonhosted.org/packages/6e/8d/6da186483e308da5da1cc6918ce913dcfe14ffde98e710bfeff2a6158d4e/numpy-2.4.2-cp313-cp313-win_arm64.whl", hash = "sha256:0fece1d1f0a89c16b03442eae5c56dc0be0c7883b5d388e0c03f53019a4bfd71", size = 10221082, upload-time = "2026-01-31T23:11:40.392Z" }, + { url = "https://files.pythonhosted.org/packages/25/a1/9510aa43555b44781968935c7548a8926274f815de42ad3997e9e83680dd/numpy-2.4.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5633c0da313330fd20c484c78cdd3f9b175b55e1a766c4a174230c6b70ad8262", size = 14815866, upload-time = "2026-01-31T23:11:42.495Z" }, + { url = "https://files.pythonhosted.org/packages/36/30/6bbb5e76631a5ae46e7923dd16ca9d3f1c93cfa8d4ed79a129814a9d8db3/numpy-2.4.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d9f64d786b3b1dd742c946c42d15b07497ed14af1a1f3ce840cce27daa0ce913", size = 5325631, upload-time = "2026-01-31T23:11:44.7Z" }, + { url = "https://files.pythonhosted.org/packages/46/00/3a490938800c1923b567b3a15cd17896e68052e2145d8662aaf3e1ffc58f/numpy-2.4.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:b21041e8cb6a1eb5312dd1d2f80a94d91efffb7a06b70597d44f1bd2dfc315ab", size = 6646254, upload-time = "2026-01-31T23:11:46.341Z" }, + { url = "https://files.pythonhosted.org/packages/d3/e9/fac0890149898a9b609caa5af7455a948b544746e4b8fe7c212c8edd71f8/numpy-2.4.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:00ab83c56211a1d7c07c25e3217ea6695e50a3e2f255053686b081dc0b091a82", size = 15720138, upload-time = "2026-01-31T23:11:48.082Z" }, + { url = "https://files.pythonhosted.org/packages/ea/5c/08887c54e68e1e28df53709f1893ce92932cc6f01f7c3d4dc952f61ffd4e/numpy-2.4.2-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fb882da679409066b4603579619341c6d6898fc83a8995199d5249f986e8e8f", size = 16655398, upload-time = "2026-01-31T23:11:50.293Z" }, + { url = "https://files.pythonhosted.org/packages/4d/89/253db0fa0e66e9129c745e4ef25631dc37d5f1314dad2b53e907b8538e6d/numpy-2.4.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:66cb9422236317f9d44b67b4d18f44efe6e9c7f8794ac0462978513359461554", size = 17079064, upload-time = "2026-01-31T23:11:52.927Z" }, + { url = "https://files.pythonhosted.org/packages/2a/d5/cbade46ce97c59c6c3da525e8d95b7abe8a42974a1dc5c1d489c10433e88/numpy-2.4.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0f01dcf33e73d80bd8dc0f20a71303abbafa26a19e23f6b68d1aa9990af90257", size = 18379680, upload-time = "2026-01-31T23:11:55.22Z" }, + { url = "https://files.pythonhosted.org/packages/40/62/48f99ae172a4b63d981babe683685030e8a3df4f246c893ea5c6ef99f018/numpy-2.4.2-cp313-cp313t-win32.whl", hash = "sha256:52b913ec40ff7ae845687b0b34d8d93b60cb66dcee06996dd5c99f2fc9328657", size = 6082433, upload-time = "2026-01-31T23:11:58.096Z" }, + { url = "https://files.pythonhosted.org/packages/07/38/e054a61cfe48ad9f1ed0d188e78b7e26859d0b60ef21cd9de4897cdb5326/numpy-2.4.2-cp313-cp313t-win_amd64.whl", hash = "sha256:5eea80d908b2c1f91486eb95b3fb6fab187e569ec9752ab7d9333d2e66bf2d6b", size = 12451181, upload-time = "2026-01-31T23:11:59.782Z" }, + { url = "https://files.pythonhosted.org/packages/6e/a4/a05c3a6418575e185dd84d0b9680b6bb2e2dc3e4202f036b7b4e22d6e9dc/numpy-2.4.2-cp313-cp313t-win_arm64.whl", hash = "sha256:fd49860271d52127d61197bb50b64f58454e9f578cb4b2c001a6de8b1f50b0b1", size = 10290756, upload-time = "2026-01-31T23:12:02.438Z" }, + { url = "https://files.pythonhosted.org/packages/18/88/b7df6050bf18fdcfb7046286c6535cabbdd2064a3440fca3f069d319c16e/numpy-2.4.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:444be170853f1f9d528428eceb55f12918e4fda5d8805480f36a002f1415e09b", size = 16663092, upload-time = "2026-01-31T23:12:04.521Z" }, + { url = "https://files.pythonhosted.org/packages/25/7a/1fee4329abc705a469a4afe6e69b1ef7e915117747886327104a8493a955/numpy-2.4.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d1240d50adff70c2a88217698ca844723068533f3f5c5fa6ee2e3220e3bdb000", size = 14698770, upload-time = "2026-01-31T23:12:06.96Z" }, + { url = "https://files.pythonhosted.org/packages/fb/0b/f9e49ba6c923678ad5bc38181c08ac5e53b7a5754dbca8e581aa1a56b1ff/numpy-2.4.2-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:7cdde6de52fb6664b00b056341265441192d1291c130e99183ec0d4b110ff8b1", size = 5208562, upload-time = "2026-01-31T23:12:09.632Z" }, + { url = "https://files.pythonhosted.org/packages/7d/12/d7de8f6f53f9bb76997e5e4c069eda2051e3fe134e9181671c4391677bb2/numpy-2.4.2-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:cda077c2e5b780200b6b3e09d0b42205a3d1c68f30c6dceb90401c13bff8fe74", size = 6543710, upload-time = "2026-01-31T23:12:11.969Z" }, + { url = "https://files.pythonhosted.org/packages/09/63/c66418c2e0268a31a4cf8a8b512685748200f8e8e8ec6c507ce14e773529/numpy-2.4.2-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d30291931c915b2ab5717c2974bb95ee891a1cf22ebc16a8006bd59cd210d40a", size = 15677205, upload-time = "2026-01-31T23:12:14.33Z" }, + { url = "https://files.pythonhosted.org/packages/5d/6c/7f237821c9642fb2a04d2f1e88b4295677144ca93285fd76eff3bcba858d/numpy-2.4.2-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bba37bc29d4d85761deed3954a1bc62be7cf462b9510b51d367b769a8c8df325", size = 16611738, upload-time = "2026-01-31T23:12:16.525Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a7/39c4cdda9f019b609b5c473899d87abff092fc908cfe4d1ecb2fcff453b0/numpy-2.4.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b2f0073ed0868db1dcd86e052d37279eef185b9c8db5bf61f30f46adac63c909", size = 17028888, upload-time = "2026-01-31T23:12:19.306Z" }, + { url = "https://files.pythonhosted.org/packages/da/b3/e84bb64bdfea967cc10950d71090ec2d84b49bc691df0025dddb7c26e8e3/numpy-2.4.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7f54844851cdb630ceb623dcec4db3240d1ac13d4990532446761baede94996a", size = 18339556, upload-time = "2026-01-31T23:12:21.816Z" }, + { url = "https://files.pythonhosted.org/packages/88/f5/954a291bc1192a27081706862ac62bb5920fbecfbaa302f64682aa90beed/numpy-2.4.2-cp314-cp314-win32.whl", hash = "sha256:12e26134a0331d8dbd9351620f037ec470b7c75929cb8a1537f6bfe411152a1a", size = 6006899, upload-time = "2026-01-31T23:12:24.14Z" }, + { url = "https://files.pythonhosted.org/packages/05/cb/eff72a91b2efdd1bc98b3b8759f6a1654aa87612fc86e3d87d6fe4f948c4/numpy-2.4.2-cp314-cp314-win_amd64.whl", hash = "sha256:068cdb2d0d644cdb45670810894f6a0600797a69c05f1ac478e8d31670b8ee75", size = 12443072, upload-time = "2026-01-31T23:12:26.33Z" }, + { url = "https://files.pythonhosted.org/packages/37/75/62726948db36a56428fce4ba80a115716dc4fad6a3a4352487f8bb950966/numpy-2.4.2-cp314-cp314-win_arm64.whl", hash = "sha256:6ed0be1ee58eef41231a5c943d7d1375f093142702d5723ca2eb07db9b934b05", size = 10494886, upload-time = "2026-01-31T23:12:28.488Z" }, + { url = "https://files.pythonhosted.org/packages/36/2f/ee93744f1e0661dc267e4b21940870cabfae187c092e1433b77b09b50ac4/numpy-2.4.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:98f16a80e917003a12c0580f97b5f875853ebc33e2eaa4bccfc8201ac6869308", size = 14818567, upload-time = "2026-01-31T23:12:30.709Z" }, + { url = "https://files.pythonhosted.org/packages/a7/24/6535212add7d76ff938d8bdc654f53f88d35cddedf807a599e180dcb8e66/numpy-2.4.2-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:20abd069b9cda45874498b245c8015b18ace6de8546bf50dfa8cea1696ed06ef", size = 5328372, upload-time = "2026-01-31T23:12:32.962Z" }, + { url = "https://files.pythonhosted.org/packages/5e/9d/c48f0a035725f925634bf6b8994253b43f2047f6778a54147d7e213bc5a7/numpy-2.4.2-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:e98c97502435b53741540a5717a6749ac2ada901056c7db951d33e11c885cc7d", size = 6649306, upload-time = "2026-01-31T23:12:34.797Z" }, + { url = "https://files.pythonhosted.org/packages/81/05/7c73a9574cd4a53a25907bad38b59ac83919c0ddc8234ec157f344d57d9a/numpy-2.4.2-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:da6cad4e82cb893db4b69105c604d805e0c3ce11501a55b5e9f9083b47d2ffe8", size = 15722394, upload-time = "2026-01-31T23:12:36.565Z" }, + { url = "https://files.pythonhosted.org/packages/35/fa/4de10089f21fc7d18442c4a767ab156b25c2a6eaf187c0db6d9ecdaeb43f/numpy-2.4.2-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e4424677ce4b47fe73c8b5556d876571f7c6945d264201180db2dc34f676ab5", size = 16653343, upload-time = "2026-01-31T23:12:39.188Z" }, + { url = "https://files.pythonhosted.org/packages/b8/f9/d33e4ffc857f3763a57aa85650f2e82486832d7492280ac21ba9efda80da/numpy-2.4.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2b8f157c8a6f20eb657e240f8985cc135598b2b46985c5bccbde7616dc9c6b1e", size = 17078045, upload-time = "2026-01-31T23:12:42.041Z" }, + { url = "https://files.pythonhosted.org/packages/c8/b8/54bdb43b6225badbea6389fa038c4ef868c44f5890f95dd530a218706da3/numpy-2.4.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5daf6f3914a733336dab21a05cdec343144600e964d2fcdabaac0c0269874b2a", size = 18380024, upload-time = "2026-01-31T23:12:44.331Z" }, + { url = "https://files.pythonhosted.org/packages/a5/55/6e1a61ded7af8df04016d81b5b02daa59f2ea9252ee0397cb9f631efe9e5/numpy-2.4.2-cp314-cp314t-win32.whl", hash = "sha256:8c50dd1fc8826f5b26a5ee4d77ca55d88a895f4e4819c7ecc2a9f5905047a443", size = 6153937, upload-time = "2026-01-31T23:12:47.229Z" }, + { url = "https://files.pythonhosted.org/packages/45/aa/fa6118d1ed6d776b0983f3ceac9b1a5558e80df9365b1c3aa6d42bf9eee4/numpy-2.4.2-cp314-cp314t-win_amd64.whl", hash = "sha256:fcf92bee92742edd401ba41135185866f7026c502617f422eb432cfeca4fe236", size = 12631844, upload-time = "2026-01-31T23:12:48.997Z" }, + { url = "https://files.pythonhosted.org/packages/32/0a/2ec5deea6dcd158f254a7b372fb09cfba5719419c8d66343bab35237b3fb/numpy-2.4.2-cp314-cp314t-win_arm64.whl", hash = "sha256:1f92f53998a17265194018d1cc321b2e96e900ca52d54c7c77837b71b9465181", size = 10565379, upload-time = "2026-01-31T23:12:51.345Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f8/50e14d36d915ef64d8f8bc4a087fc8264d82c785eda6711f80ab7e620335/numpy-2.4.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:89f7268c009bc492f506abd6f5265defa7cb3f7487dc21d357c3d290add45082", size = 16833179, upload-time = "2026-01-31T23:12:53.5Z" }, + { url = "https://files.pythonhosted.org/packages/17/17/809b5cad63812058a8189e91a1e2d55a5a18fd04611dbad244e8aeae465c/numpy-2.4.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6dee3bb76aa4009d5a912180bf5b2de012532998d094acee25d9cb8dee3e44a", size = 14889755, upload-time = "2026-01-31T23:12:55.933Z" }, + { url = "https://files.pythonhosted.org/packages/3e/ea/181b9bcf7627fc8371720316c24db888dcb9829b1c0270abf3d288b2e29b/numpy-2.4.2-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:cd2bd2bbed13e213d6b55dc1d035a4f91748a7d3edc9480c13898b0353708920", size = 5399500, upload-time = "2026-01-31T23:12:58.671Z" }, + { url = "https://files.pythonhosted.org/packages/33/9f/413adf3fc955541ff5536b78fcf0754680b3c6d95103230252a2c9408d23/numpy-2.4.2-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:cf28c0c1d4c4bf00f509fa7eb02c58d7caf221b50b467bcb0d9bbf1584d5c821", size = 6714252, upload-time = "2026-01-31T23:13:00.518Z" }, + { url = "https://files.pythonhosted.org/packages/91/da/643aad274e29ccbdf42ecd94dafe524b81c87bcb56b83872d54827f10543/numpy-2.4.2-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e04ae107ac591763a47398bb45b568fc38f02dbc4aa44c063f67a131f99346cb", size = 15797142, upload-time = "2026-01-31T23:13:02.219Z" }, + { url = "https://files.pythonhosted.org/packages/66/27/965b8525e9cb5dc16481b30a1b3c21e50c7ebf6e9dbd48d0c4d0d5089c7e/numpy-2.4.2-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:602f65afdef699cda27ec0b9224ae5dc43e328f4c24c689deaf77133dbee74d0", size = 16727979, upload-time = "2026-01-31T23:13:04.62Z" }, + { url = "https://files.pythonhosted.org/packages/de/e5/b7d20451657664b07986c2f6e3be564433f5dcaf3482d68eaecd79afaf03/numpy-2.4.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:be71bf1edb48ebbbf7f6337b5bfd2f895d1902f6335a5830b20141fc126ffba0", size = 12502577, upload-time = "2026-01-31T23:13:07.08Z" }, ] [[package]] @@ -3471,7 +3503,7 @@ wheels = [ [[package]] name = "pandas" -version = "3.0.0" +version = "3.0.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.14' and sys_platform == 'win32'", @@ -3488,59 +3520,59 @@ resolution-markers = [ "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] dependencies = [ - { name = "numpy", version = "2.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "python-dateutil", marker = "python_full_version >= '3.11'" }, { name = "tzdata", marker = "(python_full_version >= '3.11' and sys_platform == 'emscripten') or (python_full_version >= '3.11' and sys_platform == 'win32')" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/de/da/b1dc0481ab8d55d0f46e343cfe67d4551a0e14fcee52bd38ca1bd73258d8/pandas-3.0.0.tar.gz", hash = "sha256:0facf7e87d38f721f0af46fe70d97373a37701b1c09f7ed7aeeb292ade5c050f", size = 4633005, upload-time = "2026-01-21T15:52:04.726Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/46/1e/b184654a856e75e975a6ee95d6577b51c271cd92cb2b020c9378f53e0032/pandas-3.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d64ce01eb9cdca96a15266aa679ae50212ec52757c79204dbc7701a222401850", size = 10313247, upload-time = "2026-01-21T15:50:15.775Z" }, - { url = "https://files.pythonhosted.org/packages/dd/5e/e04a547ad0f0183bf151fd7c7a477468e3b85ff2ad231c566389e6cc9587/pandas-3.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:613e13426069793aa1ec53bdcc3b86e8d32071daea138bbcf4fa959c9cdaa2e2", size = 9913131, upload-time = "2026-01-21T15:50:18.611Z" }, - { url = "https://files.pythonhosted.org/packages/a2/93/bb77bfa9fc2aba9f7204db807d5d3fb69832ed2854c60ba91b4c65ba9219/pandas-3.0.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0192fee1f1a8e743b464a6607858ee4b071deb0b118eb143d71c2a1d170996d5", size = 10741925, upload-time = "2026-01-21T15:50:21.058Z" }, - { url = "https://files.pythonhosted.org/packages/62/fb/89319812eb1d714bfc04b7f177895caeba8ab4a37ef6712db75ed786e2e0/pandas-3.0.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f0b853319dec8d5e0c8b875374c078ef17f2269986a78168d9bd57e49bf650ae", size = 11245979, upload-time = "2026-01-21T15:50:23.413Z" }, - { url = "https://files.pythonhosted.org/packages/a9/63/684120486f541fc88da3862ed31165b3b3e12b6a1c7b93be4597bc84e26c/pandas-3.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:707a9a877a876c326ae2cb640fbdc4ef63b0a7b9e2ef55c6df9942dcee8e2af9", size = 11756337, upload-time = "2026-01-21T15:50:25.932Z" }, - { url = "https://files.pythonhosted.org/packages/39/92/7eb0ad232312b59aec61550c3c81ad0743898d10af5df7f80bc5e5065416/pandas-3.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:afd0aa3d0b5cda6e0b8ffc10dbcca3b09ef3cbcd3fe2b27364f85fdc04e1989d", size = 12325517, upload-time = "2026-01-21T15:50:27.952Z" }, - { url = "https://files.pythonhosted.org/packages/51/27/bf9436dd0a4fc3130acec0828951c7ef96a0631969613a9a35744baf27f6/pandas-3.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:113b4cca2614ff7e5b9fee9b6f066618fe73c5a83e99d721ffc41217b2bf57dd", size = 9881576, upload-time = "2026-01-21T15:50:30.149Z" }, - { url = "https://files.pythonhosted.org/packages/e7/2b/c618b871fce0159fd107516336e82891b404e3f340821853c2fc28c7830f/pandas-3.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c14837eba8e99a8da1527c0280bba29b0eb842f64aa94982c5e21227966e164b", size = 9140807, upload-time = "2026-01-21T15:50:32.308Z" }, - { url = "https://files.pythonhosted.org/packages/0b/38/db33686f4b5fa64d7af40d96361f6a4615b8c6c8f1b3d334eee46ae6160e/pandas-3.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9803b31f5039b3c3b10cc858c5e40054adb4b29b4d81cb2fd789f4121c8efbcd", size = 10334013, upload-time = "2026-01-21T15:50:34.771Z" }, - { url = "https://files.pythonhosted.org/packages/a5/7b/9254310594e9774906bacdd4e732415e1f86ab7dbb4b377ef9ede58cd8ec/pandas-3.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:14c2a4099cd38a1d18ff108168ea417909b2dea3bd1ebff2ccf28ddb6a74d740", size = 9874154, upload-time = "2026-01-21T15:50:36.67Z" }, - { url = "https://files.pythonhosted.org/packages/63/d4/726c5a67a13bc66643e66d2e9ff115cead482a44fc56991d0c4014f15aaf/pandas-3.0.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d257699b9a9960e6125686098d5714ac59d05222bef7a5e6af7a7fd87c650801", size = 10384433, upload-time = "2026-01-21T15:50:39.132Z" }, - { url = "https://files.pythonhosted.org/packages/bf/2e/9211f09bedb04f9832122942de8b051804b31a39cfbad199a819bb88d9f3/pandas-3.0.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:69780c98f286076dcafca38d8b8eee1676adf220199c0a39f0ecbf976b68151a", size = 10864519, upload-time = "2026-01-21T15:50:41.043Z" }, - { url = "https://files.pythonhosted.org/packages/00/8d/50858522cdc46ac88b9afdc3015e298959a70a08cd21e008a44e9520180c/pandas-3.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4a66384f017240f3858a4c8a7cf21b0591c3ac885cddb7758a589f0f71e87ebb", size = 11394124, upload-time = "2026-01-21T15:50:43.377Z" }, - { url = "https://files.pythonhosted.org/packages/86/3f/83b2577db02503cd93d8e95b0f794ad9d4be0ba7cb6c8bcdcac964a34a42/pandas-3.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be8c515c9bc33989d97b89db66ea0cececb0f6e3c2a87fcc8b69443a6923e95f", size = 11920444, upload-time = "2026-01-21T15:50:45.932Z" }, - { url = "https://files.pythonhosted.org/packages/64/2d/4f8a2f192ed12c90a0aab47f5557ece0e56b0370c49de9454a09de7381b2/pandas-3.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:a453aad8c4f4e9f166436994a33884442ea62aa8b27d007311e87521b97246e1", size = 9730970, upload-time = "2026-01-21T15:50:47.962Z" }, - { url = "https://files.pythonhosted.org/packages/d4/64/ff571be435cf1e643ca98d0945d76732c0b4e9c37191a89c8550b105eed1/pandas-3.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:da768007b5a33057f6d9053563d6b74dd6d029c337d93c6d0d22a763a5c2ecc0", size = 9041950, upload-time = "2026-01-21T15:50:50.422Z" }, - { url = "https://files.pythonhosted.org/packages/6f/fa/7f0ac4ca8877c57537aaff2a842f8760e630d8e824b730eb2e859ffe96ca/pandas-3.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b78d646249b9a2bc191040988c7bb524c92fa8534fb0898a0741d7e6f2ffafa6", size = 10307129, upload-time = "2026-01-21T15:50:52.877Z" }, - { url = "https://files.pythonhosted.org/packages/6f/11/28a221815dcea4c0c9414dfc845e34a84a6a7dabc6da3194498ed5ba4361/pandas-3.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bc9cba7b355cb4162442a88ce495e01cb605f17ac1e27d6596ac963504e0305f", size = 9850201, upload-time = "2026-01-21T15:50:54.807Z" }, - { url = "https://files.pythonhosted.org/packages/ba/da/53bbc8c5363b7e5bd10f9ae59ab250fc7a382ea6ba08e4d06d8694370354/pandas-3.0.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c9a1a149aed3b6c9bf246033ff91e1b02d529546c5d6fb6b74a28fea0cf4c70", size = 10354031, upload-time = "2026-01-21T15:50:57.463Z" }, - { url = "https://files.pythonhosted.org/packages/f7/a3/51e02ebc2a14974170d51e2410dfdab58870ea9bcd37cda15bd553d24dc4/pandas-3.0.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:95683af6175d884ee89471842acfca29172a85031fccdabc35e50c0984470a0e", size = 10861165, upload-time = "2026-01-21T15:50:59.32Z" }, - { url = "https://files.pythonhosted.org/packages/a5/fe/05a51e3cac11d161472b8297bd41723ea98013384dd6d76d115ce3482f9b/pandas-3.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1fbbb5a7288719e36b76b4f18d46ede46e7f916b6c8d9915b756b0a6c3f792b3", size = 11359359, upload-time = "2026-01-21T15:51:02.014Z" }, - { url = "https://files.pythonhosted.org/packages/ee/56/ba620583225f9b85a4d3e69c01df3e3870659cc525f67929b60e9f21dcd1/pandas-3.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8e8b9808590fa364416b49b2a35c1f4cf2785a6c156935879e57f826df22038e", size = 11912907, upload-time = "2026-01-21T15:51:05.175Z" }, - { url = "https://files.pythonhosted.org/packages/c9/8c/c6638d9f67e45e07656b3826405c5cc5f57f6fd07c8b2572ade328c86e22/pandas-3.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:98212a38a709feb90ae658cb6227ea3657c22ba8157d4b8f913cd4c950de5e7e", size = 9732138, upload-time = "2026-01-21T15:51:07.569Z" }, - { url = "https://files.pythonhosted.org/packages/7b/bf/bd1335c3bf1770b6d8fed2799993b11c4971af93bb1b729b9ebbc02ca2ec/pandas-3.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:177d9df10b3f43b70307a149d7ec49a1229a653f907aa60a48f1877d0e6be3be", size = 9033568, upload-time = "2026-01-21T15:51:09.484Z" }, - { url = "https://files.pythonhosted.org/packages/8e/c6/f5e2171914d5e29b9171d495344097d54e3ffe41d2d85d8115baba4dc483/pandas-3.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2713810ad3806767b89ad3b7b69ba153e1c6ff6d9c20f9c2140379b2a98b6c98", size = 10741936, upload-time = "2026-01-21T15:51:11.693Z" }, - { url = "https://files.pythonhosted.org/packages/51/88/9a0164f99510a1acb9f548691f022c756c2314aad0d8330a24616c14c462/pandas-3.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:15d59f885ee5011daf8335dff47dcb8a912a27b4ad7826dc6cbe809fd145d327", size = 10393884, upload-time = "2026-01-21T15:51:14.197Z" }, - { url = "https://files.pythonhosted.org/packages/e0/53/b34d78084d88d8ae2b848591229da8826d1e65aacf00b3abe34023467648/pandas-3.0.0-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:24e6547fb64d2c92665dd2adbfa4e85fa4fd70a9c070e7cfb03b629a0bbab5eb", size = 10310740, upload-time = "2026-01-21T15:51:16.093Z" }, - { url = "https://files.pythonhosted.org/packages/5b/d3/bee792e7c3d6930b74468d990604325701412e55d7aaf47460a22311d1a5/pandas-3.0.0-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:48ee04b90e2505c693d3f8e8f524dab8cb8aaf7ddcab52c92afa535e717c4812", size = 10700014, upload-time = "2026-01-21T15:51:18.818Z" }, - { url = "https://files.pythonhosted.org/packages/55/db/2570bc40fb13aaed1cbc3fbd725c3a60ee162477982123c3adc8971e7ac1/pandas-3.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:66f72fb172959af42a459e27a8d8d2c7e311ff4c1f7db6deb3b643dbc382ae08", size = 11323737, upload-time = "2026-01-21T15:51:20.784Z" }, - { url = "https://files.pythonhosted.org/packages/bc/2e/297ac7f21c8181b62a4cccebad0a70caf679adf3ae5e83cb676194c8acc3/pandas-3.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4a4a400ca18230976724a5066f20878af785f36c6756e498e94c2a5e5d57779c", size = 11771558, upload-time = "2026-01-21T15:51:22.977Z" }, - { url = "https://files.pythonhosted.org/packages/0a/46/e1c6876d71c14332be70239acce9ad435975a80541086e5ffba2f249bcf6/pandas-3.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:940eebffe55528074341a5a36515f3e4c5e25e958ebbc764c9502cfc35ba3faa", size = 10473771, upload-time = "2026-01-21T15:51:25.285Z" }, - { url = "https://files.pythonhosted.org/packages/c0/db/0270ad9d13c344b7a36fa77f5f8344a46501abf413803e885d22864d10bf/pandas-3.0.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:597c08fb9fef0edf1e4fa2f9828dd27f3d78f9b8c9b4a748d435ffc55732310b", size = 10312075, upload-time = "2026-01-21T15:51:28.5Z" }, - { url = "https://files.pythonhosted.org/packages/09/9f/c176f5e9717f7c91becfe0f55a52ae445d3f7326b4a2cf355978c51b7913/pandas-3.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:447b2d68ac5edcbf94655fe909113a6dba6ef09ad7f9f60c80477825b6c489fe", size = 9900213, upload-time = "2026-01-21T15:51:30.955Z" }, - { url = "https://files.pythonhosted.org/packages/d9/e7/63ad4cc10b257b143e0a5ebb04304ad806b4e1a61c5da25f55896d2ca0f4/pandas-3.0.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:debb95c77ff3ed3ba0d9aa20c3a2f19165cc7956362f9873fce1ba0a53819d70", size = 10428768, upload-time = "2026-01-21T15:51:33.018Z" }, - { url = "https://files.pythonhosted.org/packages/9e/0e/4e4c2d8210f20149fd2248ef3fff26623604922bd564d915f935a06dd63d/pandas-3.0.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fedabf175e7cd82b69b74c30adbaa616de301291a5231138d7242596fc296a8d", size = 10882954, upload-time = "2026-01-21T15:51:35.287Z" }, - { url = "https://files.pythonhosted.org/packages/c6/60/c9de8ac906ba1f4d2250f8a951abe5135b404227a55858a75ad26f84db47/pandas-3.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:412d1a89aab46889f3033a386912efcdfa0f1131c5705ff5b668dda88305e986", size = 11430293, upload-time = "2026-01-21T15:51:37.57Z" }, - { url = "https://files.pythonhosted.org/packages/a1/69/806e6637c70920e5787a6d6896fd707f8134c2c55cd761e7249a97b7dc5a/pandas-3.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e979d22316f9350c516479dd3a92252be2937a9531ed3a26ec324198a99cdd49", size = 11952452, upload-time = "2026-01-21T15:51:39.618Z" }, - { url = "https://files.pythonhosted.org/packages/cb/de/918621e46af55164c400ab0ef389c9d969ab85a43d59ad1207d4ddbe30a5/pandas-3.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:083b11415b9970b6e7888800c43c82e81a06cd6b06755d84804444f0007d6bb7", size = 9851081, upload-time = "2026-01-21T15:51:41.758Z" }, - { url = "https://files.pythonhosted.org/packages/91/a1/3562a18dd0bd8c73344bfa26ff90c53c72f827df119d6d6b1dacc84d13e3/pandas-3.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:5db1e62cb99e739fa78a28047e861b256d17f88463c76b8dafc7c1338086dca8", size = 9174610, upload-time = "2026-01-21T15:51:44.312Z" }, - { url = "https://files.pythonhosted.org/packages/ce/26/430d91257eaf366f1737d7a1c158677caaf6267f338ec74e3a1ec444111c/pandas-3.0.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:697b8f7d346c68274b1b93a170a70974cdc7d7354429894d5927c1effdcccd73", size = 10761999, upload-time = "2026-01-21T15:51:46.899Z" }, - { url = "https://files.pythonhosted.org/packages/ec/1a/954eb47736c2b7f7fe6a9d56b0cb6987773c00faa3c6451a43db4beb3254/pandas-3.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8cb3120f0d9467ed95e77f67a75e030b67545bcfa08964e349252d674171def2", size = 10410279, upload-time = "2026-01-21T15:51:48.89Z" }, - { url = "https://files.pythonhosted.org/packages/20/fc/b96f3a5a28b250cd1b366eb0108df2501c0f38314a00847242abab71bb3a/pandas-3.0.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:33fd3e6baa72899746b820c31e4b9688c8e1b7864d7aec2de7ab5035c285277a", size = 10330198, upload-time = "2026-01-21T15:51:51.015Z" }, - { url = "https://files.pythonhosted.org/packages/90/b3/d0e2952f103b4fbef1ef22d0c2e314e74fc9064b51cee30890b5e3286ee6/pandas-3.0.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8942e333dc67ceda1095227ad0febb05a3b36535e520154085db632c40ad084", size = 10728513, upload-time = "2026-01-21T15:51:53.387Z" }, - { url = "https://files.pythonhosted.org/packages/76/81/832894f286df828993dc5fd61c63b231b0fb73377e99f6c6c369174cf97e/pandas-3.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:783ac35c4d0fe0effdb0d67161859078618b1b6587a1af15928137525217a721", size = 11345550, upload-time = "2026-01-21T15:51:55.329Z" }, - { url = "https://files.pythonhosted.org/packages/34/a0/ed160a00fb4f37d806406bc0a79a8b62fe67f29d00950f8d16203ff3409b/pandas-3.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:125eb901e233f155b268bbef9abd9afb5819db74f0e677e89a61b246228c71ac", size = 11799386, upload-time = "2026-01-21T15:51:57.457Z" }, - { url = "https://files.pythonhosted.org/packages/36/c8/2ac00d7255252c5e3cf61b35ca92ca25704b0188f7454ca4aec08a33cece/pandas-3.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b86d113b6c109df3ce0ad5abbc259fe86a1bd4adfd4a31a89da42f84f65509bb", size = 10873041, upload-time = "2026-01-21T15:52:00.034Z" }, - { url = "https://files.pythonhosted.org/packages/e6/3f/a80ac00acbc6b35166b42850e98a4f466e2c0d9c64054161ba9620f95680/pandas-3.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:1c39eab3ad38f2d7a249095f0a3d8f8c22cc0f847e98ccf5bbe732b272e2d9fa", size = 9441003, upload-time = "2026-01-21T15:52:02.281Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/2e/0c/b28ed414f080ee0ad153f848586d61d1878f91689950f037f976ce15f6c8/pandas-3.0.1.tar.gz", hash = "sha256:4186a699674af418f655dbd420ed87f50d56b4cd6603784279d9eef6627823c8", size = 4641901, upload-time = "2026-02-17T22:20:16.434Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/07/c7087e003ceee9b9a82539b40414ec557aa795b584a1a346e89180853d79/pandas-3.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:de09668c1bf3b925c07e5762291602f0d789eca1b3a781f99c1c78f6cac0e7ea", size = 10323380, upload-time = "2026-02-17T22:18:16.133Z" }, + { url = "https://files.pythonhosted.org/packages/c1/27/90683c7122febeefe84a56f2cde86a9f05f68d53885cebcc473298dfc33e/pandas-3.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:24ba315ba3d6e5806063ac6eb717504e499ce30bd8c236d8693a5fd3f084c796", size = 9923455, upload-time = "2026-02-17T22:18:19.13Z" }, + { url = "https://files.pythonhosted.org/packages/0e/f1/ed17d927f9950643bc7631aa4c99ff0cc83a37864470bc419345b656a41f/pandas-3.0.1-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:406ce835c55bac912f2a0dcfaf27c06d73c6b04a5dde45f1fd3169ce31337389", size = 10753464, upload-time = "2026-02-17T22:18:21.134Z" }, + { url = "https://files.pythonhosted.org/packages/2e/7c/870c7e7daec2a6c7ff2ac9e33b23317230d4e4e954b35112759ea4a924a7/pandas-3.0.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:830994d7e1f31dd7e790045235605ab61cff6c94defc774547e8b7fdfbff3dc7", size = 11255234, upload-time = "2026-02-17T22:18:24.175Z" }, + { url = "https://files.pythonhosted.org/packages/5c/39/3653fe59af68606282b989c23d1a543ceba6e8099cbcc5f1d506a7bae2aa/pandas-3.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a64ce8b0f2de1d2efd2ae40b0abe7f8ae6b29fbfb3812098ed5a6f8e235ad9bf", size = 11767299, upload-time = "2026-02-17T22:18:26.824Z" }, + { url = "https://files.pythonhosted.org/packages/9b/31/1daf3c0c94a849c7a8dab8a69697b36d313b229918002ba3e409265c7888/pandas-3.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9832c2c69da24b602c32e0c7b1b508a03949c18ba08d4d9f1c1033426685b447", size = 12333292, upload-time = "2026-02-17T22:18:28.996Z" }, + { url = "https://files.pythonhosted.org/packages/1f/67/af63f83cd6ca603a00fe8530c10a60f0879265b8be00b5930e8e78c5b30b/pandas-3.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:84f0904a69e7365f79a0c77d3cdfccbfb05bf87847e3a51a41e1426b0edb9c79", size = 9892176, upload-time = "2026-02-17T22:18:31.79Z" }, + { url = "https://files.pythonhosted.org/packages/79/ab/9c776b14ac4b7b4140788eca18468ea39894bc7340a408f1d1e379856a6b/pandas-3.0.1-cp311-cp311-win_arm64.whl", hash = "sha256:4a68773d5a778afb31d12e34f7dd4612ab90de8c6fb1d8ffe5d4a03b955082a1", size = 9151328, upload-time = "2026-02-17T22:18:35.721Z" }, + { url = "https://files.pythonhosted.org/packages/37/51/b467209c08dae2c624873d7491ea47d2b47336e5403309d433ea79c38571/pandas-3.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:476f84f8c20c9f5bc47252b66b4bb25e1a9fc2fa98cead96744d8116cb85771d", size = 10344357, upload-time = "2026-02-17T22:18:38.262Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f1/e2567ffc8951ab371db2e40b2fe068e36b81d8cf3260f06ae508700e5504/pandas-3.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0ab749dfba921edf641d4036c4c21c0b3ea70fea478165cb98a998fb2a261955", size = 9884543, upload-time = "2026-02-17T22:18:41.476Z" }, + { url = "https://files.pythonhosted.org/packages/d7/39/327802e0b6d693182403c144edacbc27eb82907b57062f23ef5a4c4a5ea7/pandas-3.0.1-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8e36891080b87823aff3640c78649b91b8ff6eea3c0d70aeabd72ea43ab069b", size = 10396030, upload-time = "2026-02-17T22:18:43.822Z" }, + { url = "https://files.pythonhosted.org/packages/3d/fe/89d77e424365280b79d99b3e1e7d606f5165af2f2ecfaf0c6d24c799d607/pandas-3.0.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:532527a701281b9dd371e2f582ed9094f4c12dd9ffb82c0c54ee28d8ac9520c4", size = 10876435, upload-time = "2026-02-17T22:18:45.954Z" }, + { url = "https://files.pythonhosted.org/packages/b5/a6/2a75320849dd154a793f69c951db759aedb8d1dd3939eeacda9bdcfa1629/pandas-3.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:356e5c055ed9b0da1580d465657bc7d00635af4fd47f30afb23025352ba764d1", size = 11405133, upload-time = "2026-02-17T22:18:48.533Z" }, + { url = "https://files.pythonhosted.org/packages/58/53/1d68fafb2e02d7881df66aa53be4cd748d25cbe311f3b3c85c93ea5d30ca/pandas-3.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9d810036895f9ad6345b8f2a338dd6998a74e8483847403582cab67745bff821", size = 11932065, upload-time = "2026-02-17T22:18:50.837Z" }, + { url = "https://files.pythonhosted.org/packages/75/08/67cc404b3a966b6df27b38370ddd96b3b023030b572283d035181854aac5/pandas-3.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:536232a5fe26dd989bd633e7a0c450705fdc86a207fec7254a55e9a22950fe43", size = 9741627, upload-time = "2026-02-17T22:18:53.905Z" }, + { url = "https://files.pythonhosted.org/packages/86/4f/caf9952948fb00d23795f09b893d11f1cacb384e666854d87249530f7cbe/pandas-3.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:0f463ebfd8de7f326d38037c7363c6dacb857c5881ab8961fb387804d6daf2f7", size = 9052483, upload-time = "2026-02-17T22:18:57.31Z" }, + { url = "https://files.pythonhosted.org/packages/0b/48/aad6ec4f8d007534c091e9a7172b3ec1b1ee6d99a9cbb936b5eab6c6cf58/pandas-3.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5272627187b5d9c20e55d27caf5f2cd23e286aba25cadf73c8590e432e2b7262", size = 10317509, upload-time = "2026-02-17T22:18:59.498Z" }, + { url = "https://files.pythonhosted.org/packages/a8/14/5990826f779f79148ae9d3a2c39593dc04d61d5d90541e71b5749f35af95/pandas-3.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:661e0f665932af88c7877f31da0dc743fe9c8f2524bdffe23d24fdcb67ef9d56", size = 9860561, upload-time = "2026-02-17T22:19:02.265Z" }, + { url = "https://files.pythonhosted.org/packages/fa/80/f01ff54664b6d70fed71475543d108a9b7c888e923ad210795bef04ffb7d/pandas-3.0.1-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:75e6e292ff898679e47a2199172593d9f6107fd2dd3617c22c2946e97d5df46e", size = 10365506, upload-time = "2026-02-17T22:19:05.017Z" }, + { url = "https://files.pythonhosted.org/packages/f2/85/ab6d04733a7d6ff32bfc8382bf1b07078228f5d6ebec5266b91bfc5c4ff7/pandas-3.0.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1ff8cf1d2896e34343197685f432450ec99a85ba8d90cce2030c5eee2ef98791", size = 10873196, upload-time = "2026-02-17T22:19:07.204Z" }, + { url = "https://files.pythonhosted.org/packages/48/a9/9301c83d0b47c23ac5deab91c6b39fd98d5b5db4d93b25df8d381451828f/pandas-3.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eca8b4510f6763f3d37359c2105df03a7a221a508f30e396a51d0713d462e68a", size = 11370859, upload-time = "2026-02-17T22:19:09.436Z" }, + { url = "https://files.pythonhosted.org/packages/59/fe/0c1fc5bd2d29c7db2ab372330063ad555fb83e08422829c785f5ec2176ca/pandas-3.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:06aff2ad6f0b94a17822cf8b83bbb563b090ed82ff4fe7712db2ce57cd50d9b8", size = 11924584, upload-time = "2026-02-17T22:19:11.562Z" }, + { url = "https://files.pythonhosted.org/packages/d6/7d/216a1588b65a7aa5f4535570418a599d943c85afb1d95b0876fc00aa1468/pandas-3.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:9fea306c783e28884c29057a1d9baa11a349bbf99538ec1da44c8476563d1b25", size = 9742769, upload-time = "2026-02-17T22:19:13.926Z" }, + { url = "https://files.pythonhosted.org/packages/c4/cb/810a22a6af9a4e97c8ab1c946b47f3489c5bca5adc483ce0ffc84c9cc768/pandas-3.0.1-cp313-cp313-win_arm64.whl", hash = "sha256:a8d37a43c52917427e897cb2e429f67a449327394396a81034a4449b99afda59", size = 9043855, upload-time = "2026-02-17T22:19:16.09Z" }, + { url = "https://files.pythonhosted.org/packages/92/fa/423c89086cca1f039cf1253c3ff5b90f157b5b3757314aa635f6bf3e30aa/pandas-3.0.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d54855f04f8246ed7b6fc96b05d4871591143c46c0b6f4af874764ed0d2d6f06", size = 10752673, upload-time = "2026-02-17T22:19:18.304Z" }, + { url = "https://files.pythonhosted.org/packages/22/23/b5a08ec1f40020397f0faba72f1e2c11f7596a6169c7b3e800abff0e433f/pandas-3.0.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e1b677accee34a09e0dc2ce5624e4a58a1870ffe56fc021e9caf7f23cd7668f", size = 10404967, upload-time = "2026-02-17T22:19:20.726Z" }, + { url = "https://files.pythonhosted.org/packages/5c/81/94841f1bb4afdc2b52a99daa895ac2c61600bb72e26525ecc9543d453ebc/pandas-3.0.1-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a9cabbdcd03f1b6cd254d6dda8ae09b0252524be1592594c00b7895916cb1324", size = 10320575, upload-time = "2026-02-17T22:19:24.919Z" }, + { url = "https://files.pythonhosted.org/packages/0a/8b/2ae37d66a5342a83adadfd0cb0b4bf9c3c7925424dd5f40d15d6cfaa35ee/pandas-3.0.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ae2ab1f166668b41e770650101e7090824fd34d17915dd9cd479f5c5e0065e9", size = 10710921, upload-time = "2026-02-17T22:19:27.181Z" }, + { url = "https://files.pythonhosted.org/packages/a2/61/772b2e2757855e232b7ccf7cb8079a5711becb3a97f291c953def15a833f/pandas-3.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6bf0603c2e30e2cafac32807b06435f28741135cb8697eae8b28c7d492fc7d76", size = 11334191, upload-time = "2026-02-17T22:19:29.411Z" }, + { url = "https://files.pythonhosted.org/packages/1b/08/b16c6df3ef555d8495d1d265a7963b65be166785d28f06a350913a4fac78/pandas-3.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6c426422973973cae1f4a23e51d4ae85974f44871b24844e4f7de752dd877098", size = 11782256, upload-time = "2026-02-17T22:19:32.34Z" }, + { url = "https://files.pythonhosted.org/packages/55/80/178af0594890dee17e239fca96d3d8670ba0f5ff59b7d0439850924a9c09/pandas-3.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b03f91ae8c10a85c1613102c7bef5229b5379f343030a3ccefeca8a33414cf35", size = 10485047, upload-time = "2026-02-17T22:19:34.605Z" }, + { url = "https://files.pythonhosted.org/packages/bb/8b/4bb774a998b97e6c2fd62a9e6cfdaae133b636fd1c468f92afb4ae9a447a/pandas-3.0.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:99d0f92ed92d3083d140bf6b97774f9f13863924cf3f52a70711f4e7588f9d0a", size = 10322465, upload-time = "2026-02-17T22:19:36.803Z" }, + { url = "https://files.pythonhosted.org/packages/72/3a/5b39b51c64159f470f1ca3b1c2a87da290657ca022f7cd11442606f607d1/pandas-3.0.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3b66857e983208654294bb6477b8a63dee26b37bdd0eb34d010556e91261784f", size = 9910632, upload-time = "2026-02-17T22:19:39.001Z" }, + { url = "https://files.pythonhosted.org/packages/4e/f7/b449ffb3f68c11da12fc06fbf6d2fa3a41c41e17d0284d23a79e1c13a7e4/pandas-3.0.1-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56cf59638bf24dc9bdf2154c81e248b3289f9a09a6d04e63608c159022352749", size = 10440535, upload-time = "2026-02-17T22:19:41.157Z" }, + { url = "https://files.pythonhosted.org/packages/55/77/6ea82043db22cb0f2bbfe7198da3544000ddaadb12d26be36e19b03a2dc5/pandas-3.0.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c1a9f55e0f46951874b863d1f3906dcb57df2d9be5c5847ba4dfb55b2c815249", size = 10893940, upload-time = "2026-02-17T22:19:43.493Z" }, + { url = "https://files.pythonhosted.org/packages/03/30/f1b502a72468c89412c1b882a08f6eed8a4ee9dc033f35f65d0663df6081/pandas-3.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1849f0bba9c8a2fb0f691d492b834cc8dadf617e29015c66e989448d58d011ee", size = 11442711, upload-time = "2026-02-17T22:19:46.074Z" }, + { url = "https://files.pythonhosted.org/packages/0d/f0/ebb6ddd8fc049e98cabac5c2924d14d1dda26a20adb70d41ea2e428d3ec4/pandas-3.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c3d288439e11b5325b02ae6e9cc83e6805a62c40c5a6220bea9beb899c073b1c", size = 11963918, upload-time = "2026-02-17T22:19:48.838Z" }, + { url = "https://files.pythonhosted.org/packages/09/f8/8ce132104074f977f907442790eaae24e27bce3b3b454e82faa3237ff098/pandas-3.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:93325b0fe372d192965f4cca88d97667f49557398bbf94abdda3bf1b591dbe66", size = 9862099, upload-time = "2026-02-17T22:19:51.081Z" }, + { url = "https://files.pythonhosted.org/packages/e6/b7/6af9aac41ef2456b768ef0ae60acf8abcebb450a52043d030a65b4b7c9bd/pandas-3.0.1-cp314-cp314-win_arm64.whl", hash = "sha256:97ca08674e3287c7148f4858b01136f8bdfe7202ad25ad04fec602dd1d29d132", size = 9185333, upload-time = "2026-02-17T22:19:53.266Z" }, + { url = "https://files.pythonhosted.org/packages/66/fc/848bb6710bc6061cb0c5badd65b92ff75c81302e0e31e496d00029fe4953/pandas-3.0.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:58eeb1b2e0fb322befcf2bbc9ba0af41e616abadb3d3414a6bc7167f6cbfce32", size = 10772664, upload-time = "2026-02-17T22:19:55.806Z" }, + { url = "https://files.pythonhosted.org/packages/69/5c/866a9bbd0f79263b4b0db6ec1a341be13a1473323f05c122388e0f15b21d/pandas-3.0.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cd9af1276b5ca9e298bd79a26bda32fa9cc87ed095b2a9a60978d2ca058eaf87", size = 10421286, upload-time = "2026-02-17T22:19:58.091Z" }, + { url = "https://files.pythonhosted.org/packages/51/a4/2058fb84fb1cfbfb2d4a6d485e1940bb4ad5716e539d779852494479c580/pandas-3.0.1-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94f87a04984d6b63788327cd9f79dda62b7f9043909d2440ceccf709249ca988", size = 10342050, upload-time = "2026-02-17T22:20:01.376Z" }, + { url = "https://files.pythonhosted.org/packages/22/1b/674e89996cc4be74db3c4eb09240c4bb549865c9c3f5d9b086ff8fcfbf00/pandas-3.0.1-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85fe4c4df62e1e20f9db6ebfb88c844b092c22cd5324bdcf94bfa2fc1b391221", size = 10740055, upload-time = "2026-02-17T22:20:04.328Z" }, + { url = "https://files.pythonhosted.org/packages/d0/f8/e954b750764298c22fa4614376531fe63c521ef517e7059a51f062b87dca/pandas-3.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:331ca75a2f8672c365ae25c0b29e46f5ac0c6551fdace8eec4cd65e4fac271ff", size = 11357632, upload-time = "2026-02-17T22:20:06.647Z" }, + { url = "https://files.pythonhosted.org/packages/6d/02/c6e04b694ffd68568297abd03588b6d30295265176a5c01b7459d3bc35a3/pandas-3.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:15860b1fdb1973fffade772fdb931ccf9b2f400a3f5665aef94a00445d7d8dd5", size = 11810974, upload-time = "2026-02-17T22:20:08.946Z" }, + { url = "https://files.pythonhosted.org/packages/89/41/d7dfb63d2407f12055215070c42fc6ac41b66e90a2946cdc5e759058398b/pandas-3.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:44f1364411d5670efa692b146c748f4ed013df91ee91e9bec5677fb1fd58b937", size = 10884622, upload-time = "2026-02-17T22:20:11.711Z" }, + { url = "https://files.pythonhosted.org/packages/68/b0/34937815889fa982613775e4b97fddd13250f11012d769949c5465af2150/pandas-3.0.1-cp314-cp314t-win_arm64.whl", hash = "sha256:108dd1790337a494aa80e38def654ca3f0968cf4f362c85f44c15e471667102d", size = 9452085, upload-time = "2026-02-17T22:20:14.331Z" }, ] [[package]] @@ -3581,7 +3613,7 @@ resolution-markers = [ ] dependencies = [ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, - { name = "numpy", version = "2.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "types-pytz", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/39/d9/0682716a9ba539b78748f026c523ae5f280fc478381f7f1c6c037d0f0fc3/pandas_stubs-2.2.2.240909.tar.gz", hash = "sha256:3c0951a2c3e45e3475aed9d80b7147ae82f176b9e42e9fb321cfdebf3d411b3d", size = 103599, upload-time = "2024-09-09T20:55:19.76Z" } @@ -3621,7 +3653,7 @@ name = "pexpect" version = "4.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "ptyprocess", marker = "(python_full_version < '3.11' and sys_platform == 'emscripten') or (python_full_version < '3.11' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" }, + { name = "ptyprocess" }, ] sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } wheels = [ @@ -3873,7 +3905,7 @@ wheels = [ [[package]] name = "platformdirs" -version = "4.7.0" +version = "4.9.2" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.14' and sys_platform == 'win32'", @@ -3890,9 +3922,9 @@ resolution-markers = [ "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version == '3.10.*'", ] -sdist = { url = "https://files.pythonhosted.org/packages/71/25/ccd8e88fcd16a4eb6343a8b4b9635e6f3928a7ebcd82822a14d20e3ca29f/platformdirs-4.7.0.tar.gz", hash = "sha256:fd1a5f8599c85d49b9ac7d6e450bc2f1aaf4a23f1fe86d09952fe20ad365cf36", size = 23118, upload-time = "2026-02-12T22:21:53.764Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/04/fea538adf7dbbd6d186f551d595961e564a3b6715bdf276b477460858672/platformdirs-4.9.2.tar.gz", hash = "sha256:9a33809944b9db043ad67ca0db94b14bf452cc6aeaac46a88ea55b26e2e9d291", size = 28394, upload-time = "2026-02-16T03:56:10.574Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/e3/1eddccb2c39ecfbe09b3add42a04abcc3fa5b468aa4224998ffb8a7e9c8f/platformdirs-4.7.0-py3-none-any.whl", hash = "sha256:1ed8db354e344c5bb6039cd727f096af975194b508e37177719d562b2b540ee6", size = 18983, upload-time = "2026-02-12T22:21:52.237Z" }, + { url = "https://files.pythonhosted.org/packages/48/31/05e764397056194206169869b50cf2fee4dbbbc71b344705b9c0d878d4d8/platformdirs-4.9.2-py3-none-any.whl", hash = "sha256:9170634f126f8efdae22fb58ae8a0eaa86f38365bc57897a6c4f781d1f5875bd", size = 21168, upload-time = "2026-02-16T03:56:08.891Z" }, ] [[package]] @@ -3927,7 +3959,7 @@ wheels = [ [[package]] name = "posthog" -version = "7.8.6" +version = "7.9.3" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.14' and sys_platform == 'win32'", @@ -3952,33 +3984,33 @@ dependencies = [ { name = "six", marker = "python_full_version >= '3.10'" }, { name = "typing-extensions", marker = "python_full_version >= '3.10'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/21/c9/a7c67c039f23f16a0b87d17561ba2a1c863b01f054a226c92437c539a7b6/posthog-7.8.6.tar.gz", hash = "sha256:6f67e18b5f19bf20d7ef2e1a80fa1ad879a5cd309ca13cfb300f45a8105968c4", size = 169304, upload-time = "2026-02-11T13:59:42.558Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/06/bcffcd262c861695fbaa74490b872e37d6fc41d3dcc1a43207d20525522f/posthog-7.9.3.tar.gz", hash = "sha256:55f7580265d290936ac4c112a4e2031a41743be4f90d4183ac9f85b721ff13ae", size = 172336, upload-time = "2026-02-18T22:20:24.085Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/56/c7/41664398a838f52ddfc89141e4c38b88eaa01b9e9a269c5ac184bd8586c6/posthog-7.8.6-py3-none-any.whl", hash = "sha256:21809f73e8e8f09d2bc273b09582f1a9f997b66f51fc626ef5bd3c5bdffd8bcd", size = 194801, upload-time = "2026-02-11T13:59:41.26Z" }, + { url = "https://files.pythonhosted.org/packages/11/7e/0e06a96823fa7c11ce73920e6ff77e82445db62ac4eae0b6f211edb4c4c2/posthog-7.9.3-py3-none-any.whl", hash = "sha256:2ddcacdef6c4afb124ebfcf27d7be58388943a7e24f8d4a51a52732c9b90bad6", size = 197819, upload-time = "2026-02-18T22:20:22.015Z" }, ] [[package]] name = "prek" -version = "0.3.2" +version = "0.3.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d3/f5/ee52def928dd1355c20bcfcf765e1e61434635c33f3075e848e7b83a157b/prek-0.3.2.tar.gz", hash = "sha256:dce0074ff1a21290748ca567b4bda7553ee305a8c7b14d737e6c58364a499364", size = 334229, upload-time = "2026-02-06T13:49:47.539Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bf/f1/7613dc8347a33e40fc5b79eec6bc7d458d8bbc339782333d8433b665f86f/prek-0.3.3.tar.gz", hash = "sha256:117bd46ebeb39def24298ce021ccc73edcf697b81856fcff36d762dd56093f6f", size = 343697, upload-time = "2026-02-15T13:33:28.723Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/69/70a5fc881290a63910494df2677c0fb241d27cfaa435bbcd0de5cd2e2443/prek-0.3.2-py3-none-linux_armv6l.whl", hash = "sha256:4f352f9c3fc98aeed4c8b2ec4dbf16fc386e45eea163c44d67e5571489bd8e6f", size = 4614960, upload-time = "2026-02-06T13:50:05.818Z" }, - { url = "https://files.pythonhosted.org/packages/c0/15/a82d5d32a2207ccae5d86ea9e44f2b93531ed000faf83a253e8d1108e026/prek-0.3.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:4a000cfbc3a6ec7d424f8be3c3e69ccd595448197f92daac8652382d0acc2593", size = 4622889, upload-time = "2026-02-06T13:49:53.662Z" }, - { url = "https://files.pythonhosted.org/packages/89/75/ea833b58a12741397017baef9b66a6e443bfa8286ecbd645d14111446280/prek-0.3.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5436bdc2702cbd7bcf9e355564ae66f8131211e65fefae54665a94a07c3d450a", size = 4239653, upload-time = "2026-02-06T13:50:02.88Z" }, - { url = "https://files.pythonhosted.org/packages/10/b4/d9c3885987afac6e20df4cb7db14e3b0d5a08a77ae4916488254ebac4d0b/prek-0.3.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:0161b5f584f9e7f416d6cf40a17b98f17953050ff8d8350ec60f20fe966b86b6", size = 4595101, upload-time = "2026-02-06T13:49:49.813Z" }, - { url = "https://files.pythonhosted.org/packages/21/a6/1a06473ed83dbc898de22838abdb13954e2583ce229f857f61828384634c/prek-0.3.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4e641e8533bca38797eebb49aa89ed0e8db0e61225943b27008c257e3af4d631", size = 4521978, upload-time = "2026-02-06T13:49:41.266Z" }, - { url = "https://files.pythonhosted.org/packages/0c/5e/c38390d5612e6d86b32151c1d2fdab74a57913473193591f0eb00c894c21/prek-0.3.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfca1810d49d3f9ef37599c958c4e716bc19a1d78a7e88cbdcb332e0b008994f", size = 4829108, upload-time = "2026-02-06T13:49:44.598Z" }, - { url = "https://files.pythonhosted.org/packages/80/a6/cecce2ab623747ff65ed990bb0d95fa38449ee19b348234862acf9392fff/prek-0.3.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5d69d754299a95a85dc20196f633232f306bee7e7c8cba61791f49ce70404ec", size = 5357520, upload-time = "2026-02-06T13:49:48.512Z" }, - { url = "https://files.pythonhosted.org/packages/a5/18/d6bcb29501514023c76d55d5cd03bdbc037737c8de8b6bc41cdebfb1682c/prek-0.3.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:539dcb90ad9b20837968539855df6a29493b328a1ae87641560768eed4f313b0", size = 4852635, upload-time = "2026-02-06T13:49:58.347Z" }, - { url = "https://files.pythonhosted.org/packages/1b/0a/ae46f34ba27ba87aea5c9ad4ac9cd3e07e014fd5079ae079c84198f62118/prek-0.3.2-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:1998db3d0cbe243984736c82232be51318f9192e2433919a6b1c5790f600b5fd", size = 4599484, upload-time = "2026-02-06T13:49:43.296Z" }, - { url = "https://files.pythonhosted.org/packages/1a/a9/73bfb5b3f7c3583f9b0d431924873928705cdef6abb3d0461c37254a681b/prek-0.3.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:07ab237a5415a3e8c0db54de9d63899bcd947624bdd8820d26f12e65f8d19eb7", size = 4657694, upload-time = "2026-02-06T13:50:01.074Z" }, - { url = "https://files.pythonhosted.org/packages/a7/bc/0994bc176e1a80110fad3babce2c98b0ac4007630774c9e18fc200a34781/prek-0.3.2-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:0ced19701d69c14a08125f14a5dd03945982edf59e793c73a95caf4697a7ac30", size = 4509337, upload-time = "2026-02-06T13:49:54.891Z" }, - { url = "https://files.pythonhosted.org/packages/f9/13/e73f85f65ba8f626468e5d1694ab3763111513da08e0074517f40238c061/prek-0.3.2-py3-none-musllinux_1_1_i686.whl", hash = "sha256:ffb28189f976fa111e770ee94e4f298add307714568fb7d610c8a7095cb1ce59", size = 4697350, upload-time = "2026-02-06T13:50:04.526Z" }, - { url = "https://files.pythonhosted.org/packages/14/47/98c46dcd580305b9960252a4eb966f1a7b1035c55c363f378d85662ba400/prek-0.3.2-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:f63134b3eea14421789a7335d86f99aee277cb520427196f2923b9260c60e5c5", size = 4955860, upload-time = "2026-02-06T13:49:56.581Z" }, - { url = "https://files.pythonhosted.org/packages/73/42/1bb4bba3ff47897df11e9dfd774027cdfa135482c961a54e079af0faf45a/prek-0.3.2-py3-none-win32.whl", hash = "sha256:58c806bd1344becd480ef5a5ba348846cc000af0e1fbe854fef91181a2e06461", size = 4267619, upload-time = "2026-02-06T13:49:39.503Z" }, - { url = "https://files.pythonhosted.org/packages/97/11/6665f47a7c350d83de17403c90bbf7a762ef50876ece456a86f64f46fbfb/prek-0.3.2-py3-none-win_amd64.whl", hash = "sha256:70114b48e9eb8048b2c11b4c7715ce618529c6af71acc84dd8877871a2ef71a6", size = 4624324, upload-time = "2026-02-06T13:49:45.922Z" }, - { url = "https://files.pythonhosted.org/packages/22/e7/740997ca82574d03426f897fd88afe3fc8a7306b8c7ea342a8bc1c538488/prek-0.3.2-py3-none-win_arm64.whl", hash = "sha256:9144d176d0daa2469a25c303ef6f6fa95a8df015eb275232f5cb53551ecefef0", size = 4336008, upload-time = "2026-02-06T13:49:52.27Z" }, + { url = "https://files.pythonhosted.org/packages/2d/8b/dce13d2a3065fd1e8ffce593a0e51c4a79c3cde9c9a15dc0acc8d9d1573d/prek-0.3.3-py3-none-linux_armv6l.whl", hash = "sha256:e8629cac4bdb131be8dc6e5a337f0f76073ad34a8305f3fe2bc1ab6201ede0a4", size = 4644636, upload-time = "2026-02-15T13:33:43.609Z" }, + { url = "https://files.pythonhosted.org/packages/01/30/06ab4dbe7ce02a8ce833e92deb1d9a8e85ae9d40e33d1959a2070b7494c6/prek-0.3.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:4b9e819b9e4118e1e785047b1c8bd9aec7e4d836ed034cb58b7db5bcaaf49437", size = 4651410, upload-time = "2026-02-15T13:33:34.277Z" }, + { url = "https://files.pythonhosted.org/packages/d4/fc/da3bc5cb38471e7192eda06b7a26b7c24ef83e82da2c1dbc145f2bf33640/prek-0.3.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:bf29db3b5657c083eb8444c25aadeeec5167dc492e9019e188f87932f01ea50a", size = 4273163, upload-time = "2026-02-15T13:33:42.106Z" }, + { url = "https://files.pythonhosted.org/packages/b4/74/47839395091e2937beced81a5dd2f8ea9c8239c853da8611aaf78ee21a8b/prek-0.3.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:ae09736149815b26e64a9d350ca05692bab32c2afdf2939114d3211aaad68a3e", size = 4631808, upload-time = "2026-02-15T13:33:20.076Z" }, + { url = "https://files.pythonhosted.org/packages/e2/89/3f5ef6f7c928c017cb63b029349d6bc03598ab7f6979d4a770ce02575f82/prek-0.3.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:856c2b55c51703c366bb4ce81c6a91102b70573a9fc8637db2ac61c66e4565f9", size = 4548959, upload-time = "2026-02-15T13:33:36.325Z" }, + { url = "https://files.pythonhosted.org/packages/b2/18/80002c4c4475f90ca025f27739a016927a0e5d905c60612fc95da1c56ab7/prek-0.3.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3acdf13a018f685beaff0a71d4b0d2ccbab4eaa1aced6d08fd471c1a654183eb", size = 4862256, upload-time = "2026-02-15T13:33:37.754Z" }, + { url = "https://files.pythonhosted.org/packages/c5/25/648bf084c2468fa7cfcdbbe9e59956bbb31b81f36e113bc9107d80af26a7/prek-0.3.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0f035667a8bd0a77b2bfa2b2e125da8cb1793949e9eeef0d8daab7f8ac8b57fe", size = 5404486, upload-time = "2026-02-15T13:33:39.239Z" }, + { url = "https://files.pythonhosted.org/packages/8b/43/261fb60a11712a327da345912bd8b338dc5a050199de800faafa278a6133/prek-0.3.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d09b2ad14332eede441d977de08eb57fb3f61226ed5fd2ceb7aadf5afcdb6794", size = 4887513, upload-time = "2026-02-15T13:33:40.702Z" }, + { url = "https://files.pythonhosted.org/packages/c7/2c/581e757ee57ec6046b32e0ee25660fc734bc2622c319f57119c49c0cab58/prek-0.3.3-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:c0c3ffac16e37a9daba43a7e8316778f5809b70254be138761a8b5b9ef0df28e", size = 4632336, upload-time = "2026-02-15T13:33:25.867Z" }, + { url = "https://files.pythonhosted.org/packages/d5/d8/aa276ce5d11b77882da4102ca0cb7161095831105043ae7979bbfdcc3dc4/prek-0.3.3-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a3dc7720b580c07c0386e17af2486a5b4bc2f6cc57034a288a614dcbc4abe555", size = 4679370, upload-time = "2026-02-15T13:33:22.247Z" }, + { url = "https://files.pythonhosted.org/packages/70/19/9d4fa7bde428e58d9f48a74290c08736d42aeb5690dcdccc7a713e34a449/prek-0.3.3-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:60e0fa15da5020a03df2ee40268145ec5b88267ec2141a205317ad4df8c992d6", size = 4540316, upload-time = "2026-02-15T13:33:24.088Z" }, + { url = "https://files.pythonhosted.org/packages/25/b5/973cce29257e0b47b16cc9b4c162772ea01dbb7c080791ea0c068e106e05/prek-0.3.3-py3-none-musllinux_1_1_i686.whl", hash = "sha256:553515da9586d9624dc42db32b744fdb91cf62b053753037a0cadb3c2d8d82a2", size = 4724566, upload-time = "2026-02-15T13:33:29.832Z" }, + { url = "https://files.pythonhosted.org/packages/d6/8b/ad8b2658895a8ed2b0bc630bf38686fe38b7ff2c619c58953a80e4de3048/prek-0.3.3-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:9512cf370e0d1496503463a4a65621480efb41b487841a9e9ff1661edf14b238", size = 4995072, upload-time = "2026-02-15T13:33:27.417Z" }, + { url = "https://files.pythonhosted.org/packages/fd/b7/0540c101c00882adb9d30319d22d8f879413598269ecc60235e41875efd4/prek-0.3.3-py3-none-win32.whl", hash = "sha256:b2b328c7c6dc14ccdc79785348589aa39850f47baff33d8f199f2dee80ff774c", size = 4293144, upload-time = "2026-02-15T13:33:46.013Z" }, + { url = "https://files.pythonhosted.org/packages/97/c7/e4f11da653093040efba2d835aa0995d78940aea30887287aeaebe34a545/prek-0.3.3-py3-none-win_amd64.whl", hash = "sha256:3d7d7acf7ca8db65ba0943c52326c898f84bab0b1c26a35c87e0d177f574ca5f", size = 4652761, upload-time = "2026-02-15T13:33:32.962Z" }, + { url = "https://files.pythonhosted.org/packages/11/e4/d99dec54c6a5fb2763488bff6078166383169a93f3af27d2edae88379a39/prek-0.3.3-py3-none-win_arm64.whl", hash = "sha256:8aa87ee7628cd74482c0dd6537a3def1f162b25cd642d78b1b35dd3e81817f60", size = 4367520, upload-time = "2026-02-15T13:33:31.664Z" }, ] [[package]] @@ -4084,7 +4116,7 @@ wheels = [ [[package]] name = "pyarrow" -version = "23.0.0" +version = "23.0.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.14' and sys_platform == 'win32'", @@ -4101,57 +4133,57 @@ resolution-markers = [ "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version == '3.10.*'", ] -sdist = { url = "https://files.pythonhosted.org/packages/01/33/ffd9c3eb087fa41dd79c3cf20c4c0ae3cdb877c4f8e1107a446006344924/pyarrow-23.0.0.tar.gz", hash = "sha256:180e3150e7edfcd182d3d9afba72f7cf19839a497cc76555a8dce998a8f67615", size = 1167185, upload-time = "2026-01-18T16:19:42.218Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ae/2f/23e042a5aa99bcb15e794e14030e8d065e00827e846e53a66faec73c7cd6/pyarrow-23.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:cbdc2bf5947aa4d462adcf8453cf04aee2f7932653cb67a27acd96e5e8528a67", size = 34281861, upload-time = "2026-01-18T16:13:34.332Z" }, - { url = "https://files.pythonhosted.org/packages/8b/65/1651933f504b335ec9cd8f99463718421eb08d883ed84f0abd2835a16cad/pyarrow-23.0.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:4d38c836930ce15cd31dce20114b21ba082da231c884bdc0a7b53e1477fe7f07", size = 35825067, upload-time = "2026-01-18T16:13:42.549Z" }, - { url = "https://files.pythonhosted.org/packages/84/ec/d6fceaec050c893f4e35c0556b77d4cc9973fcc24b0a358a5781b1234582/pyarrow-23.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:4222ff8f76919ecf6c716175a0e5fddb5599faeed4c56d9ea41a2c42be4998b2", size = 44458539, upload-time = "2026-01-18T16:13:52.975Z" }, - { url = "https://files.pythonhosted.org/packages/fd/d9/369f134d652b21db62fe3ec1c5c2357e695f79eb67394b8a93f3a2b2cffa/pyarrow-23.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:87f06159cbe38125852657716889296c83c37b4d09a5e58f3d10245fd1f69795", size = 47535889, upload-time = "2026-01-18T16:14:03.693Z" }, - { url = "https://files.pythonhosted.org/packages/a3/95/f37b6a252fdbf247a67a78fb3f61a529fe0600e304c4d07741763d3522b1/pyarrow-23.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1675c374570d8b91ea6d4edd4608fa55951acd44e0c31bd146e091b4005de24f", size = 48157777, upload-time = "2026-01-18T16:14:12.483Z" }, - { url = "https://files.pythonhosted.org/packages/ab/ab/fb94923108c9c6415dab677cf1f066d3307798eafc03f9a65ab4abc61056/pyarrow-23.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:247374428fde4f668f138b04031a7e7077ba5fa0b5b1722fdf89a017bf0b7ee0", size = 50580441, upload-time = "2026-01-18T16:14:20.187Z" }, - { url = "https://files.pythonhosted.org/packages/ae/78/897ba6337b517fc8e914891e1bd918da1c4eb8e936a553e95862e67b80f6/pyarrow-23.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:de53b1bd3b88a2ee93c9af412c903e57e738c083be4f6392288294513cd8b2c1", size = 27530028, upload-time = "2026-01-18T16:14:27.353Z" }, - { url = "https://files.pythonhosted.org/packages/aa/c0/57fe251102ca834fee0ef69a84ad33cc0ff9d5dfc50f50b466846356ecd7/pyarrow-23.0.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:5574d541923efcbfdf1294a2746ae3b8c2498a2dc6cd477882f6f4e7b1ac08d3", size = 34276762, upload-time = "2026-01-18T16:14:34.128Z" }, - { url = "https://files.pythonhosted.org/packages/f8/4e/24130286548a5bc250cbed0b6bbf289a2775378a6e0e6f086ae8c68fc098/pyarrow-23.0.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:2ef0075c2488932e9d3c2eb3482f9459c4be629aa673b725d5e3cf18f777f8e4", size = 35821420, upload-time = "2026-01-18T16:14:40.699Z" }, - { url = "https://files.pythonhosted.org/packages/ee/55/a869e8529d487aa2e842d6c8865eb1e2c9ec33ce2786eb91104d2c3e3f10/pyarrow-23.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:65666fc269669af1ef1c14478c52222a2aa5c907f28b68fb50a203c777e4f60c", size = 44457412, upload-time = "2026-01-18T16:14:49.051Z" }, - { url = "https://files.pythonhosted.org/packages/36/81/1de4f0edfa9a483bbdf0082a05790bd6a20ed2169ea12a65039753be3a01/pyarrow-23.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:4d85cb6177198f3812db4788e394b757223f60d9a9f5ad6634b3e32be1525803", size = 47534285, upload-time = "2026-01-18T16:14:56.748Z" }, - { url = "https://files.pythonhosted.org/packages/f2/04/464a052d673b5ece074518f27377861662449f3c1fdb39ce740d646fd098/pyarrow-23.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1a9ff6fa4141c24a03a1a434c63c8fa97ce70f8f36bccabc18ebba905ddf0f17", size = 48157913, upload-time = "2026-01-18T16:15:05.114Z" }, - { url = "https://files.pythonhosted.org/packages/f4/1b/32a4de9856ee6688c670ca2def588382e573cce45241a965af04c2f61687/pyarrow-23.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:84839d060a54ae734eb60a756aeacb62885244aaa282f3c968f5972ecc7b1ecc", size = 50582529, upload-time = "2026-01-18T16:15:12.846Z" }, - { url = "https://files.pythonhosted.org/packages/db/c7/d6581f03e9b9e44ea60b52d1750ee1a7678c484c06f939f45365a45f7eef/pyarrow-23.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:a149a647dbfe928ce8830a713612aa0b16e22c64feac9d1761529778e4d4eaa5", size = 27542646, upload-time = "2026-01-18T16:15:18.89Z" }, - { url = "https://files.pythonhosted.org/packages/3d/bd/c861d020831ee57609b73ea721a617985ece817684dc82415b0bc3e03ac3/pyarrow-23.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:5961a9f646c232697c24f54d3419e69b4261ba8a8b66b0ac54a1851faffcbab8", size = 34189116, upload-time = "2026-01-18T16:15:28.054Z" }, - { url = "https://files.pythonhosted.org/packages/8c/23/7725ad6cdcbaf6346221391e7b3eecd113684c805b0a95f32014e6fa0736/pyarrow-23.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:632b3e7c3d232f41d64e1a4a043fb82d44f8a349f339a1188c6a0dd9d2d47d8a", size = 35803831, upload-time = "2026-01-18T16:15:33.798Z" }, - { url = "https://files.pythonhosted.org/packages/57/06/684a421543455cdc2944d6a0c2cc3425b028a4c6b90e34b35580c4899743/pyarrow-23.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:76242c846db1411f1d6c2cc3823be6b86b40567ee24493344f8226ba34a81333", size = 44436452, upload-time = "2026-01-18T16:15:41.598Z" }, - { url = "https://files.pythonhosted.org/packages/c6/6f/8f9eb40c2328d66e8b097777ddcf38494115ff9f1b5bc9754ba46991191e/pyarrow-23.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b73519f8b52ae28127000986bf228fda781e81d3095cd2d3ece76eb5cf760e1b", size = 47557396, upload-time = "2026-01-18T16:15:51.252Z" }, - { url = "https://files.pythonhosted.org/packages/10/6e/f08075f1472e5159553501fde2cc7bc6700944bdabe49a03f8a035ee6ccd/pyarrow-23.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:068701f6823449b1b6469120f399a1239766b117d211c5d2519d4ed5861f75de", size = 48147129, upload-time = "2026-01-18T16:16:00.299Z" }, - { url = "https://files.pythonhosted.org/packages/7d/82/d5a680cd507deed62d141cc7f07f7944a6766fc51019f7f118e4d8ad0fb8/pyarrow-23.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1801ba947015d10e23bca9dd6ef5d0e9064a81569a89b6e9a63b59224fd060df", size = 50596642, upload-time = "2026-01-18T16:16:08.502Z" }, - { url = "https://files.pythonhosted.org/packages/a9/26/4f29c61b3dce9fa7780303b86895ec6a0917c9af927101daaaf118fbe462/pyarrow-23.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:52265266201ec25b6839bf6bd4ea918ca6d50f31d13e1cf200b4261cd11dc25c", size = 27660628, upload-time = "2026-01-18T16:16:15.28Z" }, - { url = "https://files.pythonhosted.org/packages/66/34/564db447d083ec7ff93e0a883a597d2f214e552823bfc178a2d0b1f2c257/pyarrow-23.0.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:ad96a597547af7827342ffb3c503c8316e5043bb09b47a84885ce39394c96e00", size = 34184630, upload-time = "2026-01-18T16:16:22.141Z" }, - { url = "https://files.pythonhosted.org/packages/aa/3a/3999daebcb5e6119690c92a621c4d78eef2ffba7a0a1b56386d2875fcd77/pyarrow-23.0.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:b9edf990df77c2901e79608f08c13fbde60202334a4fcadb15c1f57bf7afee43", size = 35796820, upload-time = "2026-01-18T16:16:29.441Z" }, - { url = "https://files.pythonhosted.org/packages/ec/ee/39195233056c6a8d0976d7d1ac1cd4fe21fb0ec534eca76bc23ef3f60e11/pyarrow-23.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:36d1b5bc6ddcaff0083ceec7e2561ed61a51f49cce8be079ee8ed406acb6fdef", size = 44438735, upload-time = "2026-01-18T16:16:38.79Z" }, - { url = "https://files.pythonhosted.org/packages/2c/41/6a7328ee493527e7afc0c88d105ecca69a3580e29f2faaeac29308369fd7/pyarrow-23.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:4292b889cd224f403304ddda8b63a36e60f92911f89927ec8d98021845ea21be", size = 47557263, upload-time = "2026-01-18T16:16:46.248Z" }, - { url = "https://files.pythonhosted.org/packages/c6/ee/34e95b21ee84db494eae60083ddb4383477b31fb1fd19fd866d794881696/pyarrow-23.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dfd9e133e60eaa847fd80530a1b89a052f09f695d0b9c34c235ea6b2e0924cf7", size = 48153529, upload-time = "2026-01-18T16:16:53.412Z" }, - { url = "https://files.pythonhosted.org/packages/52/88/8a8d83cea30f4563efa1b7bf51d241331ee5cd1b185a7e063f5634eca415/pyarrow-23.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:832141cc09fac6aab1cd3719951d23301396968de87080c57c9a7634e0ecd068", size = 50598851, upload-time = "2026-01-18T16:17:01.133Z" }, - { url = "https://files.pythonhosted.org/packages/c6/4c/2929c4be88723ba025e7b3453047dc67e491c9422965c141d24bab6b5962/pyarrow-23.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:7a7d067c9a88faca655c71bcc30ee2782038d59c802d57950826a07f60d83c4c", size = 27577747, upload-time = "2026-01-18T16:18:02.413Z" }, - { url = "https://files.pythonhosted.org/packages/64/52/564a61b0b82d72bd68ec3aef1adda1e3eba776f89134b9ebcb5af4b13cb6/pyarrow-23.0.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:ce9486e0535a843cf85d990e2ec5820a47918235183a5c7b8b97ed7e92c2d47d", size = 34446038, upload-time = "2026-01-18T16:17:07.861Z" }, - { url = "https://files.pythonhosted.org/packages/cc/c9/232d4f9855fd1de0067c8a7808a363230d223c83aeee75e0fe6eab851ba9/pyarrow-23.0.0-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:075c29aeaa685fd1182992a9ed2499c66f084ee54eea47da3eb76e125e06064c", size = 35921142, upload-time = "2026-01-18T16:17:15.401Z" }, - { url = "https://files.pythonhosted.org/packages/96/f2/60af606a3748367b906bb82d41f0032e059f075444445d47e32a7ff1df62/pyarrow-23.0.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:799965a5379589510d888be3094c2296efd186a17ca1cef5b77703d4d5121f53", size = 44490374, upload-time = "2026-01-18T16:17:23.93Z" }, - { url = "https://files.pythonhosted.org/packages/ff/2d/7731543050a678ea3a413955a2d5d80d2a642f270aa57a3cb7d5a86e3f46/pyarrow-23.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:ef7cac8fe6fccd8b9e7617bfac785b0371a7fe26af59463074e4882747145d40", size = 47527896, upload-time = "2026-01-18T16:17:33.393Z" }, - { url = "https://files.pythonhosted.org/packages/5a/90/f3342553b7ac9879413aed46500f1637296f3c8222107523a43a1c08b42a/pyarrow-23.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:15a414f710dc927132dd67c361f78c194447479555af57317066ee5116b90e9e", size = 48210401, upload-time = "2026-01-18T16:17:42.012Z" }, - { url = "https://files.pythonhosted.org/packages/f3/da/9862ade205ecc46c172b6ce5038a74b5151c7401e36255f15975a45878b2/pyarrow-23.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3e0d2e6915eca7d786be6a77bf227fbc06d825a75b5b5fe9bcbef121dec32685", size = 50579677, upload-time = "2026-01-18T16:17:50.241Z" }, - { url = "https://files.pythonhosted.org/packages/c2/4c/f11f371f5d4740a5dafc2e11c76bcf42d03dfdb2d68696da97de420b6963/pyarrow-23.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:4b317ea6e800b5704e5e5929acb6e2dc13e9276b708ea97a39eb8b345aa2658b", size = 27631889, upload-time = "2026-01-18T16:17:56.55Z" }, - { url = "https://files.pythonhosted.org/packages/97/bb/15aec78bcf43a0c004067bd33eb5352836a29a49db8581fc56f2b6ca88b7/pyarrow-23.0.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:20b187ed9550d233a872074159f765f52f9d92973191cd4b93f293a19efbe377", size = 34213265, upload-time = "2026-01-18T16:18:07.904Z" }, - { url = "https://files.pythonhosted.org/packages/f6/6c/deb2c594bbba41c37c5d9aa82f510376998352aa69dfcb886cb4b18ad80f/pyarrow-23.0.0-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:18ec84e839b493c3886b9b5e06861962ab4adfaeb79b81c76afbd8d84c7d5fda", size = 35819211, upload-time = "2026-01-18T16:18:13.94Z" }, - { url = "https://files.pythonhosted.org/packages/e0/e5/ee82af693cb7b5b2b74f6524cdfede0e6ace779d7720ebca24d68b57c36b/pyarrow-23.0.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:e438dd3f33894e34fd02b26bd12a32d30d006f5852315f611aa4add6c7fab4bc", size = 44502313, upload-time = "2026-01-18T16:18:20.367Z" }, - { url = "https://files.pythonhosted.org/packages/9c/86/95c61ad82236495f3c31987e85135926ba3ec7f3819296b70a68d8066b49/pyarrow-23.0.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:a244279f240c81f135631be91146d7fa0e9e840e1dfed2aba8483eba25cd98e6", size = 47585886, upload-time = "2026-01-18T16:18:27.544Z" }, - { url = "https://files.pythonhosted.org/packages/bb/6e/a72d901f305201802f016d015de1e05def7706fff68a1dedefef5dc7eff7/pyarrow-23.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c4692e83e42438dba512a570c6eaa42be2f8b6c0f492aea27dec54bdc495103a", size = 48207055, upload-time = "2026-01-18T16:18:35.425Z" }, - { url = "https://files.pythonhosted.org/packages/f9/e5/5de029c537630ca18828db45c30e2a78da03675a70ac6c3528203c416fe3/pyarrow-23.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ae7f30f898dfe44ea69654a35c93e8da4cef6606dc4c72394068fd95f8e9f54a", size = 50619812, upload-time = "2026-01-18T16:18:43.553Z" }, - { url = "https://files.pythonhosted.org/packages/59/8d/2af846cd2412e67a087f5bda4a8e23dfd4ebd570f777db2e8686615dafc1/pyarrow-23.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:5b86bb649e4112fb0614294b7d0a175c7513738876b89655605ebb87c804f861", size = 28263851, upload-time = "2026-01-18T16:19:38.567Z" }, - { url = "https://files.pythonhosted.org/packages/7b/7f/caab863e587041156f6786c52e64151b7386742c8c27140f637176e9230e/pyarrow-23.0.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:ebc017d765d71d80a3f8584ca0566b53e40464586585ac64176115baa0ada7d3", size = 34463240, upload-time = "2026-01-18T16:18:49.755Z" }, - { url = "https://files.pythonhosted.org/packages/c9/fa/3a5b8c86c958e83622b40865e11af0857c48ec763c11d472c87cd518283d/pyarrow-23.0.0-cp314-cp314t-macosx_12_0_x86_64.whl", hash = "sha256:0800cc58a6d17d159df823f87ad66cefebf105b982493d4bad03ee7fab84b993", size = 35935712, upload-time = "2026-01-18T16:18:55.626Z" }, - { url = "https://files.pythonhosted.org/packages/c5/08/17a62078fc1a53decb34a9aa79cf9009efc74d63d2422e5ade9fed2f99e3/pyarrow-23.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:3a7c68c722da9bb5b0f8c10e3eae71d9825a4b429b40b32709df5d1fa55beb3d", size = 44503523, upload-time = "2026-01-18T16:19:03.958Z" }, - { url = "https://files.pythonhosted.org/packages/cc/70/84d45c74341e798aae0323d33b7c39194e23b1abc439ceaf60a68a7a969a/pyarrow-23.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:bd5556c24622df90551063ea41f559b714aa63ca953db884cfb958559087a14e", size = 47542490, upload-time = "2026-01-18T16:19:11.208Z" }, - { url = "https://files.pythonhosted.org/packages/61/d9/d1274b0e6f19e235de17441e53224f4716574b2ca837022d55702f24d71d/pyarrow-23.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:54810f6e6afc4ffee7c2e0051b61722fbea9a4961b46192dcfae8ea12fa09059", size = 48233605, upload-time = "2026-01-18T16:19:19.544Z" }, - { url = "https://files.pythonhosted.org/packages/39/07/e4e2d568cb57543d84482f61e510732820cddb0f47c4bb7df629abfed852/pyarrow-23.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:14de7d48052cf4b0ed174533eafa3cfe0711b8076ad70bede32cf59f744f0d7c", size = 50603979, upload-time = "2026-01-18T16:19:26.717Z" }, - { url = "https://files.pythonhosted.org/packages/72/9c/47693463894b610f8439b2e970b82ef81e9599c757bf2049365e40ff963c/pyarrow-23.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:427deac1f535830a744a4f04a6ac183a64fcac4341b3f618e693c41b7b98d2b0", size = 28338905, upload-time = "2026-01-18T16:19:32.93Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/88/22/134986a4cc224d593c1afde5494d18ff629393d74cc2eddb176669f234a4/pyarrow-23.0.1.tar.gz", hash = "sha256:b8c5873e33440b2bc2f4a79d2b47017a89c5a24116c055625e6f2ee50523f019", size = 1167336, upload-time = "2026-02-16T10:14:12.39Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/a8/24e5dc6855f50a62936ceb004e6e9645e4219a8065f304145d7fb8a79d5d/pyarrow-23.0.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:3fab8f82571844eb3c460f90a75583801d14ca0cc32b1acc8c361650e006fd56", size = 34307390, upload-time = "2026-02-16T10:08:08.654Z" }, + { url = "https://files.pythonhosted.org/packages/bc/8e/4be5617b4aaae0287f621ad31c6036e5f63118cfca0dc57d42121ff49b51/pyarrow-23.0.1-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:3f91c038b95f71ddfc865f11d5876c42f343b4495535bd262c7b321b0b94507c", size = 35853761, upload-time = "2026-02-16T10:08:17.811Z" }, + { url = "https://files.pythonhosted.org/packages/2e/08/3e56a18819462210432ae37d10f5c8eed3828be1d6c751b6e6a2e93c286a/pyarrow-23.0.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:d0744403adabef53c985a7f8a082b502a368510c40d184df349a0a8754533258", size = 44493116, upload-time = "2026-02-16T10:08:25.792Z" }, + { url = "https://files.pythonhosted.org/packages/f8/82/c40b68001dbec8a3faa4c08cd8c200798ac732d2854537c5449dc859f55a/pyarrow-23.0.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:c33b5bf406284fd0bba436ed6f6c3ebe8e311722b441d89397c54f871c6863a2", size = 47564532, upload-time = "2026-02-16T10:08:34.27Z" }, + { url = "https://files.pythonhosted.org/packages/20/bc/73f611989116b6f53347581b02177f9f620efdf3cd3f405d0e83cdf53a83/pyarrow-23.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ddf743e82f69dcd6dbbcb63628895d7161e04e56794ef80550ac6f3315eeb1d5", size = 48183685, upload-time = "2026-02-16T10:08:42.889Z" }, + { url = "https://files.pythonhosted.org/packages/b0/cc/6c6b3ecdae2a8c3aced99956187e8302fc954cc2cca2a37cf2111dad16ce/pyarrow-23.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e052a211c5ac9848ae15d5ec875ed0943c0221e2fcfe69eee80b604b4e703222", size = 50605582, upload-time = "2026-02-16T10:08:51.641Z" }, + { url = "https://files.pythonhosted.org/packages/8d/94/d359e708672878d7638a04a0448edf7c707f9e5606cee11e15aaa5c7535a/pyarrow-23.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:5abde149bb3ce524782d838eb67ac095cd3fd6090eba051130589793f1a7f76d", size = 27521148, upload-time = "2026-02-16T10:08:58.077Z" }, + { url = "https://files.pythonhosted.org/packages/b0/41/8e6b6ef7e225d4ceead8459427a52afdc23379768f54dd3566014d7618c1/pyarrow-23.0.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:6f0147ee9e0386f519c952cc670eb4a8b05caa594eeffe01af0e25f699e4e9bb", size = 34302230, upload-time = "2026-02-16T10:09:03.859Z" }, + { url = "https://files.pythonhosted.org/packages/bf/4a/1472c00392f521fea03ae93408bf445cc7bfa1ab81683faf9bc188e36629/pyarrow-23.0.1-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:0ae6e17c828455b6265d590100c295193f93cc5675eb0af59e49dbd00d2de350", size = 35850050, upload-time = "2026-02-16T10:09:11.877Z" }, + { url = "https://files.pythonhosted.org/packages/0c/b2/bd1f2f05ded56af7f54d702c8364c9c43cd6abb91b0e9933f3d77b4f4132/pyarrow-23.0.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:fed7020203e9ef273360b9e45be52a2a47d3103caf156a30ace5247ffb51bdbd", size = 44491918, upload-time = "2026-02-16T10:09:18.144Z" }, + { url = "https://files.pythonhosted.org/packages/0b/62/96459ef5b67957eac38a90f541d1c28833d1b367f014a482cb63f3b7cd2d/pyarrow-23.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:26d50dee49d741ac0e82185033488d28d35be4d763ae6f321f97d1140eb7a0e9", size = 47562811, upload-time = "2026-02-16T10:09:25.792Z" }, + { url = "https://files.pythonhosted.org/packages/7d/94/1170e235add1f5f45a954e26cd0e906e7e74e23392dcb560de471f7366ec/pyarrow-23.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3c30143b17161310f151f4a2bcfe41b5ff744238c1039338779424e38579d701", size = 48183766, upload-time = "2026-02-16T10:09:34.645Z" }, + { url = "https://files.pythonhosted.org/packages/0e/2d/39a42af4570377b99774cdb47f63ee6c7da7616bd55b3d5001aa18edfe4f/pyarrow-23.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:db2190fa79c80a23fdd29fef4b8992893f024ae7c17d2f5f4db7171fa30c2c78", size = 50607669, upload-time = "2026-02-16T10:09:44.153Z" }, + { url = "https://files.pythonhosted.org/packages/00/ca/db94101c187f3df742133ac837e93b1f269ebdac49427f8310ee40b6a58f/pyarrow-23.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:f00f993a8179e0e1c9713bcc0baf6d6c01326a406a9c23495ec1ba9c9ebf2919", size = 27527698, upload-time = "2026-02-16T10:09:50.263Z" }, + { url = "https://files.pythonhosted.org/packages/9a/4b/4166bb5abbfe6f750fc60ad337c43ecf61340fa52ab386da6e8dbf9e63c4/pyarrow-23.0.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:f4b0dbfa124c0bb161f8b5ebb40f1a680b70279aa0c9901d44a2b5a20806039f", size = 34214575, upload-time = "2026-02-16T10:09:56.225Z" }, + { url = "https://files.pythonhosted.org/packages/e1/da/3f941e3734ac8088ea588b53e860baeddac8323ea40ce22e3d0baa865cc9/pyarrow-23.0.1-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:7707d2b6673f7de054e2e83d59f9e805939038eebe1763fe811ee8fa5c0cd1a7", size = 35832540, upload-time = "2026-02-16T10:10:03.428Z" }, + { url = "https://files.pythonhosted.org/packages/88/7c/3d841c366620e906d54430817531b877ba646310296df42ef697308c2705/pyarrow-23.0.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:86ff03fb9f1a320266e0de855dee4b17da6794c595d207f89bba40d16b5c78b9", size = 44470940, upload-time = "2026-02-16T10:10:10.704Z" }, + { url = "https://files.pythonhosted.org/packages/2c/a5/da83046273d990f256cb79796a190bbf7ec999269705ddc609403f8c6b06/pyarrow-23.0.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:813d99f31275919c383aab17f0f455a04f5a429c261cc411b1e9a8f5e4aaaa05", size = 47586063, upload-time = "2026-02-16T10:10:17.95Z" }, + { url = "https://files.pythonhosted.org/packages/5b/3c/b7d2ebcff47a514f47f9da1e74b7949138c58cfeb108cdd4ee62f43f0cf3/pyarrow-23.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bf5842f960cddd2ef757d486041d57c96483efc295a8c4a0e20e704cbbf39c67", size = 48173045, upload-time = "2026-02-16T10:10:25.363Z" }, + { url = "https://files.pythonhosted.org/packages/43/b2/b40961262213beaba6acfc88698eb773dfce32ecdf34d19291db94c2bd73/pyarrow-23.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:564baf97c858ecc03ec01a41062e8f4698abc3e6e2acd79c01c2e97880a19730", size = 50621741, upload-time = "2026-02-16T10:10:33.477Z" }, + { url = "https://files.pythonhosted.org/packages/f6/70/1fdda42d65b28b078e93d75d371b2185a61da89dda4def8ba6ba41ebdeb4/pyarrow-23.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:07deae7783782ac7250989a7b2ecde9b3c343a643f82e8a4df03d93b633006f0", size = 27620678, upload-time = "2026-02-16T10:10:39.31Z" }, + { url = "https://files.pythonhosted.org/packages/47/10/2cbe4c6f0fb83d2de37249567373d64327a5e4d8db72f486db42875b08f6/pyarrow-23.0.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:6b8fda694640b00e8af3c824f99f789e836720aa8c9379fb435d4c4953a756b8", size = 34210066, upload-time = "2026-02-16T10:10:45.487Z" }, + { url = "https://files.pythonhosted.org/packages/cb/4f/679fa7e84dadbaca7a65f7cdba8d6c83febbd93ca12fa4adf40ba3b6362b/pyarrow-23.0.1-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:8ff51b1addc469b9444b7c6f3548e19dc931b172ab234e995a60aea9f6e6025f", size = 35825526, upload-time = "2026-02-16T10:10:52.266Z" }, + { url = "https://files.pythonhosted.org/packages/f9/63/d2747d930882c9d661e9398eefc54f15696547b8983aaaf11d4a2e8b5426/pyarrow-23.0.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:71c5be5cbf1e1cb6169d2a0980850bccb558ddc9b747b6206435313c47c37677", size = 44473279, upload-time = "2026-02-16T10:11:01.557Z" }, + { url = "https://files.pythonhosted.org/packages/b3/93/10a48b5e238de6d562a411af6467e71e7aedbc9b87f8d3a35f1560ae30fb/pyarrow-23.0.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:9b6f4f17b43bc39d56fec96e53fe89d94bac3eb134137964371b45352d40d0c2", size = 47585798, upload-time = "2026-02-16T10:11:09.401Z" }, + { url = "https://files.pythonhosted.org/packages/5c/20/476943001c54ef078dbf9542280e22741219a184a0632862bca4feccd666/pyarrow-23.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9fc13fc6c403d1337acab46a2c4346ca6c9dec5780c3c697cf8abfd5e19b6b37", size = 48179446, upload-time = "2026-02-16T10:11:17.781Z" }, + { url = "https://files.pythonhosted.org/packages/4b/b6/5dd0c47b335fcd8edba9bfab78ad961bd0fd55ebe53468cc393f45e0be60/pyarrow-23.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5c16ed4f53247fa3ffb12a14d236de4213a4415d127fe9cebed33d51671113e2", size = 50623972, upload-time = "2026-02-16T10:11:26.185Z" }, + { url = "https://files.pythonhosted.org/packages/d5/09/a532297c9591a727d67760e2e756b83905dd89adb365a7f6e9c72578bcc1/pyarrow-23.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:cecfb12ef629cf6be0b1887f9f86463b0dd3dc3195ae6224e74006be4736035a", size = 27540749, upload-time = "2026-02-16T10:12:23.297Z" }, + { url = "https://files.pythonhosted.org/packages/a5/8e/38749c4b1303e6ae76b3c80618f84861ae0c55dd3c2273842ea6f8258233/pyarrow-23.0.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:29f7f7419a0e30264ea261fdc0e5fe63ce5a6095003db2945d7cd78df391a7e1", size = 34471544, upload-time = "2026-02-16T10:11:32.535Z" }, + { url = "https://files.pythonhosted.org/packages/a3/73/f237b2bc8c669212f842bcfd842b04fc8d936bfc9d471630569132dc920d/pyarrow-23.0.1-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:33d648dc25b51fd8055c19e4261e813dfc4d2427f068bcecc8b53d01b81b0500", size = 35949911, upload-time = "2026-02-16T10:11:39.813Z" }, + { url = "https://files.pythonhosted.org/packages/0c/86/b912195eee0903b5611bf596833def7d146ab2d301afeb4b722c57ffc966/pyarrow-23.0.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:cd395abf8f91c673dd3589cadc8cc1ee4e8674fa61b2e923c8dd215d9c7d1f41", size = 44520337, upload-time = "2026-02-16T10:11:47.764Z" }, + { url = "https://files.pythonhosted.org/packages/69/c2/f2a717fb824f62d0be952ea724b4f6f9372a17eed6f704b5c9526f12f2f1/pyarrow-23.0.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:00be9576d970c31defb5c32eb72ef585bf600ef6d0a82d5eccaae96639cf9d07", size = 47548944, upload-time = "2026-02-16T10:11:56.607Z" }, + { url = "https://files.pythonhosted.org/packages/84/a7/90007d476b9f0dc308e3bc57b832d004f848fd6c0da601375d20d92d1519/pyarrow-23.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c2139549494445609f35a5cda4eb94e2c9e4d704ce60a095b342f82460c73a83", size = 48236269, upload-time = "2026-02-16T10:12:04.47Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3f/b16fab3e77709856eb6ac328ce35f57a6d4a18462c7ca5186ef31b45e0e0/pyarrow-23.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7044b442f184d84e2351e5084600f0d7343d6117aabcbc1ac78eb1ae11eb4125", size = 50604794, upload-time = "2026-02-16T10:12:11.797Z" }, + { url = "https://files.pythonhosted.org/packages/e9/a1/22df0620a9fac31d68397a75465c344e83c3dfe521f7612aea33e27ab6c0/pyarrow-23.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:a35581e856a2fafa12f3f54fce4331862b1cfb0bef5758347a858a4aa9d6bae8", size = 27660642, upload-time = "2026-02-16T10:12:17.746Z" }, + { url = "https://files.pythonhosted.org/packages/8d/1b/6da9a89583ce7b23ac611f183ae4843cd3a6cf54f079549b0e8c14031e73/pyarrow-23.0.1-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:5df1161da23636a70838099d4aaa65142777185cc0cdba4037a18cee7d8db9ca", size = 34238755, upload-time = "2026-02-16T10:12:32.819Z" }, + { url = "https://files.pythonhosted.org/packages/ae/b5/d58a241fbe324dbaeb8df07be6af8752c846192d78d2272e551098f74e88/pyarrow-23.0.1-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:fa8e51cb04b9f8c9c5ace6bab63af9a1f88d35c0d6cbf53e8c17c098552285e1", size = 35847826, upload-time = "2026-02-16T10:12:38.949Z" }, + { url = "https://files.pythonhosted.org/packages/54/a5/8cbc83f04aba433ca7b331b38f39e000efd9f0c7ce47128670e737542996/pyarrow-23.0.1-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:0b95a3994f015be13c63148fef8832e8a23938128c185ee951c98908a696e0eb", size = 44536859, upload-time = "2026-02-16T10:12:45.467Z" }, + { url = "https://files.pythonhosted.org/packages/36/2e/c0f017c405fcdc252dbccafbe05e36b0d0eb1ea9a958f081e01c6972927f/pyarrow-23.0.1-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:4982d71350b1a6e5cfe1af742c53dfb759b11ce14141870d05d9e540d13bc5d1", size = 47614443, upload-time = "2026-02-16T10:12:55.525Z" }, + { url = "https://files.pythonhosted.org/packages/af/6b/2314a78057912f5627afa13ba43809d9d653e6630859618b0fd81a4e0759/pyarrow-23.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c250248f1fe266db627921c89b47b7c06fee0489ad95b04d50353537d74d6886", size = 48232991, upload-time = "2026-02-16T10:13:04.729Z" }, + { url = "https://files.pythonhosted.org/packages/40/f2/1bcb1d3be3460832ef3370d621142216e15a2c7c62602a4ea19ec240dd64/pyarrow-23.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5f4763b83c11c16e5f4c15601ba6dfa849e20723b46aa2617cb4bffe8768479f", size = 50645077, upload-time = "2026-02-16T10:13:14.147Z" }, + { url = "https://files.pythonhosted.org/packages/eb/3f/b1da7b61cd66566a4d4c8383d376c606d1c34a906c3f1cb35c479f59d1aa/pyarrow-23.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:3a4c85ef66c134161987c17b147d6bffdca4566f9a4c1d81a0a01cdf08414ea5", size = 28234271, upload-time = "2026-02-16T10:14:09.397Z" }, + { url = "https://files.pythonhosted.org/packages/b5/78/07f67434e910a0f7323269be7bfbf58699bd0c1d080b18a1ab49ba943fe8/pyarrow-23.0.1-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:17cd28e906c18af486a499422740298c52d7c6795344ea5002a7720b4eadf16d", size = 34488692, upload-time = "2026-02-16T10:13:21.541Z" }, + { url = "https://files.pythonhosted.org/packages/50/76/34cf7ae93ece1f740a04910d9f7e80ba166b9b4ab9596a953e9e62b90fe1/pyarrow-23.0.1-cp314-cp314t-macosx_12_0_x86_64.whl", hash = "sha256:76e823d0e86b4fb5e1cf4a58d293036e678b5a4b03539be933d3b31f9406859f", size = 35964383, upload-time = "2026-02-16T10:13:28.63Z" }, + { url = "https://files.pythonhosted.org/packages/46/90/459b827238936d4244214be7c684e1b366a63f8c78c380807ae25ed92199/pyarrow-23.0.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:a62e1899e3078bf65943078b3ad2a6ddcacf2373bc06379aac61b1e548a75814", size = 44538119, upload-time = "2026-02-16T10:13:35.506Z" }, + { url = "https://files.pythonhosted.org/packages/28/a1/93a71ae5881e99d1f9de1d4554a87be37da11cd6b152239fb5bd924fdc64/pyarrow-23.0.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:df088e8f640c9fae3b1f495b3c64755c4e719091caf250f3a74d095ddf3c836d", size = 47571199, upload-time = "2026-02-16T10:13:42.504Z" }, + { url = "https://files.pythonhosted.org/packages/88/a3/d2c462d4ef313521eaf2eff04d204ac60775263f1fb08c374b543f79f610/pyarrow-23.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:46718a220d64677c93bc243af1d44b55998255427588e400677d7192671845c7", size = 48259435, upload-time = "2026-02-16T10:13:49.226Z" }, + { url = "https://files.pythonhosted.org/packages/cc/f1/11a544b8c3d38a759eb3fbb022039117fd633e9a7b19e4841cc3da091915/pyarrow-23.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a09f3876e87f48bc2f13583ab551f0379e5dfb83210391e68ace404181a20690", size = 50629149, upload-time = "2026-02-16T10:13:57.238Z" }, + { url = "https://files.pythonhosted.org/packages/50/f2/c0e76a0b451ffdf0cf788932e182758eb7558953f4f27f1aff8e2518b653/pyarrow-23.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:527e8d899f14bd15b740cd5a54ad56b7f98044955373a17179d5956ddb93d9ce", size = 28365807, upload-time = "2026-02-16T10:14:03.892Z" }, ] [[package]] @@ -4306,7 +4338,8 @@ version = "2.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, - { name = "cattrs" }, + { name = "cattrs", version = "25.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "cattrs", version = "26.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "lsprotocol" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1b/94/cce3560f6c7296be43bd67ba342f8972b8adddfe407b62b25d1fb90c514b/pygls-2.0.1.tar.gz", hash = "sha256:2f774a669fbe2ece977d302786f01f9b0c5df7d0204ea0fa371ecb08288d6b86", size = 55796, upload-time = "2026-01-26T23:04:33.8Z" } @@ -5206,7 +5239,7 @@ resolution-markers = [ "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] dependencies = [ - { name = "numpy", version = "2.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/56/3e/9cca699f3486ce6bc12ff46dc2031f1ec8eb9ccc9a320fdaf925f1417426/scipy-1.17.0.tar.gz", hash = "sha256:2591060c8e648d8b96439e111ac41fd8342fdeff1876be2e19dea3fe8930454e", size = 30396830, upload-time = "2026-01-10T21:34:23.009Z" } wheels = [ @@ -5274,15 +5307,15 @@ wheels = [ [[package]] name = "sentry-sdk" -version = "2.52.0" +version = "2.53.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/59/eb/1b497650eb564701f9a7b8a95c51b2abe9347ed2c0b290ba78f027ebe4ea/sentry_sdk-2.52.0.tar.gz", hash = "sha256:fa0bec872cfec0302970b2996825723d67390cdd5f0229fb9efed93bd5384899", size = 410273, upload-time = "2026-02-04T15:03:54.706Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d3/06/66c8b705179bc54087845f28fd1b72f83751b6e9a195628e2e9af9926505/sentry_sdk-2.53.0.tar.gz", hash = "sha256:6520ef2c4acd823f28efc55e43eb6ce2e6d9f954a95a3aa96b6fd14871e92b77", size = 412369, upload-time = "2026-02-16T11:11:14.743Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/63/2c6daf59d86b1c30600bff679d039f57fd1932af82c43c0bde1cbc55e8d4/sentry_sdk-2.52.0-py2.py3-none-any.whl", hash = "sha256:931c8f86169fc6f2752cb5c4e6480f0d516112e78750c312e081ababecbaf2ed", size = 435547, upload-time = "2026-02-04T15:03:51.567Z" }, + { url = "https://files.pythonhosted.org/packages/47/d4/2fdf854bc3b9c7f55219678f812600a20a138af2dd847d99004994eada8f/sentry_sdk-2.53.0-py2.py3-none-any.whl", hash = "sha256:46e1ed8d84355ae54406c924f6b290c3d61f4048625989a723fd622aab838899", size = 437908, upload-time = "2026-02-16T11:11:13.227Z" }, ] [[package]] @@ -5350,7 +5383,7 @@ dependencies = [ { name = "markdown", version = "3.10.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, - { name = "numpy", version = "2.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "packaging" }, { name = "pillow", version = "11.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "pillow", version = "12.1.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, @@ -5394,7 +5427,7 @@ dependencies = [ { name = "ml-dtypes" }, { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, - { name = "numpy", version = "2.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "opt-einsum" }, { name = "packaging" }, { name = "protobuf" }, @@ -5609,7 +5642,7 @@ resolution-markers = [ ] dependencies = [ { name = "cuda-bindings", marker = "python_full_version >= '3.10' and platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "filelock", version = "3.21.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "filelock", version = "3.24.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "fsspec", version = "2026.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "jinja2", marker = "python_full_version >= '3.10'" }, { name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, @@ -6203,27 +6236,27 @@ wheels = [ [[package]] name = "uv" -version = "0.10.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0d/9a/fe74aa0127cdc26141364e07abf25e5d69b4bf9788758fad9cfecca637aa/uv-0.10.2.tar.gz", hash = "sha256:b5016f038e191cc9ef00e17be802f44363d1b1cc3ef3454d1d76839a4246c10a", size = 3858864, upload-time = "2026-02-10T19:17:51.609Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/b5/aea88f66284d220be56ef748ed5e1bd11d819be14656a38631f4b55bfd48/uv-0.10.2-py3-none-linux_armv6l.whl", hash = "sha256:69e35aa3e91a245b015365e5e6ca383ecf72a07280c6d00c17c9173f2d3b68ab", size = 22215714, upload-time = "2026-02-10T19:17:34.281Z" }, - { url = "https://files.pythonhosted.org/packages/7f/72/947ba7737ae6cd50de61d268781b9e7717caa3b07e18238ffd547f9fc728/uv-0.10.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:0b7eef95c36fe92e7aac399c0dce555474432cbfeaaa23975ed83a63923f78fd", size = 21276485, upload-time = "2026-02-10T19:18:15.415Z" }, - { url = "https://files.pythonhosted.org/packages/d3/38/5c3462b927a93be4ccaaa25138926a5fb6c9e1b72884efd7af77e451d82e/uv-0.10.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:acc08e420abab21de987151059991e3f04bc7f4044d94ca58b5dd547995b4843", size = 20048620, upload-time = "2026-02-10T19:17:26.481Z" }, - { url = "https://files.pythonhosted.org/packages/03/51/d4509b0f5b7740c1af82202e9c69b700d5848b8bd0faa25229e8edd2c19c/uv-0.10.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:aefbcd749ab2ad48bb533ec028607607f7b03be11c83ea152dbb847226cd6285", size = 21870454, upload-time = "2026-02-10T19:17:21.838Z" }, - { url = "https://files.pythonhosted.org/packages/cd/7e/2bcbafcb424bb885817a7e58e6eec9314c190c55935daaafab1858bb82cd/uv-0.10.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:fad554c38d9988409ceddfac69a465e6e5f925a8b689e7606a395c20bb4d1d78", size = 21839508, upload-time = "2026-02-10T19:17:59.211Z" }, - { url = "https://files.pythonhosted.org/packages/60/08/16df2c1f8ad121a595316b82f6e381447e8974265b2239c9135eb874f33b/uv-0.10.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6dd2dc41043e92b3316d7124a7bf48c2affe7117c93079419146f083df71933c", size = 21841283, upload-time = "2026-02-10T19:17:41.419Z" }, - { url = "https://files.pythonhosted.org/packages/76/27/a869fec4c03af5e43db700fabe208d8ee8dbd56e0ff568ba792788d505cd/uv-0.10.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:111c05182c5630ac523764e0ec2e58d7b54eb149dbe517b578993a13c2f71aff", size = 23111967, upload-time = "2026-02-10T19:18:11.764Z" }, - { url = "https://files.pythonhosted.org/packages/2a/4a/fb38515d966acfbd80179e626985aab627898ffd02c70205850d6eb44df1/uv-0.10.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45c3deaba0343fd27ab5385d6b7cde0765df1a15389ee7978b14a51c32895662", size = 23911019, upload-time = "2026-02-10T19:18:26.947Z" }, - { url = "https://files.pythonhosted.org/packages/dd/5f/51bcbb490ddb1dcb06d767f0bde649ad2826686b9e30efa57f8ab2750a1d/uv-0.10.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bb2cac4f3be60b64a23d9f035019c30a004d378b563c94f60525c9591665a56b", size = 23030217, upload-time = "2026-02-10T19:17:37.789Z" }, - { url = "https://files.pythonhosted.org/packages/46/69/144f6db851d49aa6f25b040dc5c8c684b8f92df9e8d452c7abc619c6ec23/uv-0.10.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:937687df0380d636ceafcb728cf6357f0432588e721892128985417b283c3b54", size = 23036452, upload-time = "2026-02-10T19:18:18.97Z" }, - { url = "https://files.pythonhosted.org/packages/66/29/3c7c4559c9310ed478e3d6c585ee0aad2852dc4d5fb14f4d92a2a12d1728/uv-0.10.2-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:f90bca8703ae66bccfcfb7313b4b697a496c4d3df662f4a1a2696a6320c47598", size = 21941903, upload-time = "2026-02-10T19:17:30.575Z" }, - { url = "https://files.pythonhosted.org/packages/9a/5a/42883b5ef2ef0b1bc5b70a1da12a6854a929ff824aa8eb1a5571fb27a39b/uv-0.10.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:cca026c2e584788e1264879a123bf499dd8f169b9cafac4a2065a416e09d3823", size = 22651571, upload-time = "2026-02-10T19:18:22.74Z" }, - { url = "https://files.pythonhosted.org/packages/e8/b8/e4f1dda1b3b0cc6c8ac06952bfe7bc28893ff016fb87651c8fafc6dfca96/uv-0.10.2-py3-none-musllinux_1_1_i686.whl", hash = "sha256:9f878837938103ee1307ed3ed5d9228118e3932816ab0deb451e7e16dc8ce82a", size = 22321279, upload-time = "2026-02-10T19:17:49.402Z" }, - { url = "https://files.pythonhosted.org/packages/2c/4b/baa16d46469e024846fc1a8aa0cfa63f1f89ad0fd3eaa985359a168c3fb0/uv-0.10.2-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:6ec75cfe638b316b329474aa798c3988e5946ead4d9e977fe4dc6fc2ea3e0b8b", size = 23252208, upload-time = "2026-02-10T19:17:54.46Z" }, - { url = "https://files.pythonhosted.org/packages/d6/84/6a74e5ec2ee90e4314905e6d1d1708d473e06405e492ec38868b42645388/uv-0.10.2-py3-none-win32.whl", hash = "sha256:f7f3c7e09bf53b81f55730a67dd86299158f470dffb2bd279b6432feb198d231", size = 21118543, upload-time = "2026-02-10T19:18:07.296Z" }, - { url = "https://files.pythonhosted.org/packages/dd/f9/e5cc6cf3a578b87004e857274df97d3cdecd8e19e965869b9b67c094c20c/uv-0.10.2-py3-none-win_amd64.whl", hash = "sha256:7b3685aa1da15acbe080b4cba8684afbb6baf11c9b04d4d4b347cc18b7b9cfa0", size = 23620790, upload-time = "2026-02-10T19:17:45.204Z" }, - { url = "https://files.pythonhosted.org/packages/df/7a/99979dc08ae6a65f4f7a44c5066699016c6eecdc4e695b7512c2efb53378/uv-0.10.2-py3-none-win_arm64.whl", hash = "sha256:abdd5b3c6b871b17bf852a90346eb7af881345706554fd082346b000a9393afd", size = 22035199, upload-time = "2026-02-10T19:18:03.679Z" }, +version = "0.10.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c2/bb/dfd872ab6515e5609dc899acb65ccaf8cbedddefa3e34e8da0a5b3e13070/uv-0.10.4.tar.gz", hash = "sha256:b9ecf9f9145b95ddd6627b106e2e74f4204393b41bea2488079872699c03612e", size = 3875347, upload-time = "2026-02-17T22:01:22.28Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d8/a3/565e5e45b5006c108ccd596682768c00be988421a83be92193c90bd889e4/uv-0.10.4-py3-none-linux_armv6l.whl", hash = "sha256:97cd6856145dec1d50821468bb6a10c14f3d71015eb97bb657163c837b5ffe79", size = 22352134, upload-time = "2026-02-17T22:01:30.071Z" }, + { url = "https://files.pythonhosted.org/packages/3e/c6/b86f3fdcde9f270e6dc1ff631a4fe73971bf4162c4dd169c7621110361b8/uv-0.10.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:44dd91ef224cfce2203716ecf244c3d3641269d1c99996aab852248caf2aeba4", size = 21417697, upload-time = "2026-02-17T22:01:51.162Z" }, + { url = "https://files.pythonhosted.org/packages/63/91/c4ddf7e55e05394967615050cc364a999157a44c008d0e1e9db2ed49a11c/uv-0.10.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:751959135a62f006ef51f3fcc5d02ec67986defa0424d470cce0918eede36a55", size = 20082236, upload-time = "2026-02-17T22:01:43.025Z" }, + { url = "https://files.pythonhosted.org/packages/25/92/606701b147d421ba2afe327d25f1ec5f59e519157b7e530d09cf61781d22/uv-0.10.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:c184891b496c5fa04a7e1396d7f1953f52c97a5635636330854ab68f9e8ec212", size = 21921200, upload-time = "2026-02-17T22:01:24.131Z" }, + { url = "https://files.pythonhosted.org/packages/c3/79/942e75d0920a9e4cac76257cd3e2c238f1963d7e45423793f92e84eaa480/uv-0.10.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:5b8a2170ecc700d82ed322fa056789ae2281353fef094e44f563c2f32ab8f438", size = 21974822, upload-time = "2026-02-17T22:01:45.337Z" }, + { url = "https://files.pythonhosted.org/packages/60/71/e5b1140c5c7296f935037a967717a82591522bbc93b4e67c4554dfbb4380/uv-0.10.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:decaf620106efa0d09ca27a8301dd83b8a5371e42649cd2704cfd11fe31af7d7", size = 21953309, upload-time = "2026-02-17T22:01:38.225Z" }, + { url = "https://files.pythonhosted.org/packages/70/a3/03ac1ff2058413c2c7d347f3b3396f291e192b096d2625a201c00bd962c6/uv-0.10.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f7d1035db05ac5b94387395428bdcbfce685f6c8eb2b711b66a5a1b397111913", size = 23217053, upload-time = "2026-02-17T22:01:09.278Z" }, + { url = "https://files.pythonhosted.org/packages/e3/d5/9b02140e8ff29d9b575335662288493cdcde5f123337613c04613017cf23/uv-0.10.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e754f9c8fd7532a28da7deaa6e400de5e7b459f7846bd5320db215a074fa8664", size = 24053086, upload-time = "2026-02-17T22:01:32.722Z" }, + { url = "https://files.pythonhosted.org/packages/f8/80/7023e1b0f9180226f8c3aa3e207383671cb524eb8bbd8a8eecf1c0cfe867/uv-0.10.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d419ef8d4fbd5be0af952a60c76d4f6183acb827cc729095d11c63e7dfaec24c", size = 23121689, upload-time = "2026-02-17T22:01:26.835Z" }, + { url = "https://files.pythonhosted.org/packages/f2/b3/4b9580d62e1245df52e8516cf3e404ff39cc72634d2d749d47b1dada4161/uv-0.10.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82978155e571f2ac3dd57077bd746bfe41b65fa19accc3c92d1f09632cd36c63", size = 23136767, upload-time = "2026-02-17T22:01:40.729Z" }, + { url = "https://files.pythonhosted.org/packages/bd/4e/058976e2a5513f11954e09595a1821d5db1819e96e00bafded19c6a470e9/uv-0.10.4-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:8437e56a7d0f8ecd7421e8b84024dd8153179b8f1371ca1bd66b79fa7fb4c2c1", size = 22003202, upload-time = "2026-02-17T22:01:12.447Z" }, + { url = "https://files.pythonhosted.org/packages/41/c5/da0fc5b732f7dd1f99116ce19e3c1cae7dfa7d04528a0c38268f20643edf/uv-0.10.4-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:ff1c6a465ec035dfe2dfd745b2e85061f47ab3c5cc626eead491994c028eacc6", size = 22720004, upload-time = "2026-02-17T22:01:53.551Z" }, + { url = "https://files.pythonhosted.org/packages/71/17/13c24dd56c135553645c2c62543eba928e88479fdd2d8356fdf35a0113bc/uv-0.10.4-py3-none-musllinux_1_1_i686.whl", hash = "sha256:525dc49a02b78fcd77431f013f2c48b2a152e31808e792c0d1aee4600495a320", size = 22401692, upload-time = "2026-02-17T22:01:35.368Z" }, + { url = "https://files.pythonhosted.org/packages/9c/b2/7a5fdbc0bfd8364e6290457794127d5e766dbc6d44bb15d1a9e318bc356b/uv-0.10.4-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:7d514b30877fda6e83874ccbd1379e0249cfa064511c5858433edcf697d0d4e3", size = 23330968, upload-time = "2026-02-17T22:01:15.237Z" }, + { url = "https://files.pythonhosted.org/packages/d1/df/004e32be4cd24338422842dd93383f2df0be4554efb6872fef37997ff3ca/uv-0.10.4-py3-none-win32.whl", hash = "sha256:4aed1237847dbd694475c06e8608f2f5f6509181ac148ee35694400d382a3784", size = 21373394, upload-time = "2026-02-17T22:01:20.362Z" }, + { url = "https://files.pythonhosted.org/packages/31/dd/1900452678d46f6a649ab8167bededb02500b0561fc9f69e1f52607895c7/uv-0.10.4-py3-none-win_amd64.whl", hash = "sha256:4a1c595cf692fa611019a7ad9bf4b0757fccd0a3f838ca05e53db82912ddaa39", size = 23813606, upload-time = "2026-02-17T22:01:17.733Z" }, + { url = "https://files.pythonhosted.org/packages/7b/e8/c6ba7ceee3ec58d21156b4968449e6a12af15eea8d26308b3b3ffeef2baf/uv-0.10.4-py3-none-win_arm64.whl", hash = "sha256:28c59a02d7a648b75a9c2ea735773d9d357a1eee773b78593c275b0bef1a4b73", size = 22180241, upload-time = "2026-02-17T22:01:56.305Z" }, ] [[package]] @@ -6377,7 +6410,7 @@ wheels = [ [[package]] name = "xarray" -version = "2026.1.0" +version = "2026.2.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.14' and sys_platform == 'win32'", @@ -6394,13 +6427,13 @@ resolution-markers = [ "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] dependencies = [ - { name = "numpy", version = "2.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "packaging", marker = "python_full_version >= '3.11'" }, - { name = "pandas", version = "3.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "pandas", version = "3.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f5/85/113ff1e2cde9e8a5b13c2f0ef4e9f5cd6ca3a036b6452f4dd523419289b5/xarray-2026.1.0.tar.gz", hash = "sha256:0c9814761f9d9a9545df37292d3fda89f83201f3e02ae0f09f03313d9cfdd5e2", size = 3107024, upload-time = "2026-01-28T17:49:03.822Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/03/e3353b72e518574b32993989d8f696277bf878e9d508c7dd22e86c0dab5b/xarray-2026.2.0.tar.gz", hash = "sha256:978b6acb018770554f8fd964af4eb02f9bcc165d4085dbb7326190d92aa74bcf", size = 3111388, upload-time = "2026-02-13T22:20:50.18Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7d/8e/952a351c10df395d9bab850f611f4368834ae9104d6449049f5a49e00925/xarray-2026.1.0-py3-none-any.whl", hash = "sha256:5fcc03d3ed8dfb662aa254efe6cd65efc70014182bbc2126e4b90d291d970d41", size = 1403009, upload-time = "2026-01-28T17:49:01.538Z" }, + { url = "https://files.pythonhosted.org/packages/99/92/545eb2ca17fc0e05456728d7e4378bfee48d66433ae3b7e71948e46826fb/xarray-2026.2.0-py3-none-any.whl", hash = "sha256:e927d7d716ea71dea78a13417970850a640447d8dd2ceeb65c5687f6373837c9", size = 1405358, upload-time = "2026-02-13T22:20:47.847Z" }, ] [[package]] From d91ee0a0f317dbe3b0ce507b04507cdb827d0e65 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 18 Feb 2026 20:20:56 -0500 Subject: [PATCH 045/100] chore: update tessl agent config files Replace skills gitignores with MCP server config for codex and gemini. --- .codex/config.toml | 4 ++++ .codex/skills/.gitignore | 2 -- .gemini/settings.json | 12 ++++++++++++ .gemini/skills/.gitignore | 2 -- 4 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 .codex/config.toml delete mode 100644 .codex/skills/.gitignore create mode 100644 .gemini/settings.json delete mode 100644 .gemini/skills/.gitignore diff --git a/.codex/config.toml b/.codex/config.toml new file mode 100644 index 000000000..433432493 --- /dev/null +++ b/.codex/config.toml @@ -0,0 +1,4 @@ +[mcp_servers.tessl] +type = "stdio" +command = "tessl" +args = [ "mcp", "start" ] diff --git a/.codex/skills/.gitignore b/.codex/skills/.gitignore deleted file mode 100644 index b1cda282a..000000000 --- a/.codex/skills/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Managed by Tessl -tessl:* diff --git a/.gemini/settings.json b/.gemini/settings.json new file mode 100644 index 000000000..ebfccaac7 --- /dev/null +++ b/.gemini/settings.json @@ -0,0 +1,12 @@ +{ + "mcpServers": { + "tessl": { + "type": "stdio", + "command": "tessl", + "args": [ + "mcp", + "start" + ] + } + } +} diff --git a/.gemini/skills/.gitignore b/.gemini/skills/.gitignore deleted file mode 100644 index b1cda282a..000000000 --- a/.gemini/skills/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Managed by Tessl -tessl:* From 9e8c29d0e9cd3f2547a6889437332703f631e060 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 18 Feb 2026 20:54:10 -0500 Subject: [PATCH 046/100] fix: include module-level variables and second-degree helpers in testgen helper FQNs Generated tests were importing symbols like _EXTENSION_REGISTRY from the wrong module because helper_function_names only contained first-degree function/class helpers. The AI had no metadata about where module-level variables lived, causing incorrect import paths and 0% test coverage. --- .../python/context/code_context_extractor.py | 20 ++++++++++--------- codeflash/models/models.py | 1 + codeflash/optimization/function_optimizer.py | 11 +++++++--- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/codeflash/languages/python/context/code_context_extractor.py b/codeflash/languages/python/context/code_context_extractor.py index c7078e995..09b045dcc 100644 --- a/codeflash/languages/python/context/code_context_extractor.py +++ b/codeflash/languages/python/context/code_context_extractor.py @@ -107,8 +107,7 @@ def get_code_optimization_context( for qualified_names in helpers_of_fto_qualified_names_dict.values(): qualified_names.update({f"{qn.rsplit('.', 1)[0]}.__init__" for qn in qualified_names if "." in qn}) - # Get FunctionSource representation of helpers of helpers of FTO - helpers_of_helpers_dict, _helpers_of_helpers_list = get_function_sources_from_jedi( + helpers_of_helpers_dict, helpers_of_helpers_list = get_function_sources_from_jedi( helpers_of_fto_qualified_names_dict, project_root_path ) @@ -186,6 +185,8 @@ def get_code_optimization_context( code_hash_context = hashing_code_context.markdown code_hash = hashlib.sha256(code_hash_context.encode("utf-8")).hexdigest() + all_helper_fqns = list({fs.fully_qualified_name for fs in helpers_of_fto_list + helpers_of_helpers_list}) + return CodeOptimizationContext( testgen_context=testgen_context, read_writable_code=final_read_writable_code, @@ -193,6 +194,7 @@ def get_code_optimization_context( hashing_code_context=code_hash_context, hashing_code_context_hash=code_hash, helper_functions=helpers_of_fto_list, + testgen_helper_fqns=all_helper_fqns, preexisting_objects=preexisting_objects, ) @@ -317,13 +319,12 @@ def get_code_optimization_context_for_language( return CodeOptimizationContext( testgen_context=testgen_context, read_writable_code=read_writable_code, - # Pass type definitions and globals as read-only context for the AI - # This way the AI sees them as context but doesn't include them in optimized output read_only_context_code=code_context.read_only_context, hashing_code_context=read_writable_code.flat, hashing_code_context_hash=code_hash, helper_functions=helper_function_sources, - preexisting_objects=set(), # Not implemented for non-Python yet + testgen_helper_fqns=[fs.fully_qualified_name for fs in helper_function_sources], + preexisting_objects=set(), ) @@ -519,15 +520,16 @@ def get_function_sources_from_jedi( and not belongs_to_function_qualified(definition, qualified_function_name) and definition.full_name.startswith(definition.module_name) ) - if is_valid_definition and definition.type in ("function", "class"): + if is_valid_definition and definition.type in ("function", "class", "statement"): if definition.type == "function": fqn = definition.full_name func_name = definition.name - else: - # When a class is instantiated (e.g., MyClass()), track its __init__ as a helper - # This ensures the class definition with constructor is included in testgen context + elif definition.type == "class": fqn = f"{definition.full_name}.__init__" func_name = "__init__" + else: + fqn = definition.full_name + func_name = definition.name qualified_name = get_qualified_name(definition.module_name, fqn) # Avoid nested functions or classes. Only class.function is allowed if len(qualified_name.split(".")) <= 2: diff --git a/codeflash/models/models.py b/codeflash/models/models.py index 86aef25c9..b7aeb43b1 100644 --- a/codeflash/models/models.py +++ b/codeflash/models/models.py @@ -380,6 +380,7 @@ class CodeOptimizationContext(BaseModel): hashing_code_context: str = "" hashing_code_context_hash: str = "" helper_functions: list[FunctionSource] + testgen_helper_fqns: list[str] = [] preexisting_objects: set[tuple[str, tuple[FunctionParent, ...]]] diff --git a/codeflash/optimization/function_optimizer.py b/codeflash/optimization/function_optimizer.py index 372d7892f..8e3d3202b 100644 --- a/codeflash/optimization/function_optimizer.py +++ b/codeflash/optimization/function_optimizer.py @@ -579,6 +579,7 @@ def generate_and_instrument_tests( test_results = self.generate_tests( testgen_context=code_context.testgen_context, helper_functions=code_context.helper_functions, + testgen_helper_fqns=code_context.testgen_helper_fqns, generated_test_paths=generated_test_paths, generated_perf_test_paths=generated_perf_test_paths, ) @@ -1521,7 +1522,8 @@ def get_code_optimization_context(self) -> Result[CodeOptimizationContext, str]: read_only_context_code=new_code_ctx.read_only_context_code, hashing_code_context=new_code_ctx.hashing_code_context, hashing_code_context_hash=new_code_ctx.hashing_code_context_hash, - helper_functions=new_code_ctx.helper_functions, # only functions that are read writable + helper_functions=new_code_ctx.helper_functions, + testgen_helper_fqns=new_code_ctx.testgen_helper_fqns, preexisting_objects=new_code_ctx.preexisting_objects, ) ) @@ -1727,6 +1729,7 @@ def generate_tests( self, testgen_context: CodeStringsMarkdown, helper_functions: list[FunctionSource], + testgen_helper_fqns: list[str], generated_test_paths: list[Path], generated_perf_test_paths: list[Path], ) -> Result[tuple[int, GeneratedTestsList, dict[str, set[FunctionCalledInTest]], str], str]: @@ -1735,11 +1738,13 @@ def generate_tests( assert len(generated_test_paths) == n_tests if not self.args.no_gen_tests: - # Submit test generation tasks + helper_fqns = testgen_helper_fqns or [ + definition.fully_qualified_name for definition in helper_functions + ] future_tests = self.submit_test_generation_tasks( self.executor, testgen_context.markdown, - [definition.fully_qualified_name for definition in helper_functions], + helper_fqns, generated_test_paths, generated_perf_test_paths, ) From 5f7dadf8259f3a0f84c0a08f7ff964a44b9a9648 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 01:56:48 +0000 Subject: [PATCH 047/100] style: auto-fix ruff formatting in function_optimizer.py --- codeflash/optimization/function_optimizer.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/codeflash/optimization/function_optimizer.py b/codeflash/optimization/function_optimizer.py index 8e3d3202b..7cbcda976 100644 --- a/codeflash/optimization/function_optimizer.py +++ b/codeflash/optimization/function_optimizer.py @@ -1738,15 +1738,9 @@ def generate_tests( assert len(generated_test_paths) == n_tests if not self.args.no_gen_tests: - helper_fqns = testgen_helper_fqns or [ - definition.fully_qualified_name for definition in helper_functions - ] + helper_fqns = testgen_helper_fqns or [definition.fully_qualified_name for definition in helper_functions] future_tests = self.submit_test_generation_tasks( - self.executor, - testgen_context.markdown, - helper_fqns, - generated_test_paths, - generated_perf_test_paths, + self.executor, testgen_context.markdown, helper_fqns, generated_test_paths, generated_perf_test_paths ) future_concolic_tests = self.executor.submit( From 6360b63822781a45f77f0e3e34fb3960caa8f4e4 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 18 Feb 2026 20:57:47 -0500 Subject: [PATCH 048/100] chore: remove tiles directory --- tiles/codeflash-docs/docs/ai-service.md | 108 ------------- tiles/codeflash-docs/docs/configuration.md | 79 --------- .../codeflash-docs/docs/context-extraction.md | 60 ------- tiles/codeflash-docs/docs/domain-types.md | 153 ------------------ tiles/codeflash-docs/docs/index.md | 41 ----- .../docs/optimization-pipeline.md | 84 ---------- tiles/codeflash-docs/docs/verification.md | 93 ----------- tiles/codeflash-docs/evals/capabilities.json | 118 -------------- .../evals/scenario-1/capability.txt | 1 - .../evals/scenario-1/criteria.json | 21 --- tiles/codeflash-docs/evals/scenario-1/task.md | 35 ---- .../evals/scenario-2/capability.txt | 1 - .../evals/scenario-2/criteria.json | 26 --- tiles/codeflash-docs/evals/scenario-2/task.md | 13 -- .../evals/scenario-3/capability.txt | 1 - .../evals/scenario-3/criteria.json | 31 ---- tiles/codeflash-docs/evals/scenario-3/task.md | 13 -- .../evals/scenario-4/capability.txt | 1 - .../evals/scenario-4/criteria.json | 26 --- tiles/codeflash-docs/evals/scenario-4/task.md | 18 --- .../evals/scenario-5/capability.txt | 1 - .../evals/scenario-5/criteria.json | 26 --- tiles/codeflash-docs/evals/scenario-5/task.md | 17 -- tiles/codeflash-docs/evals/summary.json | 40 ----- .../evals/summary_infeasible.json | 25 --- tiles/codeflash-docs/tile.json | 7 - tiles/codeflash-rules/rules/architecture.md | 45 ------ tiles/codeflash-rules/rules/code-style.md | 11 -- .../codeflash-rules/rules/git-conventions.md | 9 -- tiles/codeflash-rules/rules/language-rules.md | 9 -- .../rules/optimization-patterns.md | 11 -- tiles/codeflash-rules/rules/testing-rules.md | 13 -- tiles/codeflash-rules/tile.json | 26 --- .../codeflash-skills/evals/capabilities.json | 104 ------------ .../evals/scenario-1/capability.txt | 1 - .../evals/scenario-1/criteria.json | 26 --- .../codeflash-skills/evals/scenario-1/task.md | 13 -- .../evals/scenario-2/capability.txt | 1 - .../evals/scenario-2/criteria.json | 31 ---- .../codeflash-skills/evals/scenario-2/task.md | 21 --- .../evals/scenario-3/capability.txt | 1 - .../evals/scenario-3/criteria.json | 26 --- .../codeflash-skills/evals/scenario-3/task.md | 24 --- .../evals/scenario-4/capability.txt | 1 - .../evals/scenario-4/criteria.json | 26 --- .../codeflash-skills/evals/scenario-4/task.md | 21 --- .../evals/scenario-5/capability.txt | 1 - .../evals/scenario-5/criteria.json | 26 --- .../codeflash-skills/evals/scenario-5/task.md | 17 -- tiles/codeflash-skills/evals/summary.json | 40 ----- .../evals/summary_infeasible.json | 25 --- .../add-codeflash-feature/MODULE_REFERENCE.md | 13 -- .../skills/add-codeflash-feature/SKILL.md | 146 ----------------- .../add-codeflash-feature/TROUBLESHOOTING.md | 9 -- .../debug-optimization-failure/SKILL.md | 124 -------------- tiles/codeflash-skills/tile.json | 14 -- 56 files changed, 1874 deletions(-) delete mode 100644 tiles/codeflash-docs/docs/ai-service.md delete mode 100644 tiles/codeflash-docs/docs/configuration.md delete mode 100644 tiles/codeflash-docs/docs/context-extraction.md delete mode 100644 tiles/codeflash-docs/docs/domain-types.md delete mode 100644 tiles/codeflash-docs/docs/index.md delete mode 100644 tiles/codeflash-docs/docs/optimization-pipeline.md delete mode 100644 tiles/codeflash-docs/docs/verification.md delete mode 100644 tiles/codeflash-docs/evals/capabilities.json delete mode 100644 tiles/codeflash-docs/evals/scenario-1/capability.txt delete mode 100644 tiles/codeflash-docs/evals/scenario-1/criteria.json delete mode 100644 tiles/codeflash-docs/evals/scenario-1/task.md delete mode 100644 tiles/codeflash-docs/evals/scenario-2/capability.txt delete mode 100644 tiles/codeflash-docs/evals/scenario-2/criteria.json delete mode 100644 tiles/codeflash-docs/evals/scenario-2/task.md delete mode 100644 tiles/codeflash-docs/evals/scenario-3/capability.txt delete mode 100644 tiles/codeflash-docs/evals/scenario-3/criteria.json delete mode 100644 tiles/codeflash-docs/evals/scenario-3/task.md delete mode 100644 tiles/codeflash-docs/evals/scenario-4/capability.txt delete mode 100644 tiles/codeflash-docs/evals/scenario-4/criteria.json delete mode 100644 tiles/codeflash-docs/evals/scenario-4/task.md delete mode 100644 tiles/codeflash-docs/evals/scenario-5/capability.txt delete mode 100644 tiles/codeflash-docs/evals/scenario-5/criteria.json delete mode 100644 tiles/codeflash-docs/evals/scenario-5/task.md delete mode 100644 tiles/codeflash-docs/evals/summary.json delete mode 100644 tiles/codeflash-docs/evals/summary_infeasible.json delete mode 100644 tiles/codeflash-docs/tile.json delete mode 100644 tiles/codeflash-rules/rules/architecture.md delete mode 100644 tiles/codeflash-rules/rules/code-style.md delete mode 100644 tiles/codeflash-rules/rules/git-conventions.md delete mode 100644 tiles/codeflash-rules/rules/language-rules.md delete mode 100644 tiles/codeflash-rules/rules/optimization-patterns.md delete mode 100644 tiles/codeflash-rules/rules/testing-rules.md delete mode 100644 tiles/codeflash-rules/tile.json delete mode 100644 tiles/codeflash-skills/evals/capabilities.json delete mode 100644 tiles/codeflash-skills/evals/scenario-1/capability.txt delete mode 100644 tiles/codeflash-skills/evals/scenario-1/criteria.json delete mode 100644 tiles/codeflash-skills/evals/scenario-1/task.md delete mode 100644 tiles/codeflash-skills/evals/scenario-2/capability.txt delete mode 100644 tiles/codeflash-skills/evals/scenario-2/criteria.json delete mode 100644 tiles/codeflash-skills/evals/scenario-2/task.md delete mode 100644 tiles/codeflash-skills/evals/scenario-3/capability.txt delete mode 100644 tiles/codeflash-skills/evals/scenario-3/criteria.json delete mode 100644 tiles/codeflash-skills/evals/scenario-3/task.md delete mode 100644 tiles/codeflash-skills/evals/scenario-4/capability.txt delete mode 100644 tiles/codeflash-skills/evals/scenario-4/criteria.json delete mode 100644 tiles/codeflash-skills/evals/scenario-4/task.md delete mode 100644 tiles/codeflash-skills/evals/scenario-5/capability.txt delete mode 100644 tiles/codeflash-skills/evals/scenario-5/criteria.json delete mode 100644 tiles/codeflash-skills/evals/scenario-5/task.md delete mode 100644 tiles/codeflash-skills/evals/summary.json delete mode 100644 tiles/codeflash-skills/evals/summary_infeasible.json delete mode 100644 tiles/codeflash-skills/skills/add-codeflash-feature/MODULE_REFERENCE.md delete mode 100644 tiles/codeflash-skills/skills/add-codeflash-feature/SKILL.md delete mode 100644 tiles/codeflash-skills/skills/add-codeflash-feature/TROUBLESHOOTING.md delete mode 100644 tiles/codeflash-skills/skills/debug-optimization-failure/SKILL.md delete mode 100644 tiles/codeflash-skills/tile.json diff --git a/tiles/codeflash-docs/docs/ai-service.md b/tiles/codeflash-docs/docs/ai-service.md deleted file mode 100644 index 4197a97d0..000000000 --- a/tiles/codeflash-docs/docs/ai-service.md +++ /dev/null @@ -1,108 +0,0 @@ -# AI Service - -How codeflash communicates with the AI optimization backend. - -## `AiServiceClient` (`api/aiservice.py`) - -The client connects to the AI service at `https://app.codeflash.ai` (or `http://localhost:8000` when `CODEFLASH_AIS_SERVER=local`). - -Authentication uses Bearer token from `get_codeflash_api_key()`. All requests go through `make_ai_service_request()` which handles JSON serialization via Pydantic encoder. - -Timeout: 90s for production, 300s for local. - -## Endpoints - -### `/ai/optimize` — Generate Candidates - -Method: `optimize_code()` - -Sends source code + dependency context to generate optimization candidates. - -Payload: -- `source_code` — The read-writable code (markdown format) -- `dependency_code` — Read-only context code -- `trace_id` — Unique trace ID for the optimization run -- `language` — `"python"`, `"javascript"`, or `"typescript"` -- `n_candidates` — Number of candidates to generate (controlled by effort level) -- `is_async` — Whether the function is async -- `is_numerical_code` — Whether the code is numerical (affects optimization strategy) - -Returns: `list[OptimizedCandidate]` with `source=OptimizedCandidateSource.OPTIMIZE` - -### `/ai/optimize_line_profiler` — Line-Profiler-Guided Candidates - -Method: `optimize_python_code_line_profiler()` - -Like `/optimize` but includes `line_profiler_results` to guide the LLM toward hot lines. - -Returns: candidates with `source=OptimizedCandidateSource.OPTIMIZE_LP` - -### `/ai/refine` — Refine Existing Candidate - -Method: `refine_code()` - -Request type: `AIServiceRefinerRequest` - -Sends an existing candidate with runtime data and line profiler results to generate an improved version. - -Key fields: -- `original_source_code` / `optimized_source_code` — Before and after -- `original_code_runtime` / `optimized_code_runtime` — Timing data -- `speedup` — Current speedup ratio -- `original_line_profiler_results` / `optimized_line_profiler_results` - -Returns: candidates with `source=OptimizedCandidateSource.REFINE` and `parent_id` set to the refined candidate's ID - -### `/ai/repair` — Fix Failed Candidate - -Method: `repair_code()` - -Request type: `AIServiceCodeRepairRequest` - -Sends a failed candidate with test diffs showing what went wrong. - -Key fields: -- `original_source_code` / `modified_source_code` -- `test_diffs: list[TestDiff]` — Each with `scope` (return_value/stdout/did_pass), original vs candidate values, and test source code - -Returns: candidates with `source=OptimizedCandidateSource.REPAIR` and `parent_id` set - -### `/ai/adaptive_optimize` — Multi-Candidate Adaptive - -Method: `adaptive_optimize()` - -Request type: `AIServiceAdaptiveOptimizeRequest` - -Sends multiple previous candidates with their speedups for the LLM to learn from and generate better candidates. - -Key fields: -- `candidates: list[AdaptiveOptimizedCandidate]` — Previous candidates with source code, explanation, source type, and speedup - -Returns: candidates with `source=OptimizedCandidateSource.ADAPTIVE` - -### `/ai/rewrite_jit` — JIT Rewrite - -Method: `get_jit_rewritten_code()` - -Rewrites code to use JIT compilation (e.g., Numba). - -Returns: candidates with `source=OptimizedCandidateSource.JIT_REWRITE` - -## Candidate Parsing - -All endpoints return JSON with an `optimizations` array. Each entry has: -- `source_code` — Markdown-formatted code blocks -- `explanation` — LLM explanation -- `optimization_id` — Unique ID -- `parent_id` — Optional parent reference -- `model` — Which LLM model was used - -`_get_valid_candidates()` parses the markdown code via `CodeStringsMarkdown.parse_markdown_code()` and filters out entries with empty code blocks. - -## `LocalAiServiceClient` - -Used when `CODEFLASH_EXPERIMENT_ID` is set. Mirrors `AiServiceClient` but sends to a separate experimental endpoint for A/B testing optimization strategies. - -## LLM Call Sequencing - -`AiServiceClient` tracks call sequence via `llm_call_counter` (itertools.count). Each request includes a `call_sequence` number, used by the backend to maintain conversation context across multiple calls for the same function. diff --git a/tiles/codeflash-docs/docs/configuration.md b/tiles/codeflash-docs/docs/configuration.md deleted file mode 100644 index 32dd8d53d..000000000 --- a/tiles/codeflash-docs/docs/configuration.md +++ /dev/null @@ -1,79 +0,0 @@ -# Configuration - -Key configuration constants, effort levels, and thresholds. - -## Constants (`code_utils/config_consts.py`) - -### Test Execution - -| Constant | Value | Description | -|----------|-------|-------------| -| `MAX_TEST_RUN_ITERATIONS` | 5 | Maximum test loop iterations | -| `INDIVIDUAL_TESTCASE_TIMEOUT` | 15s | Timeout per individual test case | -| `MAX_FUNCTION_TEST_SECONDS` | 60s | Max total time for function testing | -| `MAX_TEST_FUNCTION_RUNS` | 50 | Max test function executions | -| `MAX_CUMULATIVE_TEST_RUNTIME_NANOSECONDS` | 100ms | Max cumulative test runtime | -| `TOTAL_LOOPING_TIME` | 10s | Candidate benchmarking budget | -| `MIN_TESTCASE_PASSED_THRESHOLD` | 6 | Minimum test cases that must pass | - -### Performance Thresholds - -| Constant | Value | Description | -|----------|-------|-------------| -| `MIN_IMPROVEMENT_THRESHOLD` | 0.05 (5%) | Minimum speedup to accept a candidate | -| `MIN_THROUGHPUT_IMPROVEMENT_THRESHOLD` | 0.10 (10%) | Minimum async throughput improvement | -| `MIN_CONCURRENCY_IMPROVEMENT_THRESHOLD` | 0.20 (20%) | Minimum concurrency ratio improvement | -| `COVERAGE_THRESHOLD` | 60.0% | Minimum test coverage | - -### Stability Thresholds - -| Constant | Value | Description | -|----------|-------|-------------| -| `STABILITY_WINDOW_SIZE` | 0.35 | 35% of total iteration window | -| `STABILITY_CENTER_TOLERANCE` | 0.0025 | ±0.25% around median | -| `STABILITY_SPREAD_TOLERANCE` | 0.0025 | 0.25% window spread | - -### Context Limits - -| Constant | Value | Description | -|----------|-------|-------------| -| `OPTIMIZATION_CONTEXT_TOKEN_LIMIT` | 16000 | Max tokens for optimization context | -| `TESTGEN_CONTEXT_TOKEN_LIMIT` | 16000 | Max tokens for test generation context | -| `MAX_CONTEXT_LEN_REVIEW` | 1000 | Max context length for optimization review | - -### Other - -| Constant | Value | Description | -|----------|-------|-------------| -| `MIN_CORRECT_CANDIDATES` | 2 | Min correct candidates before skipping repair | -| `REPEAT_OPTIMIZATION_PROBABILITY` | 0.1 | Probability of re-optimizing a function | -| `DEFAULT_IMPORTANCE_THRESHOLD` | 0.001 | Minimum addressable time to consider a function | -| `CONCURRENCY_FACTOR` | 10 | Number of concurrent executions for concurrency benchmark | -| `REFINED_CANDIDATE_RANKING_WEIGHTS` | (2, 1) | (runtime, diff) weights — runtime 2x more important | - -## Effort Levels - -`EffortLevel` enum: `LOW`, `MEDIUM`, `HIGH` - -Effort controls the number of candidates, repairs, and refinements: - -| Key | LOW | MEDIUM | HIGH | -|-----|-----|--------|------| -| `N_OPTIMIZER_CANDIDATES` | 3 | 5 | 6 | -| `N_OPTIMIZER_LP_CANDIDATES` | 4 | 6 | 7 | -| `N_GENERATED_TESTS` | 2 | 2 | 2 | -| `MAX_CODE_REPAIRS_PER_TRACE` | 2 | 3 | 5 | -| `REPAIR_UNMATCHED_PERCENTAGE_LIMIT` | 0.2 | 0.3 | 0.4 | -| `TOP_VALID_CANDIDATES_FOR_REFINEMENT` | 2 | 3 | 4 | -| `ADAPTIVE_OPTIMIZATION_THRESHOLD` | 0 | 0 | 2 | -| `MAX_ADAPTIVE_OPTIMIZATIONS_PER_TRACE` | 0 | 0 | 4 | - -Use `get_effort_value(EffortKeys.KEY, effort_level)` to retrieve values. - -## Project Configuration - -Configuration is read from `pyproject.toml` under `[tool.codeflash]`. Key settings are auto-detected by `setup/detector.py`: -- `module-root` — Root of the module to optimize -- `tests-root` — Root of test files -- `test-framework` — pytest, unittest, jest, etc. -- `formatter-cmds` — Code formatting commands diff --git a/tiles/codeflash-docs/docs/context-extraction.md b/tiles/codeflash-docs/docs/context-extraction.md deleted file mode 100644 index 8e0f366c9..000000000 --- a/tiles/codeflash-docs/docs/context-extraction.md +++ /dev/null @@ -1,60 +0,0 @@ -# Context Extraction - -How codeflash extracts and limits code context for optimization and test generation. - -## Overview - -Context extraction (`context/code_context_extractor.py`) builds a `CodeOptimizationContext` containing all code needed for the LLM to understand and optimize a function, split into: - -- **Read-writable code** (`CodeContextType.READ_WRITABLE`): The function being optimized plus its helper functions — code the LLM is allowed to modify -- **Read-only context** (`CodeContextType.READ_ONLY`): Dependency code for reference — imports, type definitions, base classes -- **Testgen context** (`CodeContextType.TESTGEN`): Context for test generation, may include imported class definitions and external base class inits -- **Hashing context** (`CodeContextType.HASHING`): Used for deduplication of optimization runs - -## Token Limits - -Both optimization and test generation contexts are token-limited: -- `OPTIMIZATION_CONTEXT_TOKEN_LIMIT = 16000` tokens -- `TESTGEN_CONTEXT_TOKEN_LIMIT = 16000` tokens - -Token counting uses `encoded_tokens_len()` from `code_utils/code_utils.py`. Functions whose context exceeds these limits are skipped. - -## Context Building Process - -### 1. Helper Discovery - -For the target function (`FunctionToOptimize`), the extractor finds: -- **Helpers of the function**: Functions/classes in the same file that the target function calls -- **Helpers of helpers**: Transitive dependencies of the helper functions - -These are organized as `dict[Path, set[FunctionSource]]` — mapping file paths to the set of helper functions found in each file. - -### 2. Code Extraction - -`extract_code_markdown_context_from_files()` builds `CodeStringsMarkdown` from the helper dictionaries. Each file's relevant code is extracted as a `CodeString` with its file path. - -### 3. Testgen Context Enrichment - -`build_testgen_context()` extends the basic context with: -- Imported class definitions (resolved from imports) -- External base class `__init__` methods -- External class `__init__` methods referenced in the context - -### 4. Unused Definition Removal - -`detect_unused_helper_functions()` and `remove_unused_definitions_by_function_names()` from `context/unused_definition_remover.py` prune definitions that are not transitively reachable from the target function, reducing token usage. - -### 5. Deduplication - -The hashing context (`hashing_code_context`) generates a hash (`hashing_code_context_hash`) used to detect when the same function context has already been optimized in a previous run, avoiding redundant work. - -## Key Functions - -| Function | Location | Purpose | -|----------|----------|---------| -| `build_testgen_context()` | `context/code_context_extractor.py` | Build enriched testgen context | -| `extract_code_markdown_context_from_files()` | `context/code_context_extractor.py` | Convert helper dicts to `CodeStringsMarkdown` | -| `detect_unused_helper_functions()` | `context/unused_definition_remover.py` | Find unused definitions | -| `remove_unused_definitions_by_function_names()` | `context/unused_definition_remover.py` | Remove unused definitions | -| `collect_top_level_defs_with_usages()` | `context/unused_definition_remover.py` | Analyze definition usage | -| `encoded_tokens_len()` | `code_utils/code_utils.py` | Count tokens in code | diff --git a/tiles/codeflash-docs/docs/domain-types.md b/tiles/codeflash-docs/docs/domain-types.md deleted file mode 100644 index 7bc2dd868..000000000 --- a/tiles/codeflash-docs/docs/domain-types.md +++ /dev/null @@ -1,153 +0,0 @@ -# Domain Types - -Core data types used throughout the codeflash optimization pipeline. - -## Function Representation - -### `FunctionToOptimize` (`models/function_types.py`) - -The canonical dataclass representing a function candidate for optimization. Works across Python, JavaScript, and TypeScript. - -Key fields: -- `function_name: str` — The function name -- `file_path: Path` — Absolute file path where the function is located -- `parents: list[FunctionParent]` — Parent scopes (classes/functions), each with `name` and `type` -- `starting_line / ending_line: Optional[int]` — Line range (1-indexed) -- `is_async: bool` — Whether the function is async -- `is_method: bool` — Whether it belongs to a class -- `language: str` — Programming language (default: `"python"`) - -Key properties: -- `qualified_name` — Full dotted name including parent classes (e.g., `MyClass.my_method`) -- `top_level_parent_name` — Name of outermost parent, or function name if no parents -- `class_name` — Immediate parent class name, or `None` - -### `FunctionParent` (`models/function_types.py`) - -Represents a parent scope: `name: str` (e.g., `"MyClass"`) and `type: str` (e.g., `"ClassDef"`). - -### `FunctionSource` (`models/models.py`) - -Represents a resolved function with source code. Used for helper functions in context extraction. - -Fields: `file_path`, `qualified_name`, `fully_qualified_name`, `only_function_name`, `source_code`, `jedi_definition`. - -## Code Representation - -### `CodeString` (`models/models.py`) - -A single code block with validated syntax: -- `code: str` — The source code -- `file_path: Optional[Path]` — Origin file path -- `language: str` — Language for validation (default: `"python"`) - -Validates syntax on construction via `model_validator`. - -### `CodeStringsMarkdown` (`models/models.py`) - -A collection of `CodeString` blocks — the primary format for passing code through the pipeline. - -Key properties: -- `.flat` — Combined source code with file-path comment prefixes (e.g., `# file: path/to/file.py`) -- `.markdown` — Markdown-formatted with fenced code blocks: `` ```python:filepath\ncode\n``` `` -- `.file_to_path()` — Dict mapping file path strings to code - -Static method: -- `parse_markdown_code(markdown_code, expected_language)` — Parses markdown code blocks back into `CodeStringsMarkdown` - -## Optimization Context - -### `CodeOptimizationContext` (`models/models.py`) - -Holds all code context needed for optimization: -- `read_writable_code: CodeStringsMarkdown` — Code the LLM can modify -- `read_only_context_code: str` — Reference-only dependency code -- `testgen_context: CodeStringsMarkdown` — Context for test generation -- `hashing_code_context: str` / `hashing_code_context_hash: str` — For deduplication -- `helper_functions: list[FunctionSource]` — Helper functions in the writable code -- `preexisting_objects: set[tuple[str, tuple[FunctionParent, ...]]]` — Objects that already exist in the code - -### `CodeContextType` enum (`models/models.py`) - -Defines context categories: `READ_WRITABLE`, `READ_ONLY`, `TESTGEN`, `HASHING`. - -## Candidates - -### `OptimizedCandidate` (`models/models.py`) - -A generated code variant: -- `source_code: CodeStringsMarkdown` — The optimized code -- `explanation: str` — LLM explanation of the optimization -- `optimization_id: str` — Unique identifier -- `source: OptimizedCandidateSource` — How it was generated -- `parent_id: str | None` — ID of parent candidate (for refinements/repairs) -- `model: str | None` — Which LLM model generated it - -### `OptimizedCandidateSource` enum (`models/models.py`) - -How a candidate was generated: `OPTIMIZE`, `OPTIMIZE_LP` (line profiler), `REFINE`, `REPAIR`, `ADAPTIVE`, `JIT_REWRITE`. - -### `CandidateEvaluationContext` (`models/models.py`) - -Tracks state during candidate evaluation: -- `speedup_ratios` / `optimized_runtimes` / `is_correct` — Per-candidate results -- `ast_code_to_id` — Deduplication map (normalized AST → first seen candidate) -- `valid_optimizations` — Candidates that passed all checks - -Key methods: `record_failed_candidate()`, `record_successful_candidate()`, `handle_duplicate_candidate()`, `register_new_candidate()`. - -## Baseline & Results - -### `OriginalCodeBaseline` (`models/models.py`) - -Baseline measurements for the original code: -- `behavior_test_results: TestResults` / `benchmarking_test_results: TestResults` -- `line_profile_results: dict` -- `runtime: int` — Total runtime in nanoseconds -- `coverage_results: Optional[CoverageData]` - -### `BestOptimization` (`models/models.py`) - -The winning candidate after evaluation: -- `candidate: OptimizedCandidate` -- `helper_functions: list[FunctionSource]` -- `code_context: CodeOptimizationContext` -- `runtime: int` -- `winning_behavior_test_results` / `winning_benchmarking_test_results: TestResults` - -## Test Types - -### `TestType` enum (`models/test_type.py`) - -- `EXISTING_UNIT_TEST` (1) — Pre-existing tests from the codebase -- `INSPIRED_REGRESSION` (2) — Tests inspired by existing tests -- `GENERATED_REGRESSION` (3) — AI-generated regression tests -- `REPLAY_TEST` (4) — Tests from recorded benchmark data -- `CONCOLIC_COVERAGE_TEST` (5) — Coverage-guided tests -- `INIT_STATE_TEST` (6) — Class init state verification - -### `TestFile` / `TestFiles` (`models/models.py`) - -`TestFile` represents a single test file with `instrumented_behavior_file_path`, optional `benchmarking_file_path`, `original_file_path`, `test_type`, and `tests_in_file`. - -`TestFiles` is a collection with lookup methods: `get_by_type()`, `get_by_original_file_path()`, `get_test_type_by_instrumented_file_path()`. - -### `TestResults` (`models/models.py`) - -Collection of `FunctionTestInvocation` results with indexed lookup. Key methods: -- `add(invocation)` — Deduplicated insert -- `total_passed_runtime()` — Sum of minimum runtimes per test case (nanoseconds) -- `number_of_loops()` — Max loop index across all results -- `usable_runtime_data_by_test_case()` — Dict of invocation ID → list of runtimes - -## Result Type - -### `Result[L, R]` / `Success` / `Failure` (`either.py`) - -Functional error handling type: -- `Success(value)` — Wraps a successful result -- `Failure(error)` — Wraps an error -- `result.is_successful()` / `result.is_failure()` — Check type -- `result.unwrap()` — Get success value (raises if Failure) -- `result.failure()` — Get failure value (raises if Success) -- `is_successful(result)` — Module-level helper function diff --git a/tiles/codeflash-docs/docs/index.md b/tiles/codeflash-docs/docs/index.md deleted file mode 100644 index 930e287eb..000000000 --- a/tiles/codeflash-docs/docs/index.md +++ /dev/null @@ -1,41 +0,0 @@ -# Codeflash Internal Documentation - -CodeFlash is an AI-powered Python code optimizer that automatically improves code performance while maintaining correctness. It uses LLMs to generate optimization candidates, verifies correctness through test execution, and benchmarks performance improvements. - -## Pipeline Overview - -``` -Discovery → Ranking → Context Extraction → Test Gen + Optimization → Baseline → Candidate Evaluation → PR -``` - -1. **Discovery** (`discovery/`): Find optimizable functions across the codebase using `FunctionVisitor` -2. **Ranking** (`benchmarking/function_ranker.py`): Rank functions by addressable time using trace data -3. **Context** (`context/`): Extract code dependencies — split into read-writable (modifiable) and read-only (reference) -4. **Optimization** (`optimization/`, `api/`): Generate candidates via AI service, runs concurrently with test generation -5. **Verification** (`verification/`): Run candidates against tests via custom pytest plugin, compare outputs -6. **Benchmarking** (`benchmarking/`): Measure performance, select best candidate by speedup -7. **Result** (`result/`, `github/`): Create PR with winning optimization - -## Key Entry Points - -| Task | File | -|------|------| -| CLI arguments & commands | `cli_cmds/cli.py` | -| Optimization orchestration | `optimization/optimizer.py` → `Optimizer.run()` | -| Per-function optimization | `optimization/function_optimizer.py` → `FunctionOptimizer` | -| Function discovery | `discovery/functions_to_optimize.py` | -| Context extraction | `context/code_context_extractor.py` | -| Test execution | `verification/test_runner.py`, `verification/pytest_plugin.py` | -| Performance ranking | `benchmarking/function_ranker.py` | -| Domain types | `models/models.py`, `models/function_types.py` | -| AI service | `api/aiservice.py` → `AiServiceClient` | -| Configuration | `code_utils/config_consts.py` | - -## Documentation Pages - -- [Domain Types](domain-types.md) — Core data types and their relationships -- [Optimization Pipeline](optimization-pipeline.md) — Step-by-step data flow through the pipeline -- [Context Extraction](context-extraction.md) — How code context is extracted and token-limited -- [Verification](verification.md) — Test execution, pytest plugin, deterministic patches -- [AI Service](ai-service.md) — AI service client endpoints and request types -- [Configuration](configuration.md) — Config schema, effort levels, thresholds diff --git a/tiles/codeflash-docs/docs/optimization-pipeline.md b/tiles/codeflash-docs/docs/optimization-pipeline.md deleted file mode 100644 index 9a3879ccc..000000000 --- a/tiles/codeflash-docs/docs/optimization-pipeline.md +++ /dev/null @@ -1,84 +0,0 @@ -# Optimization Pipeline - -Step-by-step data flow from function discovery to PR creation. - -## 1. Entry Point: `Optimizer.run()` (`optimization/optimizer.py`) - -The `Optimizer` class is initialized with CLI args and creates: -- `TestConfig` with test roots, project root, pytest command -- `AiServiceClient` for AI service communication -- Optional `LocalAiServiceClient` for experiments - -`run()` orchestrates the full pipeline: discovers functions, optionally ranks them, then optimizes each in turn. - -## 2. Function Discovery (`discovery/functions_to_optimize.py`) - -`FunctionVisitor` traverses source files to find optimizable functions, producing `FunctionToOptimize` instances. Filters include: -- Skipping functions that are too small or trivial -- Skipping previously optimized functions (via `was_function_previously_optimized()`) -- Applying user-configured include/exclude patterns - -## 3. Function Ranking (`benchmarking/function_ranker.py`) - -When trace data is available, `FunctionRanker` ranks functions by **addressable time** — the time a function spends that could be optimized (own time + callee time / call count). Functions below `DEFAULT_IMPORTANCE_THRESHOLD=0.001` are skipped. - -## 4. Per-Function Optimization: `FunctionOptimizer` (`optimization/function_optimizer.py`) - -For each function, `FunctionOptimizer.optimize_function()` runs the full optimization loop: - -### 4a. Context Extraction (`context/code_context_extractor.py`) - -Extracts `CodeOptimizationContext` containing: -- `read_writable_code` — Code the LLM can modify (the function + helpers) -- `read_only_context_code` — Dependency code for reference only -- `testgen_context` — Context for test generation (may include imported class definitions) - -Token limits are enforced: `OPTIMIZATION_CONTEXT_TOKEN_LIMIT=16000` and `TESTGEN_CONTEXT_TOKEN_LIMIT=16000`. Functions exceeding these are rejected. - -### 4b. Concurrent Test Generation + LLM Optimization - -These run in parallel using `concurrent.futures`: -- **Test generation**: Generates regression tests from the function context -- **LLM optimization**: Sends `read_writable_code.markdown` + `read_only_context_code` to the AI service - -The number of candidates depends on effort level (see Configuration docs). - -### 4c. Candidate Evaluation - -For each `OptimizedCandidate`: - -1. **Deduplication**: Normalize code AST and check against `CandidateEvaluationContext.ast_code_to_id`. If duplicate, copy results from previous evaluation. - -2. **Code replacement**: Replace the original function with the candidate using `replace_function_definitions_in_module()`. - -3. **Behavioral testing**: Run instrumented tests in subprocess. The custom pytest plugin applies deterministic patches. Compare return values, stdout, and pass/fail status against the original baseline. - -4. **Benchmarking**: If behavior matches, run performance tests with looping (`TOTAL_LOOPING_TIME=10s`). Calculate speedup ratio. - -5. **Validation**: Candidate must beat `MIN_IMPROVEMENT_THRESHOLD=0.05` (5% speedup) and pass stability checks. - -### 4d. Refinement & Repair - -- **Repair**: If fewer than `MIN_CORRECT_CANDIDATES=2` pass, failed candidates can be repaired via `AIServiceCodeRepairRequest` (sends test diffs to LLM). -- **Refinement**: Top valid candidates are refined via `AIServiceRefinerRequest` (sends runtime data, line profiler results). -- **Adaptive**: At HIGH effort, additional adaptive optimization rounds via `AIServiceAdaptiveOptimizeRequest`. - -### 4e. Best Candidate Selection - -The winning candidate is selected by: -1. Highest speedup ratio -2. For tied speedups, shortest diff length from original -3. Refinement candidates use weighted ranking: `(2 * runtime_rank + 1 * diff_rank)` - -Result is a `BestOptimization` with the candidate, context, test results, and runtime. - -## 5. PR Creation (`github/`) - -If a winning candidate is found, a PR is created with: -- The optimized code diff -- Performance benchmark details -- Explanation from the LLM - -## Worktree Mode - -When `--worktree` is enabled, optimization runs in an isolated git worktree (`code_utils/git_worktree_utils.py`). This allows parallel optimization without affecting the working tree. Changes are captured as patch files. diff --git a/tiles/codeflash-docs/docs/verification.md b/tiles/codeflash-docs/docs/verification.md deleted file mode 100644 index 2a84f9340..000000000 --- a/tiles/codeflash-docs/docs/verification.md +++ /dev/null @@ -1,93 +0,0 @@ -# Verification - -How codeflash verifies candidate correctness and measures performance. - -## Test Execution Architecture - -Tests are executed in a **subprocess** to isolate the test environment from the main codeflash process. The test runner (`verification/test_runner.py`) invokes pytest (or Jest for JS/TS) with specific plugin configurations. - -### Plugin Blocklists - -- **Behavioral tests**: Block `benchmark`, `codspeed`, `xdist`, `sugar` -- **Benchmarking tests**: Block `codspeed`, `cov`, `benchmark`, `profiling`, `xdist`, `sugar` - -These are defined as `BEHAVIORAL_BLOCKLISTED_PLUGINS` and `BENCHMARKING_BLOCKLISTED_PLUGINS` in `verification/test_runner.py`. - -## Custom Pytest Plugin (`verification/pytest_plugin.py`) - -The plugin is loaded into the test subprocess and provides: - -### Deterministic Patches - -`_apply_deterministic_patches()` replaces non-deterministic functions with fixed values to ensure reproducible test output: - -| Module | Function | Fixed Value | -|--------|----------|-------------| -| `time` | `time()` | `1761717605.108106` | -| `time` | `perf_counter()` | Incrementing by 1ms per call | -| `datetime` | `datetime.now()` | `2021-01-01 02:05:10 UTC` | -| `datetime` | `datetime.utcnow()` | `2021-01-01 02:05:10 UTC` | -| `uuid` | `uuid4()` / `uuid1()` | `12345678-1234-5678-9abc-123456789012` | -| `random` | `random()` | `0.123456789` (seeded with 42) | -| `os` | `urandom(n)` | `b"\x42" * n` | -| `numpy.random` | seed | `42` | - -Patches call the original function first to maintain performance characteristics (same call overhead). - -### Timing Markers - -Test results include timing markers in stdout: `!######:######!` - -The pattern `_TIMING_MARKER_PATTERN` extracts timing data for calculating function utilization fraction. - -### Loop Stability - -Performance benchmarking uses configurable stability thresholds: -- `STABILITY_WINDOW_SIZE = 0.35` (35% of total iterations) -- `STABILITY_CENTER_TOLERANCE = 0.0025` (±0.25% around median) -- `STABILITY_SPREAD_TOLERANCE = 0.0025` (0.25% window spread) - -### Memory Limits (Linux) - -On Linux, the plugin sets `RLIMIT_AS` to 85% of total system memory (RAM + swap) to prevent OOM kills. - -## Test Result Processing - -### `TestResults` (`models/models.py`) - -Collects `FunctionTestInvocation` results with: -- Deduplicated insertion via `unique_invocation_loop_id` -- `total_passed_runtime()` — Sum of minimum runtimes per test case (nanoseconds) -- `number_of_loops()` — Max loop index -- `usable_runtime_data_by_test_case()` — Grouped timing data - -### `FunctionTestInvocation` - -Each invocation records: -- `loop_index` — Iteration number (starts at 1) -- `id: InvocationId` — Fully qualified test identifier -- `did_pass: bool` — Pass/fail status -- `runtime: Optional[int]` — Time in nanoseconds -- `return_value: Optional[object]` — Captured return value -- `test_type: TestType` — Which test category - -### Behavioral vs Performance Testing - -1. **Behavioral**: Runs with `TestingMode.BEHAVIOR`. Compares return values and stdout between original and candidate. Any difference = candidate rejected. -2. **Performance**: Runs with `TestingMode.PERFORMANCE`. Loops for `TOTAL_LOOPING_TIME=10s` to get stable timing. Calculates speedup ratio. -3. **Line Profile**: Runs with `TestingMode.LINE_PROFILE`. Collects per-line timing data for refinement. - -## Test Types - -| TestType | Value | Description | -|----------|-------|-------------| -| `EXISTING_UNIT_TEST` | 1 | Pre-existing tests from the codebase | -| `INSPIRED_REGRESSION` | 2 | Tests inspired by existing tests | -| `GENERATED_REGRESSION` | 3 | AI-generated regression tests | -| `REPLAY_TEST` | 4 | Tests from recorded benchmark data | -| `CONCOLIC_COVERAGE_TEST` | 5 | Coverage-guided tests | -| `INIT_STATE_TEST` | 6 | Class init state verification | - -## Coverage - -Coverage is measured via `CoverageData` with a threshold of `COVERAGE_THRESHOLD=60.0%`. Low coverage may affect confidence in the optimization's correctness. diff --git a/tiles/codeflash-docs/evals/capabilities.json b/tiles/codeflash-docs/evals/capabilities.json deleted file mode 100644 index 1e39768a4..000000000 --- a/tiles/codeflash-docs/evals/capabilities.json +++ /dev/null @@ -1,118 +0,0 @@ -{ - "package_name": "codeflash-docs", - "total_capabilities": 16, - "capabilities": [ - { - "id": 0, - "name": "pipeline-stage-ordering", - "description": "Know the correct ordering of codeflash pipeline stages: Discovery → Ranking → Context Extraction → Test Gen + Optimization (concurrent) → Baseline → Candidate Evaluation → PR", - "complexity": "basic", - "api_elements": ["Optimizer.run()", "FunctionOptimizer.optimize_function()"] - }, - { - "id": 1, - "name": "function-to-optimize-fields", - "description": "Know FunctionToOptimize key fields (function_name, file_path, parents, starting_line/ending_line, is_async, is_method, language) and properties (qualified_name, top_level_parent_name, class_name)", - "complexity": "intermediate", - "api_elements": ["FunctionToOptimize", "FunctionParent", "models/function_types.py"] - }, - { - "id": 2, - "name": "code-strings-markdown-format", - "description": "Know that code is serialized as markdown fenced blocks with language:filepath syntax (```python:filepath\\ncode\\n```) and parsed via CodeStringsMarkdown.parse_markdown_code()", - "complexity": "intermediate", - "api_elements": ["CodeStringsMarkdown", "CodeString", ".markdown", ".flat", "parse_markdown_code()"] - }, - { - "id": 3, - "name": "read-writable-vs-read-only", - "description": "Distinguish read_writable_code (LLM can modify) from read_only_context_code (reference only) in CodeOptimizationContext", - "complexity": "basic", - "api_elements": ["CodeOptimizationContext", "read_writable_code", "read_only_context_code"] - }, - { - "id": 4, - "name": "candidate-source-types", - "description": "Know OptimizedCandidateSource variants: OPTIMIZE, OPTIMIZE_LP, REFINE, REPAIR, ADAPTIVE, JIT_REWRITE and when each is used", - "complexity": "intermediate", - "api_elements": ["OptimizedCandidateSource", "OptimizedCandidate"] - }, - { - "id": 5, - "name": "candidate-forest-dag", - "description": "Know that candidates form a forest/DAG via parent_id references where refinements and repairs build on previous candidates", - "complexity": "intermediate", - "api_elements": ["parent_id", "OptimizedCandidate", "CandidateForest"] - }, - { - "id": 6, - "name": "concurrent-testgen-optimization", - "description": "Know that test generation and LLM optimization run concurrently using concurrent.futures, not sequentially", - "complexity": "intermediate", - "api_elements": ["concurrent.futures", "FunctionOptimizer.optimize_function()"] - }, - { - "id": 7, - "name": "deterministic-patch-values", - "description": "Know the specific fixed values used by deterministic patches: time=1761717605.108106, datetime=2021-01-01 02:05:10 UTC, uuid=12345678-1234-5678-9abc-123456789012, random seeded with 42", - "complexity": "advanced", - "api_elements": ["_apply_deterministic_patches()", "pytest_plugin.py"] - }, - { - "id": 8, - "name": "test-type-enum", - "description": "Know the 6 TestType variants: EXISTING_UNIT_TEST, INSPIRED_REGRESSION, GENERATED_REGRESSION, REPLAY_TEST, CONCOLIC_COVERAGE_TEST, INIT_STATE_TEST", - "complexity": "basic", - "api_elements": ["TestType", "models/test_type.py"] - }, - { - "id": 9, - "name": "ai-service-endpoints", - "description": "Know the AI service endpoints: /ai/optimize, /ai/optimize_line_profiler, /ai/refine, /ai/repair, /ai/adaptive_optimize, /ai/rewrite_jit", - "complexity": "intermediate", - "api_elements": ["AiServiceClient", "api/aiservice.py"] - }, - { - "id": 10, - "name": "repair-request-structure", - "description": "Know that AIServiceCodeRepairRequest includes TestDiff objects with scope (RETURN_VALUE/STDOUT/DID_PASS), original vs candidate values, and test source code", - "complexity": "advanced", - "api_elements": ["AIServiceCodeRepairRequest", "TestDiff", "TestDiffScope"] - }, - { - "id": 11, - "name": "effort-level-values", - "description": "Know specific effort level values: LOW gets 3 candidates, MEDIUM gets 5, HIGH gets 6 (N_OPTIMIZER_CANDIDATES)", - "complexity": "intermediate", - "api_elements": ["EffortLevel", "N_OPTIMIZER_CANDIDATES", "EFFORT_VALUES"] - }, - { - "id": 12, - "name": "context-token-limits", - "description": "Know OPTIMIZATION_CONTEXT_TOKEN_LIMIT=16000 and TESTGEN_CONTEXT_TOKEN_LIMIT=16000 and that encoded_tokens_len() is used for counting", - "complexity": "basic", - "api_elements": ["OPTIMIZATION_CONTEXT_TOKEN_LIMIT", "TESTGEN_CONTEXT_TOKEN_LIMIT", "encoded_tokens_len()"] - }, - { - "id": 13, - "name": "best-candidate-selection", - "description": "Know the selection criteria: highest speedup, then shortest diff for ties, and refinement weighted ranking (2*runtime + 1*diff)", - "complexity": "advanced", - "api_elements": ["BestOptimization", "REFINED_CANDIDATE_RANKING_WEIGHTS"] - }, - { - "id": 14, - "name": "plugin-blocklists", - "description": "Know behavioral test blocklisted plugins (benchmark, codspeed, xdist, sugar) and benchmarking blocklist (adds cov, profiling)", - "complexity": "intermediate", - "api_elements": ["BEHAVIORAL_BLOCKLISTED_PLUGINS", "BENCHMARKING_BLOCKLISTED_PLUGINS"] - }, - { - "id": 15, - "name": "result-type-usage", - "description": "Know that Result[L,R] from either.py uses Success(value)/Failure(error) with is_successful() check before unwrap()", - "complexity": "basic", - "api_elements": ["Result", "Success", "Failure", "is_successful", "either.py"] - } - ] -} diff --git a/tiles/codeflash-docs/evals/scenario-1/capability.txt b/tiles/codeflash-docs/evals/scenario-1/capability.txt deleted file mode 100644 index 5bd3f0115..000000000 --- a/tiles/codeflash-docs/evals/scenario-1/capability.txt +++ /dev/null @@ -1 +0,0 @@ -Code serialization format and context splitting \ No newline at end of file diff --git a/tiles/codeflash-docs/evals/scenario-1/criteria.json b/tiles/codeflash-docs/evals/scenario-1/criteria.json deleted file mode 100644 index 48a4eb178..000000000 --- a/tiles/codeflash-docs/evals/scenario-1/criteria.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "context": "Tests whether the agent knows the CodeStringsMarkdown serialization format and the distinction between read-writable and read-only code context in the codeflash pipeline.", - "type": "weighted_checklist", - "checklist": [ - { - "name": "Markdown code block format", - "description": "Uses the correct fenced code block format with language:filepath syntax (```python:path/to/file.py) when constructing code for the AI service, NOT plain code blocks without file paths", - "max_score": 30 - }, - { - "name": "Read-writable vs read-only split", - "description": "Correctly separates code into read_writable_code (code the LLM can modify) and read_only_context_code (reference-only dependency code), NOT treating all code as modifiable", - "max_score": 35 - }, - { - "name": "parse_markdown_code usage", - "description": "Uses CodeStringsMarkdown.parse_markdown_code() to parse AI service responses back into structured code, NOT manual string splitting or regex", - "max_score": 35 - } - ] -} diff --git a/tiles/codeflash-docs/evals/scenario-1/task.md b/tiles/codeflash-docs/evals/scenario-1/task.md deleted file mode 100644 index 93761be4b..000000000 --- a/tiles/codeflash-docs/evals/scenario-1/task.md +++ /dev/null @@ -1,35 +0,0 @@ -# Format Code for AI Service Request - -## Context - -You are working on the codeflash optimization engine. The AI service accepts optimization requests with source code and dependency context. A function `calculate_total` in `analytics/metrics.py` needs to be optimized. It calls a helper `normalize_values` in the same file (both modifiable), and imports `BaseMetric` from `analytics/base.py` (not modifiable, just for reference). - -```python -# analytics/metrics.py -from analytics.base import BaseMetric - -def normalize_values(data: list[float]) -> list[float]: - max_val = max(data) - return [x / max_val for x in data] - -def calculate_total(metrics: list[BaseMetric]) -> float: - values = [m.value for m in metrics] - normalized = normalize_values(values) - return sum(normalized) -``` - -```python -# analytics/base.py -class BaseMetric: - def __init__(self, name: str, value: float): - self.name = name - self.value = value -``` - -## Task - -Write a Python function `prepare_optimization_payload` that constructs the code payload for an AI service optimization request for `calculate_total`. It should properly format the source code and dependency code, and include a function to parse the AI service response back into structured code objects. - -## Expected Outputs - -- A Python file `payload_builder.py` with the payload construction and response parsing logic diff --git a/tiles/codeflash-docs/evals/scenario-2/capability.txt b/tiles/codeflash-docs/evals/scenario-2/capability.txt deleted file mode 100644 index 5afa5a2e4..000000000 --- a/tiles/codeflash-docs/evals/scenario-2/capability.txt +++ /dev/null @@ -1 +0,0 @@ -Candidate source types and DAG relationships \ No newline at end of file diff --git a/tiles/codeflash-docs/evals/scenario-2/criteria.json b/tiles/codeflash-docs/evals/scenario-2/criteria.json deleted file mode 100644 index 8460c1420..000000000 --- a/tiles/codeflash-docs/evals/scenario-2/criteria.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "context": "Tests whether the agent knows the different OptimizedCandidateSource types and how candidates form a DAG via parent_id references in the codeflash pipeline.", - "type": "weighted_checklist", - "checklist": [ - { - "name": "Lists source types", - "description": "Identifies at least 4 of the 6 OptimizedCandidateSource variants: OPTIMIZE, OPTIMIZE_LP, REFINE, REPAIR, ADAPTIVE, JIT_REWRITE", - "max_score": 25 - }, - { - "name": "Parent ID linkage", - "description": "Explains that REFINE and REPAIR candidates reference their parent via parent_id, creating a DAG/forest structure, NOT independent candidates", - "max_score": 25 - }, - { - "name": "Refinement uses runtime data", - "description": "States that refinement sends runtime data and line profiler results to the AI service (AIServiceRefinerRequest), NOT just the source code", - "max_score": 25 - }, - { - "name": "Repair uses test diffs", - "description": "States that repair sends test failure diffs (TestDiff with scope: RETURN_VALUE/STDOUT/DID_PASS) to the AI service, NOT just error messages", - "max_score": 25 - } - ] -} diff --git a/tiles/codeflash-docs/evals/scenario-2/task.md b/tiles/codeflash-docs/evals/scenario-2/task.md deleted file mode 100644 index f55b25e3e..000000000 --- a/tiles/codeflash-docs/evals/scenario-2/task.md +++ /dev/null @@ -1,13 +0,0 @@ -# Document the Candidate Lifecycle - -## Context - -A new engineer is joining the codeflash team and needs to understand how optimization candidates are generated, improved, and related to each other throughout the pipeline. They've asked for a clear explanation of the different ways candidates are produced and how the system iterates on them. - -## Task - -Write a technical document explaining the full lifecycle of an optimization candidate in codeflash — from initial generation through improvement iterations. Cover all the different ways candidates can be created, what data is sent to the AI service for each type, and how candidates relate to each other structurally. - -## Expected Outputs - -- A markdown file `candidate-lifecycle.md` diff --git a/tiles/codeflash-docs/evals/scenario-3/capability.txt b/tiles/codeflash-docs/evals/scenario-3/capability.txt deleted file mode 100644 index 707dd8109..000000000 --- a/tiles/codeflash-docs/evals/scenario-3/capability.txt +++ /dev/null @@ -1 +0,0 @@ -Deterministic patch values and test execution architecture \ No newline at end of file diff --git a/tiles/codeflash-docs/evals/scenario-3/criteria.json b/tiles/codeflash-docs/evals/scenario-3/criteria.json deleted file mode 100644 index bf5c9f34f..000000000 --- a/tiles/codeflash-docs/evals/scenario-3/criteria.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "context": "Tests whether the agent knows the specific deterministic patch values used in codeflash's pytest plugin and the subprocess-based test execution architecture.", - "type": "weighted_checklist", - "checklist": [ - { - "name": "Subprocess isolation", - "description": "States that tests run in a subprocess to isolate the test environment from the main codeflash process, NOT in the same process", - "max_score": 20 - }, - { - "name": "Fixed time value", - "description": "References the specific fixed timestamp 1761717605.108106 for time.time() or the fixed datetime 2021-01-01 02:05:10 UTC for datetime.now()", - "max_score": 20 - }, - { - "name": "Fixed UUID value", - "description": "References the specific fixed UUID 12345678-1234-5678-9abc-123456789012 for uuid4/uuid1", - "max_score": 20 - }, - { - "name": "Random seed", - "description": "States that random is seeded with 42 (NOT a different seed value)", - "max_score": 20 - }, - { - "name": "Plugin blocklists", - "description": "Mentions that behavioral tests block specific pytest plugins (at least 2 of: benchmark, codspeed, xdist, sugar) to ensure deterministic execution", - "max_score": 20 - } - ] -} diff --git a/tiles/codeflash-docs/evals/scenario-3/task.md b/tiles/codeflash-docs/evals/scenario-3/task.md deleted file mode 100644 index b3970b839..000000000 --- a/tiles/codeflash-docs/evals/scenario-3/task.md +++ /dev/null @@ -1,13 +0,0 @@ -# Explain Test Reproducibility Guarantees - -## Context - -A codeflash user notices that their optimization candidate passes behavioral tests on one run but fails on the next. They suspect non-determinism in the test execution. They want to understand what guarantees codeflash provides for test reproducibility and how the system ensures consistent results. - -## Task - -Write a technical explanation of how codeflash ensures deterministic test execution. Cover the execution environment setup, what sources of non-determinism are controlled, and any specific values or configurations used. Also explain the test execution architecture. - -## Expected Outputs - -- A markdown file `test-reproducibility.md` diff --git a/tiles/codeflash-docs/evals/scenario-4/capability.txt b/tiles/codeflash-docs/evals/scenario-4/capability.txt deleted file mode 100644 index 64848618a..000000000 --- a/tiles/codeflash-docs/evals/scenario-4/capability.txt +++ /dev/null @@ -1 +0,0 @@ -Effort level configuration and candidate selection criteria \ No newline at end of file diff --git a/tiles/codeflash-docs/evals/scenario-4/criteria.json b/tiles/codeflash-docs/evals/scenario-4/criteria.json deleted file mode 100644 index 4fdc078ae..000000000 --- a/tiles/codeflash-docs/evals/scenario-4/criteria.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "context": "Tests whether the agent knows the specific effort level values for candidate generation and the criteria used to select the best optimization candidate.", - "type": "weighted_checklist", - "checklist": [ - { - "name": "Candidate counts by effort", - "description": "States correct N_OPTIMIZER_CANDIDATES values: LOW=3, MEDIUM=5, HIGH=6 (at least 2 of 3 correct)", - "max_score": 25 - }, - { - "name": "Speedup as primary selector", - "description": "States that the winning candidate is selected primarily by highest speedup ratio", - "max_score": 25 - }, - { - "name": "Diff length as tiebreaker", - "description": "States that for tied speedups, shortest diff length from original is used as tiebreaker", - "max_score": 25 - }, - { - "name": "Refinement ranking weights", - "description": "States that refinement candidates use weighted ranking with runtime weighted more heavily than diff (2:1 ratio or REFINED_CANDIDATE_RANKING_WEIGHTS=(2,1))", - "max_score": 25 - } - ] -} diff --git a/tiles/codeflash-docs/evals/scenario-4/task.md b/tiles/codeflash-docs/evals/scenario-4/task.md deleted file mode 100644 index e44e2738d..000000000 --- a/tiles/codeflash-docs/evals/scenario-4/task.md +++ /dev/null @@ -1,18 +0,0 @@ -# Design a Candidate Selection Dashboard - -## Context - -The codeflash team wants to build a dashboard that shows users how optimization candidates were evaluated and why a particular candidate won. The dashboard needs to display the selection process at each stage, from initial candidate pool through to the final winner. - -## Task - -Write a specification document for the dashboard that explains: -1. How many candidates are generated at each effort level -2. The exact criteria and order of operations used to pick the winning candidate -3. How refinement candidates are ranked differently from initial candidates - -Include concrete examples showing how two hypothetical candidates would be compared. - -## Expected Outputs - -- A markdown file `selection-dashboard-spec.md` diff --git a/tiles/codeflash-docs/evals/scenario-5/capability.txt b/tiles/codeflash-docs/evals/scenario-5/capability.txt deleted file mode 100644 index 0ec01e24f..000000000 --- a/tiles/codeflash-docs/evals/scenario-5/capability.txt +++ /dev/null @@ -1 +0,0 @@ -Pipeline concurrency and FunctionToOptimize structure \ No newline at end of file diff --git a/tiles/codeflash-docs/evals/scenario-5/criteria.json b/tiles/codeflash-docs/evals/scenario-5/criteria.json deleted file mode 100644 index 13887ac34..000000000 --- a/tiles/codeflash-docs/evals/scenario-5/criteria.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "context": "Tests whether the agent knows the FunctionToOptimize data structure and the concurrent execution model for test generation and optimization.", - "type": "weighted_checklist", - "checklist": [ - { - "name": "FunctionToOptimize fields", - "description": "Includes at least 4 of: function_name, file_path, parents (list of FunctionParent), starting_line, ending_line, is_async, is_method, language", - "max_score": 25 - }, - { - "name": "Qualified name property", - "description": "Mentions qualified_name as a property that produces the full dotted name including parent classes (e.g., MyClass.my_method)", - "max_score": 25 - }, - { - "name": "Concurrent execution", - "description": "States that test generation and LLM optimization run concurrently (in parallel), NOT sequentially one after the other", - "max_score": 25 - }, - { - "name": "Entry point identification", - "description": "Correctly identifies Optimizer.run() as the top-level entry point and FunctionOptimizer.optimize_function() as the per-function entry point", - "max_score": 25 - } - ] -} diff --git a/tiles/codeflash-docs/evals/scenario-5/task.md b/tiles/codeflash-docs/evals/scenario-5/task.md deleted file mode 100644 index 42cb34653..000000000 --- a/tiles/codeflash-docs/evals/scenario-5/task.md +++ /dev/null @@ -1,17 +0,0 @@ -# Implement a Function Optimization Status Tracker - -## Context - -The codeflash team needs a status tracker that logs what happens to each function during an optimization run. For each function, it should record the function identity, which pipeline stages it passed through, and how long each stage took. - -## Task - -Write a design document explaining: -1. What data structure represents a function being optimized, including its identity fields and how nested functions (methods inside classes) are represented -2. The full name resolution strategy for identifying functions uniquely -3. Which stages of the pipeline operate on a single function at a time vs. operating on multiple functions -4. Where in the codebase the per-function optimization is orchestrated and what the top-level entry point is - -## Expected Outputs - -- A markdown file `status-tracker-design.md` diff --git a/tiles/codeflash-docs/evals/summary.json b/tiles/codeflash-docs/evals/summary.json deleted file mode 100644 index 38e0ca577..000000000 --- a/tiles/codeflash-docs/evals/summary.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "total_scenarios": 5, - "capabilities_coverage": { - "total_capabilities": 16, - "capabilities_tested": 12, - "coverage_percentage": 75.0 - }, - "complexity_distribution": { - "basic": 1, - "intermediate": 3, - "advanced": 1 - }, - "scenarios": [ - { - "index": 1, - "capability": "code-strings-markdown-format, read-writable-vs-read-only", - "complexity": "intermediate" - }, - { - "index": 2, - "capability": "candidate-source-types, candidate-forest-dag, repair-request-structure", - "complexity": "intermediate" - }, - { - "index": 3, - "capability": "deterministic-patch-values, plugin-blocklists", - "complexity": "advanced" - }, - { - "index": 4, - "capability": "effort-level-values, best-candidate-selection", - "complexity": "intermediate" - }, - { - "index": 5, - "capability": "function-to-optimize-fields, concurrent-testgen-optimization, pipeline-stage-ordering", - "complexity": "basic" - } - ] -} diff --git a/tiles/codeflash-docs/evals/summary_infeasible.json b/tiles/codeflash-docs/evals/summary_infeasible.json deleted file mode 100644 index 7450bd0b1..000000000 --- a/tiles/codeflash-docs/evals/summary_infeasible.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "total_infeasible": 4, - "infeasible_capabilities": [ - { - "capability": "ai-service-endpoints", - "complexity": "intermediate", - "reasoning": "Testing knowledge of specific API endpoints requires actual HTTP requests or mocking that bypasses the capability being tested" - }, - { - "capability": "context-token-limits", - "complexity": "basic", - "reasoning": "Already covered by the skills tile eval (scenario-1). Testing token counting requires the actual tokenizer library" - }, - { - "capability": "test-type-enum", - "complexity": "basic", - "reasoning": "Simple enum knowledge is better verified through skills that use test types rather than isolated recall" - }, - { - "capability": "result-type-usage", - "complexity": "basic", - "reasoning": "Already covered by the skills tile eval (scenario-2). Testing Result type usage is better done through implementation tasks" - } - ] -} diff --git a/tiles/codeflash-docs/tile.json b/tiles/codeflash-docs/tile.json deleted file mode 100644 index 8d18aa129..000000000 --- a/tiles/codeflash-docs/tile.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "codeflash/codeflash-docs", - "version": "0.1.0", - "summary": "Internal documentation for the codeflash optimization engine", - "private": true, - "docs": "docs/index.md" -} diff --git a/tiles/codeflash-rules/rules/architecture.md b/tiles/codeflash-rules/rules/architecture.md deleted file mode 100644 index 3aaf78507..000000000 --- a/tiles/codeflash-rules/rules/architecture.md +++ /dev/null @@ -1,45 +0,0 @@ -# Architecture - -``` -codeflash/ -├── main.py # CLI entry point -├── cli_cmds/ # Command handling, console output (Rich) -├── discovery/ # Find optimizable functions -├── context/ # Extract code dependencies and imports -├── optimization/ # Generate optimized code via AI -│ ├── optimizer.py # Main optimization orchestration -│ └── function_optimizer.py # Per-function optimization logic -├── verification/ # Run deterministic tests (pytest plugin) -├── benchmarking/ # Performance measurement -├── github/ # PR creation -├── api/ # AI service communication -├── code_utils/ # Code parsing, git utilities -├── models/ # Pydantic models and types -├── languages/ # Multi-language support (Python, JavaScript/TypeScript) -├── setup/ # Config schema, auto-detection, first-run experience -├── picklepatch/ # Serialization/deserialization utilities -├── tracing/ # Function call tracing -├── tracer.py # Root-level tracer entry point for profiling -├── lsp/ # IDE integration (Language Server Protocol) -├── telemetry/ # Sentry, PostHog -├── either.py # Functional Result type for error handling -├── result/ # Result types and handling -└── version.py # Version information -``` - -## Key Entry Points - -| Task | Start here | -|------|------------| -| CLI arguments & commands | `cli_cmds/cli.py` | -| Optimization orchestration | `optimization/optimizer.py` → `Optimizer.run()` | -| Per-function optimization | `optimization/function_optimizer.py` → `FunctionOptimizer` | -| Function discovery | `discovery/functions_to_optimize.py` | -| Context extraction | `context/code_context_extractor.py` | -| Test execution | `verification/test_runner.py`, `verification/pytest_plugin.py` | -| Performance ranking | `benchmarking/function_ranker.py` | -| Domain types | `models/models.py`, `models/function_types.py` | -| Result handling | `either.py` (`Result`, `Success`, `Failure`, `is_successful`) | -| AI service communication | `api/aiservice.py` → `AiServiceClient` | -| Configuration constants | `code_utils/config_consts.py` | -| Language support | `languages/registry.py` → `get_language_support()` | diff --git a/tiles/codeflash-rules/rules/code-style.md b/tiles/codeflash-rules/rules/code-style.md deleted file mode 100644 index 2a2fbdf6b..000000000 --- a/tiles/codeflash-rules/rules/code-style.md +++ /dev/null @@ -1,11 +0,0 @@ -# Code Style - -- **Line length**: 120 characters -- **Python**: 3.9+ syntax (use `from __future__ import annotations` for type hints) -- **Package management**: Always use `uv`, never `pip` — run commands via `uv run` -- **Tooling**: Ruff for linting/formatting, mypy strict mode, prek for pre-commit checks (`uv run prek run`) -- **Comments**: Minimal — only explain "why", not "what" -- **Docstrings**: Do not add unless explicitly requested -- **Naming**: NEVER use leading underscores (`_function_name`) — Python has no true private functions, use public names -- **Paths**: Always use absolute `Path` objects, handle encoding explicitly (UTF-8) -- **Source transforms**: Use `libcst` for code modification/transformation to preserve formatting; `ast` is acceptable for read-only analysis and parsing diff --git a/tiles/codeflash-rules/rules/git-conventions.md b/tiles/codeflash-rules/rules/git-conventions.md deleted file mode 100644 index 1835dfdca..000000000 --- a/tiles/codeflash-rules/rules/git-conventions.md +++ /dev/null @@ -1,9 +0,0 @@ -# Git Conventions - -- **Always create a new branch from `main`** — never commit directly to `main` or reuse an existing feature branch for unrelated changes -- Use conventional commit format: `fix:`, `feat:`, `refactor:`, `docs:`, `test:`, `chore:` -- Keep commits atomic — one logical change per commit -- Commit message body should be concise (1-2 sentences max) -- PR titles should also use conventional format -- Branch naming: `cf-#-title` (lowercase, hyphenated) where `#` is the Linear issue number -- If related to a Linear issue, include `CF-#` in the PR body diff --git a/tiles/codeflash-rules/rules/language-rules.md b/tiles/codeflash-rules/rules/language-rules.md deleted file mode 100644 index 3b045a4f4..000000000 --- a/tiles/codeflash-rules/rules/language-rules.md +++ /dev/null @@ -1,9 +0,0 @@ -# Language Support Rules - -- Current language is a module-level singleton in `languages/current.py` — use `set_current_language()` / `current_language()`, never pass language as a parameter through call chains -- Use `get_language_support(identifier)` from `languages/registry.py` to get a `LanguageSupport` instance — accepts `Path`, `Language` enum, or string; never import language classes directly -- New language support classes must use the `@register_language` decorator to register with the extension and language registries -- `languages/__init__.py` uses `__getattr__` for lazy imports to avoid circular dependencies — follow this pattern when adding new exports -- `is_javascript()` returns `True` for both JavaScript and TypeScript -- Language modules are lazily imported on first `get_language_support()` call via `_ensure_languages_registered()` — the `@register_language` decorator fires on import and populates `_EXTENSION_REGISTRY` and `_LANGUAGE_REGISTRY` -- `LanguageSupport` instances are cached in `_SUPPORT_CACHE` — use `clear_cache()` only in tests diff --git a/tiles/codeflash-rules/rules/optimization-patterns.md b/tiles/codeflash-rules/rules/optimization-patterns.md deleted file mode 100644 index 7b879d227..000000000 --- a/tiles/codeflash-rules/rules/optimization-patterns.md +++ /dev/null @@ -1,11 +0,0 @@ -# Optimization Pipeline Patterns - -- All major operations return `Result[SuccessType, ErrorType]` — construct with `Success(value)` / `Failure(error)`, check with `is_successful()` before calling `unwrap()` -- Code context has token limits (`OPTIMIZATION_CONTEXT_TOKEN_LIMIT=16000`, `TESTGEN_CONTEXT_TOKEN_LIMIT=16000` in `code_utils/config_consts.py`) — exceeding them rejects the function -- `read_writable_code` (modifiable code) can span multiple files; `read_only_context_code` is reference-only dependency code -- Code is serialized as markdown code blocks: `` ```language:filepath\ncode\n``` `` — see `CodeStringsMarkdown` in `models/models.py` -- Candidates form a forest (DAG): refinements/repairs reference `parent_id` on previous candidates via `OptimizedCandidateSource` (OPTIMIZE, REFINE, REPAIR, ADAPTIVE, JIT_REWRITE) -- Test generation and optimization run concurrently — coordinate through `CandidateEvaluationContext` -- Generated tests are instrumented with `codeflash_capture.py` to record return values and traces -- Minimum improvement threshold is 5% (`MIN_IMPROVEMENT_THRESHOLD=0.05`) — candidates below this are rejected -- Stability thresholds: `STABILITY_WINDOW_SIZE=0.35`, `STABILITY_CENTER_TOLERANCE=0.0025`, `STABILITY_SPREAD_TOLERANCE=0.0025` diff --git a/tiles/codeflash-rules/rules/testing-rules.md b/tiles/codeflash-rules/rules/testing-rules.md deleted file mode 100644 index 780b48d60..000000000 --- a/tiles/codeflash-rules/rules/testing-rules.md +++ /dev/null @@ -1,13 +0,0 @@ -# Testing Rules - -- Code context extraction and replacement tests must assert full string equality — no substring matching -- Use pytest's `tmp_path` fixture for temp directories (it's a `Path` object) -- Write temp files inside `tmp_path`, never use `NamedTemporaryFile` (causes Windows file contention) -- Always call `.resolve()` on Path objects to ensure absolute paths and resolve symlinks -- Use `.as_posix()` when converting resolved paths to strings (normalizes to forward slashes) -- Any new feature or bug fix that can be tested automatically must have test cases -- If changes affect existing test expectations, update the tests accordingly — tests must always pass after changes -- The pytest plugin patches `time`, `random`, `uuid`, `datetime`, `os.urandom`, and `numpy.random` for deterministic test execution — never assume real randomness or real time in verification tests -- `conftest.py` uses an autouse fixture that calls `reset_current_language()` — tests always start with Python as the default language -- Test types are defined by the `TestType` enum: `EXISTING_UNIT_TEST`, `INSPIRED_REGRESSION`, `GENERATED_REGRESSION`, `REPLAY_TEST`, `CONCOLIC_COVERAGE_TEST`, `INIT_STATE_TEST` -- Verification runs tests in a subprocess using a custom pytest plugin (`verification/pytest_plugin.py`) — behavioral tests use blocklisted plugins (`benchmark`, `codspeed`, `xdist`, `sugar`), benchmarking tests additionally block `cov` and `profiling` diff --git a/tiles/codeflash-rules/tile.json b/tiles/codeflash-rules/tile.json deleted file mode 100644 index a286ba09b..000000000 --- a/tiles/codeflash-rules/tile.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "codeflash/codeflash-rules", - "version": "0.1.0", - "summary": "Coding standards and conventions for the codeflash codebase", - "private": true, - "rules": { - "code-style": { - "rules": "rules/code-style.md" - }, - "architecture": { - "rules": "rules/architecture.md" - }, - "optimization-patterns": { - "rules": "rules/optimization-patterns.md" - }, - "git-conventions": { - "rules": "rules/git-conventions.md" - }, - "testing-rules": { - "rules": "rules/testing-rules.md" - }, - "language-rules": { - "rules": "rules/language-rules.md" - } - } -} diff --git a/tiles/codeflash-skills/evals/capabilities.json b/tiles/codeflash-skills/evals/capabilities.json deleted file mode 100644 index cda33c968..000000000 --- a/tiles/codeflash-skills/evals/capabilities.json +++ /dev/null @@ -1,104 +0,0 @@ -{ - "package_name": "codeflash-skills", - "total_capabilities": 14, - "capabilities": [ - { - "id": 0, - "name": "sequential-pipeline-debugging", - "description": "Debug optimization failures by walking through pipeline stages sequentially and stopping at the first failure found", - "complexity": "intermediate", - "api_elements": ["discovery", "ranking", "context", "AI service", "verification", "deduplication", "repair"] - }, - { - "id": 1, - "name": "token-limit-awareness", - "description": "Know that OPTIMIZATION_CONTEXT_TOKEN_LIMIT and TESTGEN_CONTEXT_TOKEN_LIMIT are both 16000 tokens and that exceeding them causes function rejection", - "complexity": "basic", - "api_elements": ["OPTIMIZATION_CONTEXT_TOKEN_LIMIT", "TESTGEN_CONTEXT_TOKEN_LIMIT", "encoded_tokens_len()"] - }, - { - "id": 2, - "name": "improvement-threshold", - "description": "Know that MIN_IMPROVEMENT_THRESHOLD is 0.05 (5%) and candidates below this speedup are rejected", - "complexity": "basic", - "api_elements": ["MIN_IMPROVEMENT_THRESHOLD", "STABILITY_WINDOW_SIZE"] - }, - { - "id": 3, - "name": "ast-deduplication", - "description": "Know that candidates are deduplicated via AST normalization using normalize_code() and CandidateEvaluationContext.ast_code_to_id", - "complexity": "intermediate", - "api_elements": ["normalize_code()", "CandidateEvaluationContext.ast_code_to_id", "code_utils/deduplicate_code.py"] - }, - { - "id": 4, - "name": "repair-trigger-conditions", - "description": "Know that repair only triggers when fewer than MIN_CORRECT_CANDIDATES=2 pass, and is skipped when REPAIR_UNMATCHED_PERCENTAGE_LIMIT is exceeded", - "complexity": "advanced", - "api_elements": ["MIN_CORRECT_CANDIDATES", "REPAIR_UNMATCHED_PERCENTAGE_LIMIT", "AIServiceCodeRepairRequest"] - }, - { - "id": 5, - "name": "ai-service-error-patterns", - "description": "Know specific log patterns to search for when AI service fails: 'Error generating optimized candidates', 'cli-optimize-error-caught', 'cli-optimize-error-response'", - "complexity": "intermediate", - "api_elements": ["AiServiceClient", "api/aiservice.py"] - }, - { - "id": 6, - "name": "behavioral-vs-benchmark-failures", - "description": "Distinguish between behavioral test failures (return value/stdout/pass-fail mismatches via TestDiffScope) and benchmark failures (speedup below threshold)", - "complexity": "intermediate", - "api_elements": ["TestDiffScope", "RETURN_VALUE", "STDOUT", "DID_PASS"] - }, - { - "id": 7, - "name": "result-type-pattern", - "description": "Use Result[L, R] from either.py with Success/Failure constructors and is_successful() checks before unwrap()", - "complexity": "basic", - "api_elements": ["Result", "Success", "Failure", "is_successful", "unwrap()", "either.py"] - }, - { - "id": 8, - "name": "effort-config-pattern", - "description": "Add effort-dependent config via EffortKeys enum, EFFORT_VALUES dict with LOW/MEDIUM/HIGH levels, and get_effort_value()", - "complexity": "intermediate", - "api_elements": ["EffortKeys", "EffortLevel", "EFFORT_VALUES", "get_effort_value()", "config_consts.py"] - }, - { - "id": 9, - "name": "module-to-feature-mapping", - "description": "Know which codeflash module to modify for different feature types (optimization/ for strategies, api/ for endpoints, languages/ for language support, etc.)", - "complexity": "basic", - "api_elements": ["MODULE_REFERENCE.md"] - }, - { - "id": 10, - "name": "domain-type-conventions", - "description": "Use @dataclass(frozen=True) for immutable data, BaseModel for serializable models, and keep function_types.py dependency-free", - "complexity": "intermediate", - "api_elements": ["@dataclass(frozen=True)", "BaseModel", "models/models.py", "models/function_types.py"] - }, - { - "id": 11, - "name": "test-patterns", - "description": "Use tmp_path fixture, .resolve() on Paths, .as_posix() for string conversion, full string equality assertions, and awareness of deterministic patches", - "complexity": "basic", - "api_elements": ["tmp_path", ".resolve()", ".as_posix()", "pytest_plugin.py"] - }, - { - "id": 12, - "name": "quality-check-commands", - "description": "Run uv run prek run for formatting/linting, uv run mypy for type checking, and uv run pytest for tests", - "complexity": "basic", - "api_elements": ["uv run prek run", "uv run mypy", "uv run pytest"] - }, - { - "id": 13, - "name": "language-support-patterns", - "description": "Use @register_language decorator, get_language_support() for lookup, singleton pattern via set_current_language()/current_language(), and is_python()/is_javascript() guards", - "complexity": "advanced", - "api_elements": ["@register_language", "get_language_support()", "set_current_language()", "is_python()", "is_javascript()"] - } - ] -} diff --git a/tiles/codeflash-skills/evals/scenario-1/capability.txt b/tiles/codeflash-skills/evals/scenario-1/capability.txt deleted file mode 100644 index c4d34b1aa..000000000 --- a/tiles/codeflash-skills/evals/scenario-1/capability.txt +++ /dev/null @@ -1 +0,0 @@ -Sequential pipeline debugging with specific thresholds \ No newline at end of file diff --git a/tiles/codeflash-skills/evals/scenario-1/criteria.json b/tiles/codeflash-skills/evals/scenario-1/criteria.json deleted file mode 100644 index cec7afda7..000000000 --- a/tiles/codeflash-skills/evals/scenario-1/criteria.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "context": "Tests whether the agent follows the sequential debugging workflow from the skill, checking pipeline stages in order and using correct threshold values when diagnosing an optimization that produced no results.", - "type": "weighted_checklist", - "checklist": [ - { - "name": "Sequential stage order", - "description": "Investigates pipeline stages in order: discovery before ranking before context before AI service before test failures. Does NOT jump to later stages without checking earlier ones first.", - "max_score": 25 - }, - { - "name": "Token limit value", - "description": "References the specific token limit of 16000 for OPTIMIZATION_CONTEXT_TOKEN_LIMIT or TESTGEN_CONTEXT_TOKEN_LIMIT when checking context extraction", - "max_score": 25 - }, - { - "name": "Importance threshold", - "description": "References DEFAULT_IMPORTANCE_THRESHOLD=0.001 when checking function ranking", - "max_score": 25 - }, - { - "name": "Stops at failure", - "description": "Identifies the failing stage and focuses investigation there rather than continuing through all remaining stages", - "max_score": 25 - } - ] -} diff --git a/tiles/codeflash-skills/evals/scenario-1/task.md b/tiles/codeflash-skills/evals/scenario-1/task.md deleted file mode 100644 index 17c74d8cb..000000000 --- a/tiles/codeflash-skills/evals/scenario-1/task.md +++ /dev/null @@ -1,13 +0,0 @@ -# Diagnose Silent Optimization Skip - -## Context - -A user reports that when running codeflash on their project, a specific function `calculate_metrics` in `analytics/processor.py` never appears in the optimization results. The function exists in the module root, is not in the exclude list, and has not been previously optimized. Trace data shows the function is called frequently but with very short execution times (averaging 0.0005 seconds total addressable time). The function has moderate dependencies. - -## Task - -Write a diagnostic report explaining why this function is being skipped and at which stage in the pipeline the function is filtered out. Include the specific threshold or condition that causes the skip. - -## Expected Outputs - -A markdown file `diagnostic-report.md` explaining the root cause. diff --git a/tiles/codeflash-skills/evals/scenario-2/capability.txt b/tiles/codeflash-skills/evals/scenario-2/capability.txt deleted file mode 100644 index 72b283863..000000000 --- a/tiles/codeflash-skills/evals/scenario-2/capability.txt +++ /dev/null @@ -1 +0,0 @@ -Result type pattern and effort-dependent configuration \ No newline at end of file diff --git a/tiles/codeflash-skills/evals/scenario-2/criteria.json b/tiles/codeflash-skills/evals/scenario-2/criteria.json deleted file mode 100644 index 9c49891b8..000000000 --- a/tiles/codeflash-skills/evals/scenario-2/criteria.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "context": "Tests whether the agent uses the codeflash Result type pattern from either.py and the effort-dependent configuration pattern when implementing a new pipeline feature.", - "type": "weighted_checklist", - "checklist": [ - { - "name": "Imports from either.py", - "description": "Imports Success, Failure, and is_successful from codeflash.either (NOT from a different error handling module)", - "max_score": 20 - }, - { - "name": "Result return type", - "description": "Function returns Result type using Success() for success and Failure() for errors, not exceptions or None", - "max_score": 20 - }, - { - "name": "is_successful check", - "description": "Calls is_successful() or .is_successful() before calling unwrap() on the result", - "max_score": 20 - }, - { - "name": "EffortKeys enum entry", - "description": "Adds a new entry to the EffortKeys enum in config_consts.py", - "max_score": 20 - }, - { - "name": "Three effort levels", - "description": "Adds values for all three EffortLevel variants (LOW, MEDIUM, HIGH) in EFFORT_VALUES dict", - "max_score": 20 - } - ] -} diff --git a/tiles/codeflash-skills/evals/scenario-2/task.md b/tiles/codeflash-skills/evals/scenario-2/task.md deleted file mode 100644 index dfe684d14..000000000 --- a/tiles/codeflash-skills/evals/scenario-2/task.md +++ /dev/null @@ -1,21 +0,0 @@ -# Add Candidate Timeout Feature - -## Context - -The codeflash optimization engine currently has no per-candidate timeout. Some candidates take too long during verification, wasting the optimization budget. A new feature is needed to skip candidates that exceed a configurable time limit during behavioral testing. - -The timeout should vary based on the optimization effort setting — shorter timeouts for low effort runs (to save time) and longer for high effort runs (to allow more complex optimizations). - -## Task - -Implement a `check_candidate_timeout` function in `codeflash/optimization/function_optimizer.py` that: -1. Takes a candidate runtime and returns whether the candidate should be skipped -2. Uses a configurable timeout threshold that scales with optimization effort -3. Handles the error case where the runtime measurement is unavailable - -Also add the necessary configuration constant to `codeflash/code_utils/config_consts.py`. - -## Expected Outputs - -- Modified `function_optimizer.py` with the new function -- Modified `config_consts.py` with the new configuration diff --git a/tiles/codeflash-skills/evals/scenario-3/capability.txt b/tiles/codeflash-skills/evals/scenario-3/capability.txt deleted file mode 100644 index 1fa504dee..000000000 --- a/tiles/codeflash-skills/evals/scenario-3/capability.txt +++ /dev/null @@ -1 +0,0 @@ -Test patterns and deterministic patch awareness \ No newline at end of file diff --git a/tiles/codeflash-skills/evals/scenario-3/criteria.json b/tiles/codeflash-skills/evals/scenario-3/criteria.json deleted file mode 100644 index ccf96e3fa..000000000 --- a/tiles/codeflash-skills/evals/scenario-3/criteria.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "context": "Tests whether the agent follows codeflash test conventions when writing tests, including path handling, temp directory patterns, and awareness of the deterministic patching system.", - "type": "weighted_checklist", - "checklist": [ - { - "name": "Uses tmp_path fixture", - "description": "Test function uses pytest tmp_path fixture parameter, NOT tempfile.NamedTemporaryFile or tempfile.mkdtemp", - "max_score": 25 - }, - { - "name": "Calls resolve on paths", - "description": "Calls .resolve() on Path objects before using them in assertions or function calls", - "max_score": 25 - }, - { - "name": "Full string equality", - "description": "Uses exact equality assertions (== or assert_equal) for code string comparisons, NOT substring checks like 'in' or assertIn or contains", - "max_score": 25 - }, - { - "name": "No real time dependency", - "description": "Test does NOT depend on real time.time(), datetime.now(), random values, or uuid generation for correctness. Acknowledges or accounts for deterministic patches if time/random values are involved.", - "max_score": 25 - } - ] -} diff --git a/tiles/codeflash-skills/evals/scenario-3/task.md b/tiles/codeflash-skills/evals/scenario-3/task.md deleted file mode 100644 index 5b13a15d6..000000000 --- a/tiles/codeflash-skills/evals/scenario-3/task.md +++ /dev/null @@ -1,24 +0,0 @@ -# Write Tests for Context Hash Comparison - -## Context - -The codeflash context extraction module has a function `compare_context_hashes(context_a, context_b)` that takes two `CodeOptimizationContext` objects and returns whether their hashing contexts are identical. This is used to detect when the same function has already been optimized. - -```python -# In codeflash/context/code_context_extractor.py -def compare_context_hashes(context_a: CodeOptimizationContext, context_b: CodeOptimizationContext) -> bool: - return context_a.hashing_code_context_hash == context_b.hashing_code_context_hash -``` - -## Task - -Write a test file `tests/test_context/test_hash_comparison.py` with tests for this function. Include tests for: -1. Two contexts with identical code producing the same hash -2. Two contexts with different code producing different hashes -3. A context compared with itself - -The tests should create temporary Python source files to build realistic context objects. - -## Expected Outputs - -- `tests/test_context/test_hash_comparison.py` diff --git a/tiles/codeflash-skills/evals/scenario-4/capability.txt b/tiles/codeflash-skills/evals/scenario-4/capability.txt deleted file mode 100644 index c0d3fea71..000000000 --- a/tiles/codeflash-skills/evals/scenario-4/capability.txt +++ /dev/null @@ -1 +0,0 @@ -Domain type conventions and module identification \ No newline at end of file diff --git a/tiles/codeflash-skills/evals/scenario-4/criteria.json b/tiles/codeflash-skills/evals/scenario-4/criteria.json deleted file mode 100644 index 20861011c..000000000 --- a/tiles/codeflash-skills/evals/scenario-4/criteria.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "context": "Tests whether the agent follows codeflash domain type conventions and correctly identifies the right module when adding a new data type for the optimization pipeline.", - "type": "weighted_checklist", - "checklist": [ - { - "name": "Placed in models/models.py", - "description": "New data type is added to codeflash/models/models.py (NOT models/function_types.py, since it has dependencies on other codeflash modules)", - "max_score": 25 - }, - { - "name": "Uses frozen dataclass", - "description": "Immutable data type uses @dataclass(frozen=True) decorator, NOT a regular class or unfrozen dataclass", - "max_score": 25 - }, - { - "name": "BaseModel for serializable", - "description": "If a serializable model is needed, uses Pydantic BaseModel (NOT dataclass or dict)", - "max_score": 25 - }, - { - "name": "Correct module for feature", - "description": "Places the main logic in the correct module for the feature type (e.g., verification/ for test-related, optimization/ for candidate-related, api/ for service-related)", - "max_score": 25 - } - ] -} diff --git a/tiles/codeflash-skills/evals/scenario-4/task.md b/tiles/codeflash-skills/evals/scenario-4/task.md deleted file mode 100644 index 61299a115..000000000 --- a/tiles/codeflash-skills/evals/scenario-4/task.md +++ /dev/null @@ -1,21 +0,0 @@ -# Add Optimization Confidence Score - -## Context - -The codeflash team wants to add a confidence score to each optimization result. The score should capture how confident the system is that an optimization is both correct and beneficial. It combines test coverage percentage, number of passing test cases, and speedup stability into a single metric. - -The score needs to be: -- Attached to each candidate during evaluation (immutable once computed) -- Included in the final PR report (needs JSON serialization) -- Computed during the candidate evaluation phase - -## Task - -1. Define the data types needed for the confidence score -2. Write a `compute_confidence_score` function that takes coverage percentage (float), passing test count (int), and stability ratio (float) and returns the confidence result -3. Place all code in the appropriate codeflash modules - -## Expected Outputs - -- New/modified type definitions in the appropriate models file -- New function in the appropriate module diff --git a/tiles/codeflash-skills/evals/scenario-5/capability.txt b/tiles/codeflash-skills/evals/scenario-5/capability.txt deleted file mode 100644 index 28a3fe8ee..000000000 --- a/tiles/codeflash-skills/evals/scenario-5/capability.txt +++ /dev/null @@ -1 +0,0 @@ -Deduplication mechanics and repair trigger conditions \ No newline at end of file diff --git a/tiles/codeflash-skills/evals/scenario-5/criteria.json b/tiles/codeflash-skills/evals/scenario-5/criteria.json deleted file mode 100644 index 8c3f8e817..000000000 --- a/tiles/codeflash-skills/evals/scenario-5/criteria.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "context": "Tests whether the agent understands codeflash's candidate deduplication via AST normalization and the specific conditions under which code repair is triggered vs skipped.", - "type": "weighted_checklist", - "checklist": [ - { - "name": "AST normalization", - "description": "Mentions that deduplication uses AST normalization (normalize_code from code_utils/deduplicate_code.py), NOT simple string comparison", - "max_score": 25 - }, - { - "name": "Duplicate result copying", - "description": "Explains that duplicate candidates copy results from the first-seen candidate rather than being re-tested", - "max_score": 25 - }, - { - "name": "Repair trigger threshold", - "description": "States that repair triggers when fewer than 2 candidates pass (MIN_CORRECT_CANDIDATES=2), NOT when zero candidates pass or when any candidate fails", - "max_score": 25 - }, - { - "name": "Unmatched percentage limit", - "description": "Mentions REPAIR_UNMATCHED_PERCENTAGE_LIMIT as a condition that can cause repair to be skipped entirely, with effort-dependent values (0.2/0.3/0.4)", - "max_score": 25 - } - ] -} diff --git a/tiles/codeflash-skills/evals/scenario-5/task.md b/tiles/codeflash-skills/evals/scenario-5/task.md deleted file mode 100644 index 19995f3e6..000000000 --- a/tiles/codeflash-skills/evals/scenario-5/task.md +++ /dev/null @@ -1,17 +0,0 @@ -# Investigate Low Candidate Diversity - -## Context - -A codeflash user is optimizing a data processing function at medium effort level. The AI service returns 5 candidates, but the optimization log shows only 1 candidate was actually benchmarked. Of the 5 candidates, 1 passed behavioral tests but didn't meet the performance threshold. The user wants to understand what happened to the other 4 candidates and why no repair attempts were made. - -## Task - -Write an analysis document explaining: -1. Why only 1 out of 5 candidates was benchmarked -2. How the system determines which candidates to actually test -3. Under what conditions the system would have attempted to repair the failing candidates -4. What the user could change to get more diverse results - -## Expected Outputs - -A markdown file `analysis.md` with the explanation. diff --git a/tiles/codeflash-skills/evals/summary.json b/tiles/codeflash-skills/evals/summary.json deleted file mode 100644 index c5929299f..000000000 --- a/tiles/codeflash-skills/evals/summary.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "total_scenarios": 5, - "capabilities_coverage": { - "total_capabilities": 14, - "capabilities_tested": 10, - "coverage_percentage": 71.4 - }, - "complexity_distribution": { - "basic": 2, - "intermediate": 2, - "advanced": 1 - }, - "scenarios": [ - { - "index": 1, - "capability": "sequential-pipeline-debugging, token-limit-awareness, improvement-threshold", - "complexity": "intermediate" - }, - { - "index": 2, - "capability": "result-type-pattern, effort-config-pattern", - "complexity": "intermediate" - }, - { - "index": 3, - "capability": "test-patterns, quality-check-commands", - "complexity": "basic" - }, - { - "index": 4, - "capability": "domain-type-conventions, module-to-feature-mapping", - "complexity": "basic" - }, - { - "index": 5, - "capability": "ast-deduplication, repair-trigger-conditions", - "complexity": "advanced" - } - ] -} diff --git a/tiles/codeflash-skills/evals/summary_infeasible.json b/tiles/codeflash-skills/evals/summary_infeasible.json deleted file mode 100644 index 36da50727..000000000 --- a/tiles/codeflash-skills/evals/summary_infeasible.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "total_infeasible": 4, - "infeasible_capabilities": [ - { - "capability": "ai-service-error-patterns", - "complexity": "intermediate", - "reasoning": "Requires actual AI service API responses and log output that cannot be meaningfully mocked without bypassing the capability being tested" - }, - { - "capability": "behavioral-vs-benchmark-failures", - "complexity": "intermediate", - "reasoning": "Requires actual test execution results with JUnit XML output and timing data that cannot be generated in a one-shot file-based eval" - }, - { - "capability": "language-support-patterns", - "complexity": "advanced", - "reasoning": "Requires the full language registry system with imports and decorators that would need the codeflash runtime to verify" - }, - { - "capability": "quality-check-commands", - "complexity": "basic", - "reasoning": "Requires running actual uv/prek/mypy commands which need the project environment and dependencies installed" - } - ] -} diff --git a/tiles/codeflash-skills/skills/add-codeflash-feature/MODULE_REFERENCE.md b/tiles/codeflash-skills/skills/add-codeflash-feature/MODULE_REFERENCE.md deleted file mode 100644 index 9012fb294..000000000 --- a/tiles/codeflash-skills/skills/add-codeflash-feature/MODULE_REFERENCE.md +++ /dev/null @@ -1,13 +0,0 @@ -# Module Reference - -| Feature area | Primary module | Key files | -|-------------|----------------|-----------| -| New optimization strategy | `optimization/` | `function_optimizer.py`, `optimizer.py` | -| New test type | `verification/`, `models/` | `test_runner.py`, `pytest_plugin.py`, `test_type.py` | -| New AI service endpoint | `api/` | `aiservice.py` | -| New language support | `languages/` | Create new `languages//support.py` | -| Context extraction change | `context/` | `code_context_extractor.py` | -| New CLI command | `cli_cmds/` | `cli.py` | -| New config option | `setup/`, `code_utils/` | `config_consts.py`, `setup/detector.py` | -| Discovery filter | `discovery/` | `functions_to_optimize.py` | -| PR/result changes | `github/`, `result/` | Relevant handlers | diff --git a/tiles/codeflash-skills/skills/add-codeflash-feature/SKILL.md b/tiles/codeflash-skills/skills/add-codeflash-feature/SKILL.md deleted file mode 100644 index f61abfe83..000000000 --- a/tiles/codeflash-skills/skills/add-codeflash-feature/SKILL.md +++ /dev/null @@ -1,146 +0,0 @@ ---- -name: add-codeflash-feature -description: > - Guides implementation of new functionality in the codeflash optimization engine. - Use when adding a feature, building new functionality, implementing a new - optimization strategy, adding a language backend, creating an API endpoint, - extending the verification pipeline, or developing any new codeflash capability. - Covers module identification, Result type patterns, config, types, tests, and - quality checks. ---- - -# Add Codeflash Feature - -Use this workflow when implementing new functionality in the codeflash codebase — new optimization strategies, language backends, API endpoints, CLI commands, config options, or pipeline extensions. - -## Step 1: Identify Target Modules - -Determine which module(s) need modification. See [MODULE_REFERENCE.md](MODULE_REFERENCE.md) for the full mapping of feature areas to modules and key files. - -**Checkpoint**: Read the target files and understand existing patterns before writing any code. Look for similar features already implemented as reference. - -## Step 2: Follow Result Type Pattern - -Use the `Result[L, R]` type from `either.py` for error handling in pipeline operations: - -```python -from codeflash.either import Success, Failure, is_successful - -def my_operation() -> Result[str, MyResultType]: - if error_condition: - return Failure("descriptive error message") - return Success(result_value) - -# Usage: -result = my_operation() -if not is_successful(result): - logger.error(result.failure()) - return -value = result.unwrap() -``` - -**Checkpoint**: Verify your function signatures match the `Result` pattern used in surrounding code. Not all functions use `Result` — match the convention of the module you're modifying. - -## Step 3: Add Configuration Constants - -If the feature needs configurable thresholds or limits: - -1. Add constants to `code_utils/config_consts.py` -2. If effort-dependent, add to `EFFORT_VALUES` dict with values for all three levels: - ```python - # In config_consts.py: - class EffortKeys(str, Enum): - MY_NEW_KEY = "MY_NEW_KEY" - - EFFORT_VALUES: dict[str, dict[EffortLevel, Any]] = { - # ... existing entries ... - EffortKeys.MY_NEW_KEY.value: { - EffortLevel.LOW: 1, - EffortLevel.MEDIUM: 3, - EffortLevel.HIGH: 5, - }, - } - ``` -3. Access via `get_effort_value(EffortKeys.MY_NEW_KEY, effort_level)` - -**Checkpoint**: Skip this step if the feature doesn't need configuration. Not every feature requires new constants. - -## Step 4: Add Domain Types - -If new data structures are needed: - -1. Add Pydantic models or frozen dataclasses to `models/models.py` or `models/function_types.py` -2. Use `@dataclass(frozen=True)` for immutable data, `BaseModel` for models that need serialization -3. Keep `function_types.py` dependency-free — no imports from other codeflash modules - -Example following existing patterns: -```python -# In models/models.py: -@dataclass(frozen=True) -class MyNewType: - name: str - value: int - source: OptimizedCandidateSource - -# For serializable models: -class MyNewModel(BaseModel): - items: list[MyNewType] = [] -``` - -**Checkpoint**: Skip this step if you can reuse existing types. Check `models/models.py` for types that already fit your needs. - -## Step 5: Write Tests - -Follow existing test patterns: - -1. Create test files in `tests/` mirroring the source structure (e.g., `tests/test_optimization/test_my_feature.py`) -2. Use pytest's `tmp_path` fixture for temp directories — never `NamedTemporaryFile` -3. Always call `.resolve()` on Path objects and `.as_posix()` for string conversion -4. Assert full string equality for code context tests — no substring matching -5. The pytest plugin patches `time`, `random`, `uuid`, `datetime` — never rely on real values in verification tests - -```python -def test_my_feature(tmp_path: Path) -> None: - test_file = tmp_path / "test_module.py" - test_file.write_text("def foo(): return 1", encoding="utf-8") - result = my_operation(test_file.resolve()) - assert is_successful(result) - assert result.unwrap() == expected_value -``` - -**Checkpoint**: Run the new tests in isolation before proceeding: `uv run pytest tests/path/to/test_file.py -x` - -## Step 6: Run Quality Checks - -Run all validation before committing: - -```bash -# Pre-commit checks (ruff format + lint) -uv run prek run - -# Type checking -uv run mypy codeflash/ - -# Run relevant tests -uv run pytest tests/path/to/relevant/tests -x -``` - -**If checks fail**: -- `prek run` failures: Fix formatting/lint issues reported by ruff, then re-run -- `mypy` failures: Fix type errors — common issues are missing return types, wrong `Optional` usage, or missing imports in `TYPE_CHECKING` block -- Test failures: Fix the failing test or the implementation, then re-run - -## Step 7: Language Support Considerations - -If the feature needs to work across languages: - -1. Use `get_language_support(identifier)` from `languages/registry.py` — never import language classes directly -2. Current language is a singleton: `set_current_language()` / `current_language()` from `languages/current.py` -3. Use `is_python()` / `is_javascript()` guards for language-specific branches -4. New language support classes must use `@register_language` decorator and be instantiable without arguments - -**Checkpoint**: Skip this step if the feature is Python-only. Most features don't need multi-language support. - -## Troubleshooting - -If you run into issues, see [TROUBLESHOOTING.md](TROUBLESHOOTING.md) for common problems and fixes (circular imports, `UnsupportedLanguageError`, CI path failures, Pydantic validation errors, token limit exceeded). diff --git a/tiles/codeflash-skills/skills/add-codeflash-feature/TROUBLESHOOTING.md b/tiles/codeflash-skills/skills/add-codeflash-feature/TROUBLESHOOTING.md deleted file mode 100644 index 6c56f8d0b..000000000 --- a/tiles/codeflash-skills/skills/add-codeflash-feature/TROUBLESHOOTING.md +++ /dev/null @@ -1,9 +0,0 @@ -# Troubleshooting - -| Problem | Likely cause | Fix | -|---------|-------------|-----| -| Circular import at startup | Importing from `models/` in a module loaded early | Move import into `TYPE_CHECKING` block or use lazy import | -| `UnsupportedLanguageError` | Language modules not registered yet | Call `_ensure_languages_registered()` or use `get_language_support()` which does it automatically | -| Tests pass locally but fail in CI | Path differences (absolute vs relative) | Always use `.resolve()` on Path objects | -| `ValidationError` from Pydantic | Invalid code passed to `CodeString` | Check that generated code passes syntax validation for the target language | -| `encoded_tokens_len` exceeds limit | Context too large | Reduce helper functions or split into read-only vs read-writable | diff --git a/tiles/codeflash-skills/skills/debug-optimization-failure/SKILL.md b/tiles/codeflash-skills/skills/debug-optimization-failure/SKILL.md deleted file mode 100644 index f85c56641..000000000 --- a/tiles/codeflash-skills/skills/debug-optimization-failure/SKILL.md +++ /dev/null @@ -1,124 +0,0 @@ ---- -name: debug-optimization-failure -description: > - Diagnose why a codeflash optimization produced no results or failed silently. - Use when an optimization run errors out, returns no candidates, or all candidates - are rejected. Walks through discovery, ranking, context limits, AI service, - test verification, deduplication, and repair stages. ---- - -# Debug Optimization Failure - -Use this workflow when an optimization run fails or produces no results. Work through the stages sequentially — stop at the first failure found. - -## Step 1: Check Function Discovery - -Determine if the function was discovered by `FunctionVisitor`. - -1. Search logs for the function name in discovery output: - ```python - # In discovery/functions_to_optimize.py, FunctionVisitor filters out: - # - Functions matching exclude patterns in pyproject.toml [tool.codeflash] - # - Functions already optimized (was_function_previously_optimized()) - # - Functions outside the configured module-root - ``` -2. Verify the function file is under the configured `module-root` in `pyproject.toml` -3. Check if the function was previously optimized — look for it in the optimization history - -**Checkpoint**: If the function doesn't appear in discovery output, fix config patterns or file location before proceeding. - -## Step 2: Check Ranking - -If trace data is used, check if the function was ranked high enough. - -1. Look at `benchmarking/function_ranker.py` output for the function's addressable time -2. The function must exceed `DEFAULT_IMPORTANCE_THRESHOLD=0.001`: - ```python - # Addressable time = own time + callee time / call count - # Grep for the function in ranking output: - # grep -i "function_name" in ranking logs - ``` -3. Functions below the threshold are silently skipped - -**Checkpoint**: If ranked too low, the function doesn't spend enough time to be worth optimizing. No fix needed — this is expected. - -## Step 3: Check Context Token Limits - -Verify the function's context fits within token limits. - -1. Check thresholds in `code_utils/config_consts.py`: - ```python - OPTIMIZATION_CONTEXT_TOKEN_LIMIT = 16000 # tokens - TESTGEN_CONTEXT_TOKEN_LIMIT = 16000 # tokens - ``` -2. Token counting uses `encoded_tokens_len()` from `code_utils/code_utils.py` -3. Common causes: large helper function chains, deep dependency trees, large class hierarchies - -**Checkpoint**: If context exceeds limits, the function is rejected. Consider refactoring to reduce dependencies or splitting large modules. - -## Step 4: Check AI Service Response - -Verify the AI service returned valid candidates. - -1. Look for HTTP errors in logs: - ``` - # Error patterns to search for: - "Error generating optimized candidates" - "Error generating jit rewritten candidate" - "cli-optimize-error-caught" - "cli-optimize-error-response" - ``` -2. Check `_get_valid_candidates()` in `api/aiservice.py` — empty `code_strings` after `CodeStringsMarkdown.parse_markdown_code()` means the LLM returned malformed code blocks -3. Verify API key is valid (`get_codeflash_api_key()`) - -**Checkpoint**: If no candidates returned, check API key, network, and service status before proceeding. - -## Step 5: Check Test Failures - -Determine if candidates failed behavioral or benchmark tests. - -1. **Behavioral failures** — compare return values, stdout, pass/fail between baseline and candidate: - ```python - # TestDiffScope enum values to look for: - # RETURN_VALUE - function returned different value - # STDOUT - different stdout output - # DID_PASS - test passed/failed differently - ``` -2. **Benchmark failures** — candidate must beat `MIN_IMPROVEMENT_THRESHOLD=0.05` (5% speedup) -3. **Stability failures** — timing must be stable within `STABILITY_WINDOW_SIZE=0.35` (35% of iterations) -4. Check JUnit XML test results in the temp directory for specific failure messages - -**Checkpoint**: Behavioral failure = optimization changed behavior (check test diffs). Benchmark failure = not fast enough. Stability failure = noisy timing environment. - -## Step 6: Check Deduplication - -Verify candidates weren't deduplicated away. - -1. `CandidateEvaluationContext.ast_code_to_id` tracks normalized AST → candidate mapping -2. `normalize_code()` from `code_utils/deduplicate_code.py` strips comments/whitespace and normalizes the AST -3. If all candidates normalize to identical code, only the first is tested — the rest copy its results - -**Checkpoint**: If all duplicates, the LLM generated the same optimization repeatedly. Try a higher effort level for more diverse candidates. - -## Step 7: Check Repair/Refinement - -If initial candidates failed, check repair and refinement stages. - -1. Repair only triggers if fewer than `MIN_CORRECT_CANDIDATES=2` passed behavioral tests -2. Repair sends `AIServiceCodeRepairRequest` with `TestDiff` objects showing what went wrong -3. Check `REPAIR_UNMATCHED_PERCENTAGE_LIMIT` (effort-dependent: 0.2/0.3/0.4) — if too many tests failed, repair is skipped entirely -4. Refinement only runs on the top valid candidates (count depends on effort level) - -**Checkpoint**: If repair also fails, the optimization approach likely doesn't work for this function. The function may rely on side effects or external state that the LLM can't safely optimize. - -## Key Files Reference - -| File | What to check | -|------|---------------| -| `optimization/function_optimizer.py` | Main loop, `determine_best_candidate()` | -| `verification/test_runner.py` | Test subprocess execution | -| `api/aiservice.py` | AI service requests/responses | -| `code_utils/config_consts.py` | All thresholds and limits | -| `context/code_context_extractor.py` | Context extraction and token counting | -| `models/models.py` | `CandidateEvaluationContext`, `TestResults`, `TestDiff` | -| `code_utils/deduplicate_code.py` | AST normalization for deduplication | diff --git a/tiles/codeflash-skills/tile.json b/tiles/codeflash-skills/tile.json deleted file mode 100644 index 01d7a9481..000000000 --- a/tiles/codeflash-skills/tile.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "codeflash/codeflash-skills", - "version": "0.2.0", - "summary": "Procedural workflows for developing and debugging codeflash", - "private": true, - "skills": { - "debug-optimization-failure": { - "path": "skills/debug-optimization-failure/SKILL.md" - }, - "add-codeflash-feature": { - "path": "skills/add-codeflash-feature/SKILL.md" - } - } -} From 6a5c9c1b401929bbced612c6f6ff96f770af9971 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 18 Feb 2026 21:07:03 -0500 Subject: [PATCH 049/100] test: update expected context values for statement-type helpers --- tests/test_code_context_extractor.py | 49 ++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tests/test_code_context_extractor.py b/tests/test_code_context_extractor.py index add427f32..84da13762 100644 --- a/tests/test_code_context_extractor.py +++ b/tests/test_code_context_extractor.py @@ -978,7 +978,12 @@ def test_repo_helper() -> None: code_ctx = get_code_optimization_context(function_to_optimize, project_root) read_write_context, read_only_context = code_ctx.read_writable_code, code_ctx.read_only_context_code hashing_context = code_ctx.hashing_code_context + path_to_globals = project_root / "globals.py" expected_read_write_context = f""" +```python:{path_to_globals.relative_to(project_root)} +# Define a global variable +API_URL = "https://api.example.com/data" +``` ```python:{path_to_utils.relative_to(project_root)} import math @@ -1071,7 +1076,12 @@ def test_repo_helper_of_helper() -> None: code_ctx = get_code_optimization_context(function_to_optimize, project_root) read_write_context, read_only_context = code_ctx.read_writable_code, code_ctx.read_only_context_code hashing_context = code_ctx.hashing_code_context + path_to_globals = project_root / "globals.py" expected_read_write_context = f""" +```python:{path_to_globals.relative_to(project_root)} +# Define a global variable +API_URL = "https://api.example.com/data" +``` ```python:{path_to_utils.relative_to(project_root)} import math from transform_utils import DataTransformer @@ -1798,6 +1808,8 @@ def calculate(self, operation, x, y): """ expected_read_only_context = """ ```python:utility_module.py +import sys + DEFAULT_PRECISION = "medium" # Try-except block with variable definitions @@ -1808,6 +1820,17 @@ def calculate(self, operation, x, y): # Used variable in except block CALCULATION_BACKEND = "python" +# Nested if-else with variable definitions +if sys.platform.startswith('win'): + # Used variable in outer if + SYSTEM_TYPE = "windows" +elif sys.platform.startswith('linux'): + # Used variable in outer elif + SYSTEM_TYPE = "linux" +else: + # Used variable in outer else + SYSTEM_TYPE = "other" + # Function that will be used in the main code def select_precision(precision, fallback_precision): if precision is None: @@ -2014,6 +2037,8 @@ def get_system_details(): relative_path = file_path.relative_to(project_root) expected_read_write_context = f""" ```python:utility_module.py +import sys + DEFAULT_PRECISION = "medium" # Try-except block with variable definitions @@ -2024,6 +2049,17 @@ def get_system_details(): # Used variable in except block CALCULATION_BACKEND = "python" +# Nested if-else with variable definitions +if sys.platform.startswith('win'): + # Used variable in outer if + SYSTEM_TYPE = "windows" +elif sys.platform.startswith('linux'): + # Used variable in outer elif + SYSTEM_TYPE = "linux" +else: + # Used variable in outer else + SYSTEM_TYPE = "other" + # Function that will be used in the main code def select_precision(precision, fallback_precision): if precision is None: @@ -2064,6 +2100,8 @@ def __init__(self, precision="high", fallback_precision=None, mode="standard"): """ expected_read_only_context = """ ```python:utility_module.py +import sys + DEFAULT_PRECISION = "medium" # Try-except block with variable definitions @@ -2073,6 +2111,17 @@ def __init__(self, precision="high", fallback_precision=None, mode="standard"): except ImportError: # Used variable in except block CALCULATION_BACKEND = "python" + +# Nested if-else with variable definitions +if sys.platform.startswith('win'): + # Used variable in outer if + SYSTEM_TYPE = "windows" +elif sys.platform.startswith('linux'): + # Used variable in outer elif + SYSTEM_TYPE = "linux" +else: + # Used variable in outer else + SYSTEM_TYPE = "other" ``` """ assert read_write_context.markdown.strip() == expected_read_write_context.strip() From ee3737a03634d823f1e05941dc5d233ec5fc68ba Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 18 Feb 2026 21:18:24 -0500 Subject: [PATCH 050/100] chore: exclude test and fixture dirs from ty type checking --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index e9bd87766..fe96c54cb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -310,6 +310,9 @@ split-on-trailing-comma = false docstring-code-format = true skip-magic-trailing-comma = true +[tool.ty.src] +exclude = ["tests", "code_to_optimize", "pie_test_set", "experiments"] + [tool.hatch.version] source = "uv-dynamic-versioning" From b058dee829ca0c2362385f6bf4c6293ba44028bb Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 18 Feb 2026 21:57:50 -0500 Subject: [PATCH 051/100] perf: disable Sentry subprocess instrumentation and tracing StdlibIntegration monkeypatches subprocess.Popen, adding span/breadcrumb overhead to every subprocess call. Profiling showed ~342k samples (~8.9% of total runtime) in sentry_sdk.integrations.stdlib and sentry_sdk.utils. Disable subprocess instrumentation and set traces/profiles sample rates to 0 since codeflash is a CLI tool that doesn't need performance tracing. Error capturing (capture_exception, capture_message, LoggingIntegration) remains fully functional. --- codeflash/telemetry/sentry.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/codeflash/telemetry/sentry.py b/codeflash/telemetry/sentry.py index 2357439dc..5f1c2a06b 100644 --- a/codeflash/telemetry/sentry.py +++ b/codeflash/telemetry/sentry.py @@ -2,6 +2,7 @@ import sentry_sdk from sentry_sdk.integrations.logging import LoggingIntegration +from sentry_sdk.integrations.stdlib import StdlibIntegration def init_sentry(*, enabled: bool = False, exclude_errors: bool = False) -> None: @@ -15,13 +16,8 @@ def init_sentry(*, enabled: bool = False, exclude_errors: bool = False) -> None: sentry_sdk.init( dsn="https://4b9a1902f9361b48c04376df6483bc96@o4506833230561280.ingest.sentry.io/4506833262477312", - integrations=[sentry_logging], - # Set traces_sample_rate to 1.0 to capture 100% - # of transactions for performance monitoring. - traces_sample_rate=1.0, - # Set profiles_sample_rate to 1.0 to profile 100% - # of sampled transactions. - # We recommend adjusting this value in production. - profiles_sample_rate=1.0, + integrations=[sentry_logging, StdlibIntegration(subprocess_instrumentation=False)], + traces_sample_rate=0, + profiles_sample_rate=0, ignore_errors=[KeyboardInterrupt], ) From b19e1bda00a3a6bedb15aeb49eb7e205d4215754 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 18 Feb 2026 22:19:02 -0500 Subject: [PATCH 052/100] perf: replace backtracking regexes with character-class patterns in parse_test_output Replace lazy `.*?` quantifiers in matches_re_start/matches_re_end with negated character classes (`[^:]`, `[^#]`, `[^.:]`) to eliminate quadratic backtracking. Replace per-line regex search for the pytest FAILURES header with a simple `"= FAILURES =" in line` string check. Add tests for the regex patterns and failure header detection. --- codeflash/verification/parse_test_output.py | 23 ++- tests/test_parse_test_output_regex.py | 189 ++++++++++++++++++++ 2 files changed, 208 insertions(+), 4 deletions(-) create mode 100644 tests/test_parse_test_output_regex.py diff --git a/codeflash/verification/parse_test_output.py b/codeflash/verification/parse_test_output.py index 4c2c809eb..6fef22a99 100644 --- a/codeflash/verification/parse_test_output.py +++ b/codeflash/verification/parse_test_output.py @@ -47,8 +47,24 @@ def parse_func(file_path: Path) -> XMLParser: return parse(file_path, xml_parser) -matches_re_start = re.compile(r"!\$######(.*?):(.*?)([^\.:]*?):(.*?):(.*?):(.*?)######\$!\n") -matches_re_end = re.compile(r"!######(.*?):(.*?)([^\.:]*?):(.*?):(.*?):(.*?)######!") +matches_re_start = re.compile( + r"!\$######([^:]*)" # group 1: module path + r":((?:[^:.]*\.)*)" # group 2: class prefix with trailing dot, or empty + r"([^.:]*)" # group 3: test function name + r":([^:]*)" # group 4: function being tested + r":([^:]*)" # group 5: loop index + r":([^#]*)" # group 6: iteration id + r"######\$!\n" +) +matches_re_end = re.compile( + r"!######([^:]*)" # group 1: module path + r":((?:[^:.]*\.)*)" # group 2: class prefix with trailing dot, or empty + r"([^.:]*)" # group 3: test function name + r":([^:]*)" # group 4: function being tested + r":([^:]*)" # group 5: loop index + r":([^#]*)" # group 6: iteration_id or iteration_id:runtime + r"######!" +) start_pattern = re.compile(r"!\$######([^:]*):([^:]*):([^:]*):([^:]*):([^:]+)######\$!") @@ -893,7 +909,6 @@ def merge_test_results( return merged_test_results -FAILURES_HEADER_RE = re.compile(r"=+ FAILURES =+") TEST_HEADER_RE = re.compile(r"_{3,}\s*(.*?)\s*_{3,}$") @@ -903,7 +918,7 @@ def parse_test_failures_from_stdout(stdout: str) -> dict[str, str]: start = end = None for i, line in enumerate(lines): - if FAILURES_HEADER_RE.search(line.strip()): + if "= FAILURES =" in line: start = i break diff --git a/tests/test_parse_test_output_regex.py b/tests/test_parse_test_output_regex.py new file mode 100644 index 000000000..d91d57e55 --- /dev/null +++ b/tests/test_parse_test_output_regex.py @@ -0,0 +1,189 @@ +"""Tests for the regex patterns and string matching in parse_test_output.py.""" + +from codeflash.verification.parse_test_output import ( + matches_re_end, + matches_re_start, + parse_test_failures_from_stdout, +) + + +# --- matches_re_start tests --- + + +class TestMatchesReStart: + def test_simple_no_class(self): + s = "!$######tests.test_foo:test_bar:target_func:1:abc######$!\n" + m = matches_re_start.search(s) + assert m is not None + assert m.groups() == ("tests.test_foo", "", "test_bar", "target_func", "1", "abc") + + def test_with_class(self): + s = "!$######tests.test_foo:MyClass.test_bar:target_func:1:abc######$!\n" + m = matches_re_start.search(s) + assert m is not None + assert m.groups() == ("tests.test_foo", "MyClass.", "test_bar", "target_func", "1", "abc") + + def test_nested_class(self): + s = "!$######a.b.c:A.B.test_x:func:3:id123######$!\n" + m = matches_re_start.search(s) + assert m is not None + assert m.groups() == ("a.b.c", "A.B.", "test_x", "func", "3", "id123") + + def test_empty_class_and_function(self): + s = "!$######mod::func:0:iter######$!\n" + m = matches_re_start.search(s) + assert m is not None + assert m.groups() == ("mod", "", "", "func", "0", "iter") + + def test_embedded_in_stdout(self): + s = "some output\n!$######mod:test_fn:f:1:x######$!\nmore output\n" + m = matches_re_start.search(s) + assert m is not None + assert m.groups() == ("mod", "", "test_fn", "f", "1", "x") + + def test_multiple_matches(self): + s = ( + "!$######m1:C1.fn1:t1:1:a######$!\n" + "!$######m2:fn2:t2:2:b######$!\n" + ) + matches = list(matches_re_start.finditer(s)) + assert len(matches) == 2 + assert matches[0].groups() == ("m1", "C1.", "fn1", "t1", "1", "a") + assert matches[1].groups() == ("m2", "", "fn2", "t2", "2", "b") + + def test_no_match_without_newline(self): + s = "!$######mod:test_fn:f:1:x######$!" + m = matches_re_start.search(s) + assert m is None + + def test_dots_in_module_path(self): + s = "!$######a.b.c.d.e:test_fn:f:1:x######$!\n" + m = matches_re_start.search(s) + assert m is not None + assert m.group(1) == "a.b.c.d.e" + + +# --- matches_re_end tests --- + + +class TestMatchesReEnd: + def test_simple_no_class_with_runtime(self): + s = "!######tests.test_foo:test_bar:target_func:1:abc:12345######!" + m = matches_re_end.search(s) + assert m is not None + assert m.groups() == ("tests.test_foo", "", "test_bar", "target_func", "1", "abc:12345") + + def test_with_class_no_runtime(self): + s = "!######tests.test_foo:MyClass.test_bar:target_func:1:abc######!" + m = matches_re_end.search(s) + assert m is not None + assert m.groups() == ("tests.test_foo", "MyClass.", "test_bar", "target_func", "1", "abc") + + def test_nested_class_with_runtime(self): + s = "!######mod:A.B.test_x:func:3:id123:99999######!" + m = matches_re_end.search(s) + assert m is not None + assert m.groups() == ("mod", "A.B.", "test_x", "func", "3", "id123:99999") + + def test_runtime_colon_preserved_in_group6(self): + """Group 6 must capture 'iteration_id:runtime' as a single string (colon included).""" + s = "!######m:fn:f:1:iter42:98765######!" + m = matches_re_end.search(s) + assert m is not None + assert m.group(6) == "iter42:98765" + + def test_embedded_in_stdout(self): + s = "captured output\n!######mod:test_fn:f:1:x:500######!\nmore" + m = matches_re_end.search(s) + assert m is not None + assert m.groups() == ("mod", "", "test_fn", "f", "1", "x:500") + + +# --- Start/End pairing (simulates parse_test_xml matching logic) --- + + +class TestStartEndPairing: + def test_paired_markers(self): + stdout = ( + "!$######mod:Class.test_fn:func:1:iter1######$!\n" + "test output here\n" + "!######mod:Class.test_fn:func:1:iter1:54321######!" + ) + starts = list(matches_re_start.finditer(stdout)) + ends = {} + for match in matches_re_end.finditer(stdout): + groups = match.groups() + g5 = groups[5] + colon_pos = g5.find(":") + if colon_pos != -1: + key = groups[:5] + (g5[:colon_pos],) + else: + key = groups + ends[key] = match + + assert len(starts) == 1 + assert len(ends) == 1 + # Start and end should pair on the first 5 groups + iteration_id + start_groups = starts[0].groups() + assert start_groups in ends + + +# --- parse_test_failures_from_stdout tests --- + + +class TestParseTestFailuresHeader: + def test_standard_pytest_header(self): + stdout = ( + "..F.\n" + "=================================== FAILURES ===================================\n" + "_______ test_foo _______\n" + "\n" + " def test_foo():\n" + "> assert False\n" + "E AssertionError\n" + "\n" + "test.py:3: AssertionError\n" + "=========================== short test summary info ============================\n" + "FAILED test.py::test_foo\n" + ) + result = parse_test_failures_from_stdout(stdout) + assert "test_foo" in result + + def test_minimal_equals(self): + """Even a short '= FAILURES =' header should be detected.""" + stdout = ( + "= FAILURES =\n" + "_______ test_bar _______\n" + "\n" + " assert False\n" + "\n" + "test.py:1: AssertionError\n" + "= short test summary info =\n" + ) + result = parse_test_failures_from_stdout(stdout) + assert "test_bar" in result + + def test_no_failures_section(self): + stdout = "....\n4 passed in 0.1s\n" + result = parse_test_failures_from_stdout(stdout) + assert result == {} + + def test_word_failures_without_equals_is_not_matched(self): + """'FAILURES' without surrounding '=' signs should not trigger the header detection.""" + stdout = ( + "FAILURES detected in module\n" + "_______ test_baz _______\n" + "\n" + " assert False\n" + ) + result = parse_test_failures_from_stdout(stdout) + assert result == {} + + def test_failures_in_test_output_not_matched(self): + """A test printing 'FAILURES' (no = signs) should not trigger header detection.""" + stdout = ( + "Testing FAILURES handling\n" + "All good\n" + ) + result = parse_test_failures_from_stdout(stdout) + assert result == {} From 67ee7340d09ef5741e88c7058a8944b8633c542d Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 18 Feb 2026 22:47:47 -0500 Subject: [PATCH 053/100] perf: remove redundant project_root_path.resolve() from hot path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolve project root paths once at construction time (TestConfig.__post_init__, FunctionOptimizer.__init__, filter_functions entry) instead of on every call to module_name_from_file_path — eliminating ~776 redundant filesystem syscalls. --- codeflash/code_utils/code_utils.py | 2 +- codeflash/discovery/functions_to_optimize.py | 3 ++- codeflash/optimization/function_optimizer.py | 4 ++-- codeflash/verification/verification_utils.py | 4 ++++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/codeflash/code_utils/code_utils.py b/codeflash/code_utils/code_utils.py index 7a9afc96f..c5d3e832f 100644 --- a/codeflash/code_utils/code_utils.py +++ b/codeflash/code_utils/code_utils.py @@ -340,7 +340,7 @@ def get_qualified_name(module_name: str, full_qualified_name: str) -> str: def module_name_from_file_path(file_path: Path, project_root_path: Path, *, traverse_up: bool = False) -> str: try: - relative_path = file_path.resolve().relative_to(project_root_path.resolve()) + relative_path = file_path.resolve().relative_to(project_root_path) return relative_path.with_suffix("").as_posix().replace("/", ".") except ValueError: if traverse_up: diff --git a/codeflash/discovery/functions_to_optimize.py b/codeflash/discovery/functions_to_optimize.py index ed18ed53b..65622801f 100644 --- a/codeflash/discovery/functions_to_optimize.py +++ b/codeflash/discovery/functions_to_optimize.py @@ -836,6 +836,7 @@ def filter_functions( *, disable_logs: bool = False, ) -> tuple[dict[Path, list[FunctionToOptimize]], int]: + resolved_project_root = project_root.resolve() filtered_modified_functions: dict[str, list[FunctionToOptimize]] = {} blocklist_funcs = get_blocklisted_functions() logger.debug(f"Blocklisted functions: {blocklist_funcs}") @@ -912,7 +913,7 @@ def is_test_file(file_path_normalized: str) -> bool: lang_support = get_language_support(Path(file_path)) if lang_support.language == Language.PYTHON: try: - ast.parse(f"import {module_name_from_file_path(Path(file_path), project_root)}") + ast.parse(f"import {module_name_from_file_path(Path(file_path), resolved_project_root)}") except SyntaxError: malformed_paths_count += 1 continue diff --git a/codeflash/optimization/function_optimizer.py b/codeflash/optimization/function_optimizer.py index 7cbcda976..3269869ac 100644 --- a/codeflash/optimization/function_optimizer.py +++ b/codeflash/optimization/function_optimizer.py @@ -443,7 +443,7 @@ def __init__( args: Namespace | None = None, replay_tests_dir: Path | None = None, ) -> None: - self.project_root = test_cfg.project_root_path + self.project_root = test_cfg.project_root_path.resolve() self.test_cfg = test_cfg self.aiservice_client = aiservice_client if aiservice_client else AiServiceClient() self.function_to_optimize = function_to_optimize @@ -1451,7 +1451,7 @@ def reformat_code_and_helpers( optimized_code = "" if optimized_context is not None: file_to_code_context = optimized_context.file_to_path() - optimized_code = file_to_code_context.get(str(path.relative_to(self.project_root)), "") + optimized_code = file_to_code_context.get(str(path.resolve().relative_to(self.project_root)), "") new_code = format_code( self.args.formatter_cmds, path, optimized_code=optimized_code, check_diff=True, exit_on_failure=False diff --git a/codeflash/verification/verification_utils.py b/codeflash/verification/verification_utils.py index c567e6a9a..d586d9962 100644 --- a/codeflash/verification/verification_utils.py +++ b/codeflash/verification/verification_utils.py @@ -158,6 +158,10 @@ class TestConfig: _language: Optional[str] = None # Language identifier for multi-language support js_project_root: Optional[Path] = None # JavaScript project root (directory containing package.json) + def __post_init__(self) -> None: + self.project_root_path = self.project_root_path.resolve() + self.tests_project_rootdir = self.tests_project_rootdir.resolve() + @property def test_framework(self) -> str: """Returns the appropriate test framework based on language. From 377083a0f032a911e87940d556afa6976b2cce29 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 03:51:11 +0000 Subject: [PATCH 054/100] style: auto-fix ruff formatting in parse_test_output.py --- codeflash/verification/parse_test_output.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/codeflash/verification/parse_test_output.py b/codeflash/verification/parse_test_output.py index 6fef22a99..53012feb1 100644 --- a/codeflash/verification/parse_test_output.py +++ b/codeflash/verification/parse_test_output.py @@ -50,19 +50,19 @@ def parse_func(file_path: Path) -> XMLParser: matches_re_start = re.compile( r"!\$######([^:]*)" # group 1: module path r":((?:[^:.]*\.)*)" # group 2: class prefix with trailing dot, or empty - r"([^.:]*)" # group 3: test function name - r":([^:]*)" # group 4: function being tested - r":([^:]*)" # group 5: loop index - r":([^#]*)" # group 6: iteration id + r"([^.:]*)" # group 3: test function name + r":([^:]*)" # group 4: function being tested + r":([^:]*)" # group 5: loop index + r":([^#]*)" # group 6: iteration id r"######\$!\n" ) matches_re_end = re.compile( - r"!######([^:]*)" # group 1: module path + r"!######([^:]*)" # group 1: module path r":((?:[^:.]*\.)*)" # group 2: class prefix with trailing dot, or empty - r"([^.:]*)" # group 3: test function name - r":([^:]*)" # group 4: function being tested - r":([^:]*)" # group 5: loop index - r":([^#]*)" # group 6: iteration_id or iteration_id:runtime + r"([^.:]*)" # group 3: test function name + r":([^:]*)" # group 4: function being tested + r":([^:]*)" # group 5: loop index + r":([^#]*)" # group 6: iteration_id or iteration_id:runtime r"######!" ) From 486f6b81d1b27dc995809946200813797d76536c Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 18 Feb 2026 22:51:58 -0500 Subject: [PATCH 055/100] fix: use disabled_integrations to exclude StdlibIntegration StdlibIntegration in sentry-sdk 2.x doesn't accept subprocess_instrumentation as a parameter. Use disabled_integrations instead, which also avoids httplib patching overhead. --- codeflash/telemetry/sentry.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/codeflash/telemetry/sentry.py b/codeflash/telemetry/sentry.py index 5f1c2a06b..3ee266326 100644 --- a/codeflash/telemetry/sentry.py +++ b/codeflash/telemetry/sentry.py @@ -16,7 +16,8 @@ def init_sentry(*, enabled: bool = False, exclude_errors: bool = False) -> None: sentry_sdk.init( dsn="https://4b9a1902f9361b48c04376df6483bc96@o4506833230561280.ingest.sentry.io/4506833262477312", - integrations=[sentry_logging, StdlibIntegration(subprocess_instrumentation=False)], + integrations=[sentry_logging], + disabled_integrations=[StdlibIntegration], traces_sample_rate=0, profiles_sample_rate=0, ignore_errors=[KeyboardInterrupt], From 89952791bec67c504f4636ce40be2905827aaab6 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 03:56:13 +0000 Subject: [PATCH 056/100] style: add return type annotations to test methods --- tests/test_parse_test_output_regex.py | 38 +++++++++++++-------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/tests/test_parse_test_output_regex.py b/tests/test_parse_test_output_regex.py index d91d57e55..e313885ab 100644 --- a/tests/test_parse_test_output_regex.py +++ b/tests/test_parse_test_output_regex.py @@ -11,37 +11,37 @@ class TestMatchesReStart: - def test_simple_no_class(self): + def test_simple_no_class(self) -> None: s = "!$######tests.test_foo:test_bar:target_func:1:abc######$!\n" m = matches_re_start.search(s) assert m is not None assert m.groups() == ("tests.test_foo", "", "test_bar", "target_func", "1", "abc") - def test_with_class(self): + def test_with_class(self) -> None: s = "!$######tests.test_foo:MyClass.test_bar:target_func:1:abc######$!\n" m = matches_re_start.search(s) assert m is not None assert m.groups() == ("tests.test_foo", "MyClass.", "test_bar", "target_func", "1", "abc") - def test_nested_class(self): + def test_nested_class(self) -> None: s = "!$######a.b.c:A.B.test_x:func:3:id123######$!\n" m = matches_re_start.search(s) assert m is not None assert m.groups() == ("a.b.c", "A.B.", "test_x", "func", "3", "id123") - def test_empty_class_and_function(self): + def test_empty_class_and_function(self) -> None: s = "!$######mod::func:0:iter######$!\n" m = matches_re_start.search(s) assert m is not None assert m.groups() == ("mod", "", "", "func", "0", "iter") - def test_embedded_in_stdout(self): + def test_embedded_in_stdout(self) -> None: s = "some output\n!$######mod:test_fn:f:1:x######$!\nmore output\n" m = matches_re_start.search(s) assert m is not None assert m.groups() == ("mod", "", "test_fn", "f", "1", "x") - def test_multiple_matches(self): + def test_multiple_matches(self) -> None: s = ( "!$######m1:C1.fn1:t1:1:a######$!\n" "!$######m2:fn2:t2:2:b######$!\n" @@ -51,12 +51,12 @@ def test_multiple_matches(self): assert matches[0].groups() == ("m1", "C1.", "fn1", "t1", "1", "a") assert matches[1].groups() == ("m2", "", "fn2", "t2", "2", "b") - def test_no_match_without_newline(self): + def test_no_match_without_newline(self) -> None: s = "!$######mod:test_fn:f:1:x######$!" m = matches_re_start.search(s) assert m is None - def test_dots_in_module_path(self): + def test_dots_in_module_path(self) -> None: s = "!$######a.b.c.d.e:test_fn:f:1:x######$!\n" m = matches_re_start.search(s) assert m is not None @@ -67,32 +67,32 @@ def test_dots_in_module_path(self): class TestMatchesReEnd: - def test_simple_no_class_with_runtime(self): + def test_simple_no_class_with_runtime(self) -> None: s = "!######tests.test_foo:test_bar:target_func:1:abc:12345######!" m = matches_re_end.search(s) assert m is not None assert m.groups() == ("tests.test_foo", "", "test_bar", "target_func", "1", "abc:12345") - def test_with_class_no_runtime(self): + def test_with_class_no_runtime(self) -> None: s = "!######tests.test_foo:MyClass.test_bar:target_func:1:abc######!" m = matches_re_end.search(s) assert m is not None assert m.groups() == ("tests.test_foo", "MyClass.", "test_bar", "target_func", "1", "abc") - def test_nested_class_with_runtime(self): + def test_nested_class_with_runtime(self) -> None: s = "!######mod:A.B.test_x:func:3:id123:99999######!" m = matches_re_end.search(s) assert m is not None assert m.groups() == ("mod", "A.B.", "test_x", "func", "3", "id123:99999") - def test_runtime_colon_preserved_in_group6(self): + def test_runtime_colon_preserved_in_group6(self) -> None: """Group 6 must capture 'iteration_id:runtime' as a single string (colon included).""" s = "!######m:fn:f:1:iter42:98765######!" m = matches_re_end.search(s) assert m is not None assert m.group(6) == "iter42:98765" - def test_embedded_in_stdout(self): + def test_embedded_in_stdout(self) -> None: s = "captured output\n!######mod:test_fn:f:1:x:500######!\nmore" m = matches_re_end.search(s) assert m is not None @@ -103,7 +103,7 @@ def test_embedded_in_stdout(self): class TestStartEndPairing: - def test_paired_markers(self): + def test_paired_markers(self) -> None: stdout = ( "!$######mod:Class.test_fn:func:1:iter1######$!\n" "test output here\n" @@ -132,7 +132,7 @@ def test_paired_markers(self): class TestParseTestFailuresHeader: - def test_standard_pytest_header(self): + def test_standard_pytest_header(self) -> None: stdout = ( "..F.\n" "=================================== FAILURES ===================================\n" @@ -149,7 +149,7 @@ def test_standard_pytest_header(self): result = parse_test_failures_from_stdout(stdout) assert "test_foo" in result - def test_minimal_equals(self): + def test_minimal_equals(self) -> None: """Even a short '= FAILURES =' header should be detected.""" stdout = ( "= FAILURES =\n" @@ -163,12 +163,12 @@ def test_minimal_equals(self): result = parse_test_failures_from_stdout(stdout) assert "test_bar" in result - def test_no_failures_section(self): + def test_no_failures_section(self) -> None: stdout = "....\n4 passed in 0.1s\n" result = parse_test_failures_from_stdout(stdout) assert result == {} - def test_word_failures_without_equals_is_not_matched(self): + def test_word_failures_without_equals_is_not_matched(self) -> None: """'FAILURES' without surrounding '=' signs should not trigger the header detection.""" stdout = ( "FAILURES detected in module\n" @@ -179,7 +179,7 @@ def test_word_failures_without_equals_is_not_matched(self): result = parse_test_failures_from_stdout(stdout) assert result == {} - def test_failures_in_test_output_not_matched(self): + def test_failures_in_test_output_not_matched(self) -> None: """A test printing 'FAILURES' (no = signs) should not trigger header detection.""" stdout = ( "Testing FAILURES handling\n" From 474258595a6b212c2e2641fd57b3ad52d515e5c4 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 18 Feb 2026 23:00:07 -0500 Subject: [PATCH 057/100] perf: remove remaining redundant .resolve() calls on pre-resolved paths Drop .resolve() from ImportResolver, TestsCache, init_javascript, create_pr, and filter_functions where callers already pass resolved paths via CLI init or TestConfig.__post_init__. --- codeflash/cli_cmds/init_javascript.py | 4 ++-- codeflash/discovery/discover_unit_tests.py | 4 ++-- codeflash/discovery/functions_to_optimize.py | 2 +- codeflash/languages/javascript/import_resolver.py | 3 +-- codeflash/result/create_pr.py | 4 ++-- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/codeflash/cli_cmds/init_javascript.py b/codeflash/cli_cmds/init_javascript.py index d88c69904..e43bdc167 100644 --- a/codeflash/cli_cmds/init_javascript.py +++ b/codeflash/cli_cmds/init_javascript.py @@ -128,7 +128,7 @@ def determine_js_package_manager(project_root: Path) -> JsPackageManager: """ # Search from project_root up to filesystem root for lock files # This supports monorepo setups where lock file is at workspace root - current_dir = project_root.resolve() + current_dir = project_root while current_dir != current_dir.parent: if (current_dir / "bun.lockb").exists() or (current_dir / "bun.lock").exists(): return JsPackageManager.BUN @@ -161,7 +161,7 @@ def find_node_modules_with_package(project_root: Path, package_name: str) -> Pat Path to the node_modules directory containing the package, or None if not found. """ - current_dir = project_root.resolve() + current_dir = project_root while current_dir != current_dir.parent: node_modules = current_dir / "node_modules" if node_modules.exists(): diff --git a/codeflash/discovery/discover_unit_tests.py b/codeflash/discovery/discover_unit_tests.py index d1ef28a8d..c01a2f2e1 100644 --- a/codeflash/discovery/discover_unit_tests.py +++ b/codeflash/discovery/discover_unit_tests.py @@ -69,8 +69,8 @@ class TestFunction: class TestsCache: SCHEMA_VERSION = 1 # Increment this when schema changes - def __init__(self, project_root_path: str | Path) -> None: - self.project_root_path = Path(project_root_path).resolve().as_posix() + def __init__(self, project_root_path: Path) -> None: + self.project_root_path = project_root_path.as_posix() self.connection = sqlite3.connect(codeflash_cache_db) self.cur = self.connection.cursor() diff --git a/codeflash/discovery/functions_to_optimize.py b/codeflash/discovery/functions_to_optimize.py index 65622801f..d0bfe6c02 100644 --- a/codeflash/discovery/functions_to_optimize.py +++ b/codeflash/discovery/functions_to_optimize.py @@ -935,7 +935,7 @@ def is_test_file(file_path_normalized: str) -> bool: if previous_checkpoint_functions: functions_tmp = [] for function in _functions: - if function.qualified_name_with_modules_from_root(project_root) in previous_checkpoint_functions: + if function.qualified_name_with_modules_from_root(resolved_project_root) in previous_checkpoint_functions: previous_checkpoint_functions_removed_count += 1 continue functions_tmp.append(function) diff --git a/codeflash/languages/javascript/import_resolver.py b/codeflash/languages/javascript/import_resolver.py index 8f5dbe8ca..b5ec67115 100644 --- a/codeflash/languages/javascript/import_resolver.py +++ b/codeflash/languages/javascript/import_resolver.py @@ -44,8 +44,7 @@ def __init__(self, project_root: Path) -> None: project_root: Root directory of the project. """ - # Resolve to real path to handle macOS symlinks like /var -> /private/var - self.project_root = project_root.resolve() + self.project_root = project_root self._resolution_cache: dict[tuple[Path, str], Path | None] = {} def resolve_import(self, import_info: ImportInfo, source_file: Path) -> ResolvedImport | None: diff --git a/codeflash/result/create_pr.py b/codeflash/result/create_pr.py index 0be4e1cf8..b276725f2 100644 --- a/codeflash/result/create_pr.py +++ b/codeflash/result/create_pr.py @@ -126,10 +126,10 @@ def existing_tests_source_for( tests_dir_name = test_cfg.tests_project_rootdir.name if file_path.startswith((tests_dir_name + os.sep, tests_dir_name + "/")): # Module path includes "tests." - use project root parent - instrumented_abs_path = (test_cfg.tests_project_rootdir.parent / file_path).resolve() + instrumented_abs_path = test_cfg.tests_project_rootdir.parent / file_path else: # Module path doesn't include tests dir - use tests root directly - instrumented_abs_path = (test_cfg.tests_project_rootdir / file_path).resolve() + instrumented_abs_path = test_cfg.tests_project_rootdir / file_path logger.debug(f"[PR-DEBUG] Looking up: {instrumented_abs_path}") logger.debug(f"[PR-DEBUG] Available keys: {list(instrumented_to_original.keys())[:3]}") # Try to map instrumented path to original path From dc9c60a0617943c94c1a74fed4d0ec9e0ff087f8 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 18 Feb 2026 23:05:04 -0500 Subject: [PATCH 058/100] perf: remove remaining redundant .resolve() calls on pre-resolved paths Drop .resolve() from ImportResolver, TestsCache, init_javascript, create_pr, and filter_functions where callers already pass resolved paths via CLI init or TestConfig.__post_init__. Also exclude test and fixture dirs from mypy to match ruff/ty config. --- pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index fe96c54cb..56736fc6c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -207,6 +207,8 @@ warn_unreachable = true install_types = true plugins = ["pydantic.mypy"] +exclude = ["tests/", "code_to_optimize/", "pie_test_set/", "experiments/"] + [[tool.mypy.overrides]] module = ["jedi", "jedi.api.classes", "inquirer", "inquirer.themes", "numba"] ignore_missing_imports = true From ac096d90757ddbd2b72bea70ebbd9c9a69a202e3 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 04:07:49 +0000 Subject: [PATCH 059/100] style: auto-fix line length formatting in functions_to_optimize.py --- codeflash/discovery/functions_to_optimize.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/codeflash/discovery/functions_to_optimize.py b/codeflash/discovery/functions_to_optimize.py index d0bfe6c02..14455b890 100644 --- a/codeflash/discovery/functions_to_optimize.py +++ b/codeflash/discovery/functions_to_optimize.py @@ -935,7 +935,10 @@ def is_test_file(file_path_normalized: str) -> bool: if previous_checkpoint_functions: functions_tmp = [] for function in _functions: - if function.qualified_name_with_modules_from_root(resolved_project_root) in previous_checkpoint_functions: + if ( + function.qualified_name_with_modules_from_root(resolved_project_root) + in previous_checkpoint_functions + ): previous_checkpoint_functions_removed_count += 1 continue functions_tmp.append(function) From e2859088d75c98c99f44e0d2521504841176841e Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 18 Feb 2026 23:14:51 -0500 Subject: [PATCH 060/100] fix: resolve tests_project_root at inject_profiling entry point Paths with .. segments (e.g. Path(__file__) / "../foo") don't match resolved file_path in module_name_from_file_path. Resolve once at the public entry point and pass down to the async variant. Also exclude test dirs from mypy config. --- codeflash/code_utils/instrument_existing_tests.py | 1 + 1 file changed, 1 insertion(+) diff --git a/codeflash/code_utils/instrument_existing_tests.py b/codeflash/code_utils/instrument_existing_tests.py index 9486fc677..f15b2d56a 100644 --- a/codeflash/code_utils/instrument_existing_tests.py +++ b/codeflash/code_utils/instrument_existing_tests.py @@ -709,6 +709,7 @@ def inject_profiling_into_existing_test( tests_project_root: Path, mode: TestingMode = TestingMode.BEHAVIOR, ) -> tuple[bool, str | None]: + tests_project_root = tests_project_root.resolve() if function_to_optimize.is_async: return inject_async_profiling_into_existing_test( test_path, call_positions, function_to_optimize, tests_project_root, mode From b3fd6bf085559b31e096f648b8d7d12a5c1e3922 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 18 Feb 2026 23:47:04 -0500 Subject: [PATCH 061/100] fix: resolve both sides of path comparisons for Windows 8.3 name consistency On Windows, Path.resolve() can return 8.3 short names (e.g. RUNNER~1) that differ from long-name forms. Jedi returns resolved paths that may not match the project root's form, causing relative_to() failures. - Normalize Jedi definition paths through the project root via safe_relative_to to ensure consistent dict keys - Resolve both sides in is_project_path and module_name_from_file_path - Restore resolve in TestsCache for consistent cache keys --- codeflash/code_utils/code_utils.py | 2 +- codeflash/discovery/discover_unit_tests.py | 2 +- .../languages/python/context/code_context_extractor.py | 9 ++++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/codeflash/code_utils/code_utils.py b/codeflash/code_utils/code_utils.py index c5d3e832f..7a9afc96f 100644 --- a/codeflash/code_utils/code_utils.py +++ b/codeflash/code_utils/code_utils.py @@ -340,7 +340,7 @@ def get_qualified_name(module_name: str, full_qualified_name: str) -> str: def module_name_from_file_path(file_path: Path, project_root_path: Path, *, traverse_up: bool = False) -> str: try: - relative_path = file_path.resolve().relative_to(project_root_path) + relative_path = file_path.resolve().relative_to(project_root_path.resolve()) return relative_path.with_suffix("").as_posix().replace("/", ".") except ValueError: if traverse_up: diff --git a/codeflash/discovery/discover_unit_tests.py b/codeflash/discovery/discover_unit_tests.py index c01a2f2e1..1a032ec36 100644 --- a/codeflash/discovery/discover_unit_tests.py +++ b/codeflash/discovery/discover_unit_tests.py @@ -70,7 +70,7 @@ class TestsCache: SCHEMA_VERSION = 1 # Increment this when schema changes def __init__(self, project_root_path: Path) -> None: - self.project_root_path = project_root_path.as_posix() + self.project_root_path = project_root_path.resolve().as_posix() self.connection = sqlite3.connect(codeflash_cache_db) self.cur = self.connection.cursor() diff --git a/codeflash/languages/python/context/code_context_extractor.py b/codeflash/languages/python/context/code_context_extractor.py index 09b045dcc..3bb644b5d 100644 --- a/codeflash/languages/python/context/code_context_extractor.py +++ b/codeflash/languages/python/context/code_context_extractor.py @@ -512,6 +512,9 @@ def get_function_sources_from_jedi( # TODO: there can be multiple definitions, see how to handle such cases definition = definitions[0] definition_path = definition.module_path + rel = safe_relative_to(definition_path, project_root_path) + if not rel.is_absolute(): + definition_path = project_root_path / rel # The definition is part of this project and not defined within the original function is_valid_definition = ( @@ -936,7 +939,11 @@ def is_project_path(module_path: Path | None, project_root_path: Path) -> bool: # site-packages must be checked first because .venv/site-packages is under project root if path_belongs_to_site_packages(module_path): return False - return str(module_path).startswith(str(project_root_path) + os.sep) + try: + module_path.resolve().relative_to(project_root_path.resolve()) + return True + except ValueError: + return False def _is_project_module(module_name: str, project_root_path: Path) -> bool: From a726b4644e43a2acf469478a2ad4159ebf3ef510 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Wed, 18 Feb 2026 23:51:13 -0500 Subject: [PATCH 062/100] fix: guard against None definition_path from Jedi --- .../languages/python/context/code_context_extractor.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/codeflash/languages/python/context/code_context_extractor.py b/codeflash/languages/python/context/code_context_extractor.py index 3bb644b5d..55c3c4620 100644 --- a/codeflash/languages/python/context/code_context_extractor.py +++ b/codeflash/languages/python/context/code_context_extractor.py @@ -512,9 +512,10 @@ def get_function_sources_from_jedi( # TODO: there can be multiple definitions, see how to handle such cases definition = definitions[0] definition_path = definition.module_path - rel = safe_relative_to(definition_path, project_root_path) - if not rel.is_absolute(): - definition_path = project_root_path / rel + if definition_path is not None: + rel = safe_relative_to(definition_path, project_root_path) + if not rel.is_absolute(): + definition_path = project_root_path / rel # The definition is part of this project and not defined within the original function is_valid_definition = ( From 5efa1eeb0aa767224629d7a0588129efd13e7b3f Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 04:53:24 +0000 Subject: [PATCH 063/100] style: remove unused os import in code_context_extractor --- codeflash/languages/python/context/code_context_extractor.py | 1 - 1 file changed, 1 deletion(-) diff --git a/codeflash/languages/python/context/code_context_extractor.py b/codeflash/languages/python/context/code_context_extractor.py index 55c3c4620..9a4daf726 100644 --- a/codeflash/languages/python/context/code_context_extractor.py +++ b/codeflash/languages/python/context/code_context_extractor.py @@ -2,7 +2,6 @@ import ast import hashlib -import os from collections import defaultdict from itertools import chain from pathlib import Path From 74246e66544141074a543ae8c20cd61e9c4e470d Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 05:09:39 +0000 Subject: [PATCH 064/100] fix: resolve function_to_optimize.file_path for Windows 8.3 name consistency TestConfig.__post_init__ resolves project_root_path to long names, but FunctionToOptimize.file_path could retain Windows 8.3 short names (e.g., RUNNER~1 vs runneradmin), causing relative_to() failures. Co-authored-by: Kevin Turcios Co-Authored-By: Claude Opus 4.6 --- codeflash/optimization/function_optimizer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/codeflash/optimization/function_optimizer.py b/codeflash/optimization/function_optimizer.py index 3269869ac..b5a607531 100644 --- a/codeflash/optimization/function_optimizer.py +++ b/codeflash/optimization/function_optimizer.py @@ -447,6 +447,7 @@ def __init__( self.test_cfg = test_cfg self.aiservice_client = aiservice_client if aiservice_client else AiServiceClient() self.function_to_optimize = function_to_optimize + self.function_to_optimize.file_path = self.function_to_optimize.file_path.resolve() self.function_to_optimize_source_code = ( function_to_optimize_source_code if function_to_optimize_source_code From 3cdf7100cf89f7241c293e0d27828a1d15452111 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 05:16:04 +0000 Subject: [PATCH 065/100] fix: use dataclasses.replace() for frozen FunctionToOptimize path resolution FunctionToOptimize is a frozen Pydantic dataclass, so directly assigning to file_path raises FrozenInstanceError. Use dataclasses.replace() to create a new instance with the resolved path instead. Co-authored-by: Kevin Turcios --- codeflash/optimization/function_optimizer.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/codeflash/optimization/function_optimizer.py b/codeflash/optimization/function_optimizer.py index b5a607531..c24d84ae5 100644 --- a/codeflash/optimization/function_optimizer.py +++ b/codeflash/optimization/function_optimizer.py @@ -2,6 +2,7 @@ import ast import concurrent.futures +import dataclasses import logging import os import queue @@ -446,8 +447,10 @@ def __init__( self.project_root = test_cfg.project_root_path.resolve() self.test_cfg = test_cfg self.aiservice_client = aiservice_client if aiservice_client else AiServiceClient() + resolved_file_path = function_to_optimize.file_path.resolve() + if resolved_file_path != function_to_optimize.file_path: + function_to_optimize = dataclasses.replace(function_to_optimize, file_path=resolved_file_path) self.function_to_optimize = function_to_optimize - self.function_to_optimize.file_path = self.function_to_optimize.file_path.resolve() self.function_to_optimize_source_code = ( function_to_optimize_source_code if function_to_optimize_source_code From 8f65c9f78825a96aba33beee3146974e05c1edac Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 05:30:11 +0000 Subject: [PATCH 066/100] fix: resolve paths in revert_unused_helper_functions for Windows 8.3 name consistency On Windows, tempfile.mkdtemp() returns paths with 8.3 short names while Jedi resolves to long-form paths. The dict lookup for original_helper_code failed silently, causing unused helpers to never be reverted. Co-authored-by: Kevin Turcios Co-Authored-By: Claude Opus 4.6 --- .../python/context/unused_definition_remover.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/codeflash/languages/python/context/unused_definition_remover.py b/codeflash/languages/python/context/unused_definition_remover.py index 38b58f63e..ba6e4d549 100644 --- a/codeflash/languages/python/context/unused_definition_remover.py +++ b/codeflash/languages/python/context/unused_definition_remover.py @@ -587,17 +587,20 @@ def revert_unused_helper_functions( logger.debug(f"Reverting {len(unused_helpers)} unused helper function(s) to original definitions") + # Resolve all path keys for consistent comparison (Windows 8.3 short names may differ from Jedi-resolved paths) + resolved_original_helper_code = {p.resolve(): code for p, code in original_helper_code.items()} + # Group unused helpers by file path unused_helpers_by_file = defaultdict(list) for helper in unused_helpers: - unused_helpers_by_file[helper.file_path].append(helper) + unused_helpers_by_file[helper.file_path.resolve()].append(helper) # For each file, revert the unused helper functions to their original definitions for file_path, helpers_in_file in unused_helpers_by_file.items(): - if file_path in original_helper_code: + if file_path in resolved_original_helper_code: try: # Get original code for this file - original_code = original_helper_code[file_path] + original_code = resolved_original_helper_code[file_path] # Use the code replacer to selectively revert only the unused helper functions helper_names = [helper.qualified_name for helper in helpers_in_file] From 522969baadbf3a283ac96e314c0f2a37f7e8fc04 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 01:17:11 -0500 Subject: [PATCH 067/100] fix: restore call_graph parameter to get_code_optimization_context Add DependencyResolver parameter back to get_code_optimization_context() that was lost during file move from codeflash/context/ to codeflash/languages/python/context/. When call_graph is available, use it for helper discovery instead of Jedi-based fallback. --- .../python/context/code_context_extractor.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/codeflash/languages/python/context/code_context_extractor.py b/codeflash/languages/python/context/code_context_extractor.py index 9a4daf726..5ef02d788 100644 --- a/codeflash/languages/python/context/code_context_extractor.py +++ b/codeflash/languages/python/context/code_context_extractor.py @@ -36,7 +36,7 @@ if TYPE_CHECKING: from jedi.api.classes import Name - from codeflash.languages.base import HelperFunction + from codeflash.languages.base import DependencyResolver, HelperFunction from codeflash.languages.python.context.unused_definition_remover import UsageInfo # Error message constants @@ -80,6 +80,7 @@ def get_code_optimization_context( project_root_path: Path, optim_token_limit: int = OPTIMIZATION_CONTEXT_TOKEN_LIMIT, testgen_token_limit: int = TESTGEN_CONTEXT_TOKEN_LIMIT, + call_graph: DependencyResolver | None = None, ) -> CodeOptimizationContext: # Route to language-specific implementation for non-Python languages if not is_python(): @@ -88,9 +89,11 @@ def get_code_optimization_context( ) # Get FunctionSource representation of helpers of FTO - helpers_of_fto_dict, helpers_of_fto_list = get_function_sources_from_jedi( - {function_to_optimize.file_path: {function_to_optimize.qualified_name}}, project_root_path - ) + fto_input = {function_to_optimize.file_path: {function_to_optimize.qualified_name}} + if call_graph is not None: + helpers_of_fto_dict, helpers_of_fto_list = call_graph.get_callees(fto_input) + else: + helpers_of_fto_dict, helpers_of_fto_list = get_function_sources_from_jedi(fto_input, project_root_path) # Add function to optimize into helpers of FTO dict, as they'll be processed together fto_as_function_source = get_function_to_optimize_as_function_source(function_to_optimize, project_root_path) From 3e282ee293f37226b80f4a0fda2c1b7e3b4fac9e Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 01:26:37 -0500 Subject: [PATCH 068/100] fix: address security vulnerabilities while maintaining Python 3.9 support Resolve 12 Dependabot security alerts by constraining vulnerable packages to Python 3.10+ where patches are available: Python dependencies: - filelock: Pin <3.20.3 for Python 3.9, >=3.20.3 for Python 3.10+ (fixes TOCTOU symlink vulnerabilities CVE-2024-XXXXX) - tensorflow: Only install on Python 3.10+ (brings keras >=3.12.1, pillow >=12.1.1) (fixes 8 high-severity keras vulnerabilities including arbitrary code execution, directory traversal, and 1 high-severity pillow out-of-bounds write) JavaScript dependencies: - vitest: Update to latest (4.0.18) in test fixture directory (fixes moderate-severity esbuild SSRF vulnerability GHSA-67mh-4wv8-2f99) Python 3.9 notes: - filelock 3.19.1 has known TOCTOU vulnerabilities (medium severity) - tensorflow/keras/pillow excluded from Python 3.9 test dependencies - Python 3.9 reached EOL in October 2025, vulnerabilities are expected All high-severity vulnerabilities are resolved for Python 3.10+. Python 3.9 users should upgrade to 3.10+ for full security patches. --- .../code_to_optimize_vitest/package-lock.json | 704 ++++++++++-------- .../js/code_to_optimize_vitest/package.json | 2 +- pyproject.toml | 5 +- uv.lock | 395 ++-------- 4 files changed, 423 insertions(+), 683 deletions(-) diff --git a/code_to_optimize/js/code_to_optimize_vitest/package-lock.json b/code_to_optimize/js/code_to_optimize_vitest/package-lock.json index ef24dc459..72efb95c9 100644 --- a/code_to_optimize/js/code_to_optimize_vitest/package-lock.json +++ b/code_to_optimize/js/code_to_optimize_vitest/package-lock.json @@ -11,7 +11,7 @@ "@types/node": "^20.0.0", "codeflash": "file:../../../packages/codeflash", "typescript": "^5.0.0", - "vitest": "^2.0.0" + "vitest": "^4.0.18" } }, "../../../packages/codeflash": { @@ -48,9 +48,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", "cpu": [ "ppc64" ], @@ -61,13 +61,13 @@ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", "cpu": [ "arm" ], @@ -78,13 +78,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", "cpu": [ "arm64" ], @@ -95,13 +95,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", "cpu": [ "x64" ], @@ -112,13 +112,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", "cpu": [ "arm64" ], @@ -129,13 +129,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", "cpu": [ "x64" ], @@ -146,13 +146,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", "cpu": [ "arm64" ], @@ -163,13 +163,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", "cpu": [ "x64" ], @@ -180,13 +180,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", "cpu": [ "arm" ], @@ -197,13 +197,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", "cpu": [ "arm64" ], @@ -214,13 +214,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", "cpu": [ "ia32" ], @@ -231,13 +231,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", "cpu": [ "loong64" ], @@ -248,13 +248,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", "cpu": [ "mips64el" ], @@ -265,13 +265,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", "cpu": [ "ppc64" ], @@ -282,13 +282,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", "cpu": [ "riscv64" ], @@ -299,13 +299,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", "cpu": [ "s390x" ], @@ -316,13 +316,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", "cpu": [ "x64" ], @@ -333,13 +333,30 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", "cpu": [ "x64" ], @@ -350,13 +367,30 @@ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", "cpu": [ "x64" ], @@ -367,13 +401,30 @@ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", "cpu": [ "x64" ], @@ -384,13 +435,13 @@ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", "cpu": [ "arm64" ], @@ -401,13 +452,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", "cpu": [ "ia32" ], @@ -418,13 +469,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", "cpu": [ "x64" ], @@ -435,7 +486,7 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@jridgewell/sourcemap-codec": { @@ -795,6 +846,31 @@ "win32" ] }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -803,9 +879,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.19.30", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.30.tgz", - "integrity": "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==", + "version": "20.19.33", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.33.tgz", + "integrity": "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw==", "dev": true, "license": "MIT", "dependencies": { @@ -813,38 +889,40 @@ } }, "node_modules/@vitest/expect": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.9.tgz", - "integrity": "sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==", + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", + "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "2.1.9", - "@vitest/utils": "2.1.9", - "chai": "^5.1.2", - "tinyrainbow": "^1.2.0" + "@standard-schema/spec": "^1.0.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "chai": "^6.2.1", + "tinyrainbow": "^3.0.3" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/mocker": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.9.tgz", - "integrity": "sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==", + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", + "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "2.1.9", + "@vitest/spy": "4.0.18", "estree-walker": "^3.0.3", - "magic-string": "^0.30.12" + "magic-string": "^0.30.21" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { "msw": "^2.4.9", - "vite": "^5.0.0" + "vite": "^6.0.0 || ^7.0.0-0" }, "peerDependenciesMeta": { "msw": { @@ -856,70 +934,66 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz", - "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==", + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", + "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", "dev": true, "license": "MIT", "dependencies": { - "tinyrainbow": "^1.2.0" + "tinyrainbow": "^3.0.3" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/runner": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.9.tgz", - "integrity": "sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==", + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", + "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "2.1.9", - "pathe": "^1.1.2" + "@vitest/utils": "4.0.18", + "pathe": "^2.0.3" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/snapshot": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.9.tgz", - "integrity": "sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==", + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", + "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "2.1.9", - "magic-string": "^0.30.12", - "pathe": "^1.1.2" + "@vitest/pretty-format": "4.0.18", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/spy": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.9.tgz", - "integrity": "sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==", + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", + "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", "dev": true, "license": "MIT", - "dependencies": { - "tinyspy": "^3.0.2" - }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/utils": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.9.tgz", - "integrity": "sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==", + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", + "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "2.1.9", - "loupe": "^3.1.2", - "tinyrainbow": "^1.2.0" + "@vitest/pretty-format": "4.0.18", + "tinyrainbow": "^3.0.3" }, "funding": { "url": "https://opencollective.com/vitest" @@ -935,75 +1009,20 @@ "node": ">=12" } }, - "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/chai": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", - "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", "dev": true, "license": "MIT", - "dependencies": { - "assertion-error": "^2.0.1", - "check-error": "^2.1.1", - "deep-eql": "^5.0.1", - "loupe": "^3.1.0", - "pathval": "^2.0.0" - }, "engines": { "node": ">=18" } }, - "node_modules/check-error": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", - "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - } - }, "node_modules/codeflash": { "resolved": "../../../packages/codeflash", "link": true }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-eql": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", - "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/es-module-lexer": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", @@ -1012,9 +1031,9 @@ "license": "MIT" }, "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1022,32 +1041,35 @@ "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" } }, "node_modules/estree-walker": { @@ -1070,6 +1092,24 @@ "node": ">=12.0.0" } }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -1085,13 +1125,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/loupe": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", - "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", - "dev": true, - "license": "MIT" - }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -1102,13 +1135,6 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -1128,22 +1154,23 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/pathe": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", - "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], "license": "MIT" }, - "node_modules/pathval": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", - "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.16" - } + "license": "MIT" }, "node_modules/picocolors": { "version": "1.1.1", @@ -1152,6 +1179,19 @@ "dev": true, "license": "ISC" }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -1265,36 +1305,36 @@ "license": "MIT" }, "node_modules/tinyexec": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", - "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinypool": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", - "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", "dev": true, "license": "MIT", "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": ">=18" } }, - "node_modules/tinyrainbow": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", - "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "dev": true, "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, "engines": { - "node": ">=14.0.0" + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tinyspy": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", - "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "node_modules/tinyrainbow": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", + "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", "dev": true, "license": "MIT", "engines": { @@ -1323,21 +1363,24 @@ "license": "MIT" }, "node_modules/vite": { - "version": "5.4.21", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", - "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -1346,19 +1389,25 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, + "jiti": { + "optional": true + }, "less": { "optional": true }, @@ -1379,74 +1428,60 @@ }, "terser": { "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true } } }, - "node_modules/vite-node": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.9.tgz", - "integrity": "sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==", - "dev": true, - "license": "MIT", - "dependencies": { - "cac": "^6.7.14", - "debug": "^4.3.7", - "es-module-lexer": "^1.5.4", - "pathe": "^1.1.2", - "vite": "^5.0.0" - }, - "bin": { - "vite-node": "vite-node.mjs" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, "node_modules/vitest": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.9.tgz", - "integrity": "sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==", + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", + "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "2.1.9", - "@vitest/mocker": "2.1.9", - "@vitest/pretty-format": "^2.1.9", - "@vitest/runner": "2.1.9", - "@vitest/snapshot": "2.1.9", - "@vitest/spy": "2.1.9", - "@vitest/utils": "2.1.9", - "chai": "^5.1.2", - "debug": "^4.3.7", - "expect-type": "^1.1.0", - "magic-string": "^0.30.12", - "pathe": "^1.1.2", - "std-env": "^3.8.0", + "@vitest/expect": "4.0.18", + "@vitest/mocker": "4.0.18", + "@vitest/pretty-format": "4.0.18", + "@vitest/runner": "4.0.18", + "@vitest/snapshot": "4.0.18", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "es-module-lexer": "^1.7.0", + "expect-type": "^1.2.2", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^3.10.0", "tinybench": "^2.9.0", - "tinyexec": "^0.3.1", - "tinypool": "^1.0.1", - "tinyrainbow": "^1.2.0", - "vite": "^5.0.0", - "vite-node": "2.1.9", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3", + "vite": "^6.0.0 || ^7.0.0", "why-is-node-running": "^2.3.0" }, "bin": { "vitest": "vitest.mjs" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { "@edge-runtime/vm": "*", - "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "2.1.9", - "@vitest/ui": "2.1.9", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.0.18", + "@vitest/browser-preview": "4.0.18", + "@vitest/browser-webdriverio": "4.0.18", + "@vitest/ui": "4.0.18", "happy-dom": "*", "jsdom": "*" }, @@ -1454,10 +1489,19 @@ "@edge-runtime/vm": { "optional": true }, + "@opentelemetry/api": { + "optional": true + }, "@types/node": { "optional": true }, - "@vitest/browser": { + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { "optional": true }, "@vitest/ui": { diff --git a/code_to_optimize/js/code_to_optimize_vitest/package.json b/code_to_optimize/js/code_to_optimize_vitest/package.json index 6327b5792..7cc8ae347 100644 --- a/code_to_optimize/js/code_to_optimize_vitest/package.json +++ b/code_to_optimize/js/code_to_optimize_vitest/package.json @@ -18,6 +18,6 @@ "@types/node": "^20.0.0", "codeflash": "file:../../../packages/codeflash", "typescript": "^5.0.0", - "vitest": "^2.0.0" + "vitest": "^4.0.18" } } diff --git a/pyproject.toml b/pyproject.toml index 56736fc6c..bb3b83f09 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,7 +45,8 @@ dependencies = [ "platformdirs>=4.3.7", "pygls>=2.0.0,<3.0.0", "codeflash-benchmark", - "filelock", + "filelock>=3.20.3; python_version >= '3.10'", + "filelock<3.20.3; python_version < '3.10'", "pytest-asyncio>=0.18.0", ] @@ -94,7 +95,7 @@ tests = [ "xarray>=2024.7.0", "eval_type_backport", "numba>=0.60.0", - "tensorflow>=2.20.0", + "tensorflow>=2.20.0; python_version >= '3.10'", ] [tool.hatch.build.targets.sdist] diff --git a/uv.lock b/uv.lock index 21221c10b..ef5f11206 100644 --- a/uv.lock +++ b/uv.lock @@ -25,38 +25,10 @@ members = [ "codeflash-benchmark", ] -[[package]] -name = "absl-py" -version = "2.3.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.9.2' and python_full_version < '3.10'", - "python_full_version < '3.9.2'", -] -sdist = { url = "https://files.pythonhosted.org/packages/10/2a/c93173ffa1b39c1d0395b7e842bbdc62e556ca9d8d3b5572926f3e4ca752/absl_py-2.3.1.tar.gz", hash = "sha256:a97820526f7fbfd2ec1bce83f3f25e3a14840dac0d8e02a0b71cd75db3f77fc9", size = 116588, upload-time = "2025-07-03T09:31:44.05Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/aa/ba0014cc4659328dc818a28827be78e6d97312ab0cb98105a770924dc11e/absl_py-2.3.1-py3-none-any.whl", hash = "sha256:eeecf07f0c2a93ace0772c92e596ace6d3d3996c042b2128459aaae2a76de11d", size = 135811, upload-time = "2025-07-03T09:31:42.253Z" }, -] - [[package]] name = "absl-py" version = "2.4.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.10.*'", -] sdist = { url = "https://files.pythonhosted.org/packages/64/c7/8de93764ad66968d19329a7e0c147a2bb3c7054c554d4a119111b8f9440f/absl_py-2.4.0.tar.gz", hash = "sha256:8c6af82722b35cf71e0f4d1d47dcaebfff286e27110a99fc359349b247dfb5d4", size = 116543, upload-time = "2026-01-28T10:17:05.322Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/18/a6/907a406bb7d359e6a63f99c313846d9eec4f7e6f7437809e03aa00fa3074/absl_py-2.4.0-py3-none-any.whl", hash = "sha256:88476fd881ca8aab94ffa78b7b6c632a782ab3ba1cd19c9bd423abc4fb4cd28d", size = 135750, upload-time = "2026-01-28T10:17:04.19Z" }, @@ -94,8 +66,8 @@ name = "astunparse" version = "1.6.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "six" }, - { name = "wheel" }, + { name = "six", marker = "python_full_version >= '3.10'" }, + { name = "wheel", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f3/af/4182184d3c338792894f34a62672919db7ca008c89abee9b564dd34d8029/astunparse-1.6.3.tar.gz", hash = "sha256:5ad93a8456f0d084c3456d059fd9a92cce667963232cbf763eac3bc5b7940872", size = 18290, upload-time = "2019-12-22T18:12:13.129Z" } wheels = [ @@ -548,7 +520,7 @@ tests = [ { name = "scipy", version = "1.13.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, { name = "scipy", version = "1.17.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, - { name = "tensorflow" }, + { name = "tensorflow", marker = "python_full_version >= '3.10'" }, { name = "torch", version = "2.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "torch", version = "2.10.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "xarray", version = "2024.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, @@ -563,7 +535,8 @@ requires-dist = [ { name = "coverage", specifier = ">=7.6.4" }, { name = "crosshair-tool", marker = "python_full_version < '3.15'", specifier = ">=0.0.78" }, { name = "dill", specifier = ">=0.3.8" }, - { name = "filelock" }, + { name = "filelock", marker = "python_full_version < '3.10'", specifier = "<3.20.3" }, + { name = "filelock", marker = "python_full_version >= '3.10'", specifier = ">=3.20.3" }, { name = "gitpython", specifier = ">=3.1.31" }, { name = "humanize", specifier = ">=4.0.0" }, { name = "inquirer", specifier = ">=3.0.0" }, @@ -625,7 +598,7 @@ tests = [ { name = "pyarrow", specifier = ">=15.0.0" }, { name = "pyrsistent", specifier = ">=0.20.0" }, { name = "scipy", specifier = ">=1.13.1" }, - { name = "tensorflow", specifier = ">=2.20.0" }, + { name = "tensorflow", marker = "python_full_version >= '3.10'", specifier = ">=2.20.0" }, { name = "torch", specifier = ">=2.8.0" }, { name = "xarray", specifier = ">=2024.7.0" }, ] @@ -1065,7 +1038,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -1202,7 +1175,7 @@ name = "google-pasta" version = "0.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "six" }, + { name = "six", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/35/4a/0bd53b36ff0323d10d5f24ebd67af2de10a1117f5cf4d7add90df92756f1/google-pasta-0.2.0.tar.gz", hash = "sha256:c9f2c8dfc8f96d0d5808299920721be30c9eec37f2389f28904f454565c8a16e", size = 40430, upload-time = "2020-03-13T18:57:50.34Z" } wheels = [ @@ -1214,7 +1187,7 @@ name = "grpcio" version = "1.78.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/06/8a/3d098f35c143a89520e568e6539cc098fcd294495910e359889ce8741c84/grpcio-1.78.0.tar.gz", hash = "sha256:7382b95189546f375c174f53a5fa873cef91c4b8005faa05cc5b3beea9c4f1c5", size = 12852416, upload-time = "2026-02-06T09:57:18.093Z" } wheels = [ @@ -1280,65 +1253,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/aa/aa/694b2f505345cfdd234cffb2525aa379a81695e6c02fd40d7e9193e871c6/grpcio-1.78.0-cp39-cp39-win_amd64.whl", hash = "sha256:5361a0630a7fdb58a6a97638ab70e1dae2893c4d08d7aba64ded28bb9e7a29df", size = 4799428, upload-time = "2026-02-06T09:57:14.493Z" }, ] -[[package]] -name = "h5py" -version = "3.14.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.9.2' and python_full_version < '3.10'", - "python_full_version < '3.9.2'", -] -dependencies = [ - { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5d/57/dfb3c5c3f1bf5f5ef2e59a22dec4ff1f3d7408b55bfcefcfb0ea69ef21c6/h5py-3.14.0.tar.gz", hash = "sha256:2372116b2e0d5d3e5e705b7f663f7c8d96fa79a4052d250484ef91d24d6a08f4", size = 424323, upload-time = "2025-06-06T14:06:15.01Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/52/89/06cbb421e01dea2e338b3154326523c05d9698f89a01f9d9b65e1ec3fb18/h5py-3.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:24df6b2622f426857bda88683b16630014588a0e4155cba44e872eb011c4eaed", size = 3332522, upload-time = "2025-06-06T14:04:13.775Z" }, - { url = "https://files.pythonhosted.org/packages/c3/e7/6c860b002329e408348735bfd0459e7b12f712c83d357abeef3ef404eaa9/h5py-3.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ff2389961ee5872de697054dd5a033b04284afc3fb52dc51d94561ece2c10c6", size = 2831051, upload-time = "2025-06-06T14:04:18.206Z" }, - { url = "https://files.pythonhosted.org/packages/fa/cd/3dd38cdb7cc9266dc4d85f27f0261680cb62f553f1523167ad7454e32b11/h5py-3.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:016e89d3be4c44f8d5e115fab60548e518ecd9efe9fa5c5324505a90773e6f03", size = 4324677, upload-time = "2025-06-06T14:04:23.438Z" }, - { url = "https://files.pythonhosted.org/packages/b1/45/e1a754dc7cd465ba35e438e28557119221ac89b20aaebef48282654e3dc7/h5py-3.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1223b902ef0b5d90bcc8a4778218d6d6cd0f5561861611eda59fa6c52b922f4d", size = 4557272, upload-time = "2025-06-06T14:04:28.863Z" }, - { url = "https://files.pythonhosted.org/packages/5c/06/f9506c1531645829d302c420851b78bb717af808dde11212c113585fae42/h5py-3.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:852b81f71df4bb9e27d407b43071d1da330d6a7094a588efa50ef02553fa7ce4", size = 2866734, upload-time = "2025-06-06T14:04:33.5Z" }, - { url = "https://files.pythonhosted.org/packages/61/1b/ad24a8ce846cf0519695c10491e99969d9d203b9632c4fcd5004b1641c2e/h5py-3.14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f30dbc58f2a0efeec6c8836c97f6c94afd769023f44e2bb0ed7b17a16ec46088", size = 3352382, upload-time = "2025-06-06T14:04:37.95Z" }, - { url = "https://files.pythonhosted.org/packages/36/5b/a066e459ca48b47cc73a5c668e9924d9619da9e3c500d9fb9c29c03858ec/h5py-3.14.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:543877d7f3d8f8a9828ed5df6a0b78ca3d8846244b9702e99ed0d53610b583a8", size = 2852492, upload-time = "2025-06-06T14:04:42.092Z" }, - { url = "https://files.pythonhosted.org/packages/08/0c/5e6aaf221557314bc15ba0e0da92e40b24af97ab162076c8ae009320a42b/h5py-3.14.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c497600c0496548810047257e36360ff551df8b59156d3a4181072eed47d8ad", size = 4298002, upload-time = "2025-06-06T14:04:47.106Z" }, - { url = "https://files.pythonhosted.org/packages/21/d4/d461649cafd5137088fb7f8e78fdc6621bb0c4ff2c090a389f68e8edc136/h5py-3.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:723a40ee6505bd354bfd26385f2dae7bbfa87655f4e61bab175a49d72ebfc06b", size = 4516618, upload-time = "2025-06-06T14:04:52.467Z" }, - { url = "https://files.pythonhosted.org/packages/db/0c/6c3f879a0f8e891625817637fad902da6e764e36919ed091dc77529004ac/h5py-3.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:d2744b520440a996f2dae97f901caa8a953afc055db4673a993f2d87d7f38713", size = 2874888, upload-time = "2025-06-06T14:04:56.95Z" }, - { url = "https://files.pythonhosted.org/packages/3e/77/8f651053c1843391e38a189ccf50df7e261ef8cd8bfd8baba0cbe694f7c3/h5py-3.14.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e0045115d83272090b0717c555a31398c2c089b87d212ceba800d3dc5d952e23", size = 3312740, upload-time = "2025-06-06T14:05:01.193Z" }, - { url = "https://files.pythonhosted.org/packages/ff/10/20436a6cf419b31124e59fefc78d74cb061ccb22213226a583928a65d715/h5py-3.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6da62509b7e1d71a7d110478aa25d245dd32c8d9a1daee9d2a42dba8717b047a", size = 2829207, upload-time = "2025-06-06T14:05:05.061Z" }, - { url = "https://files.pythonhosted.org/packages/3f/19/c8bfe8543bfdd7ccfafd46d8cfd96fce53d6c33e9c7921f375530ee1d39a/h5py-3.14.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:554ef0ced3571366d4d383427c00c966c360e178b5fb5ee5bb31a435c424db0c", size = 4708455, upload-time = "2025-06-06T14:05:11.528Z" }, - { url = "https://files.pythonhosted.org/packages/86/f9/f00de11c82c88bfc1ef22633557bfba9e271e0cb3189ad704183fc4a2644/h5py-3.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0cbd41f4e3761f150aa5b662df991868ca533872c95467216f2bec5fcad84882", size = 4929422, upload-time = "2025-06-06T14:05:18.399Z" }, - { url = "https://files.pythonhosted.org/packages/7a/6d/6426d5d456f593c94b96fa942a9b3988ce4d65ebaf57d7273e452a7222e8/h5py-3.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:bf4897d67e613ecf5bdfbdab39a1158a64df105827da70ea1d90243d796d367f", size = 2862845, upload-time = "2025-06-06T14:05:23.699Z" }, - { url = "https://files.pythonhosted.org/packages/6c/c2/7efe82d09ca10afd77cd7c286e42342d520c049a8c43650194928bcc635c/h5py-3.14.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:aa4b7bbce683379b7bf80aaba68e17e23396100336a8d500206520052be2f812", size = 3289245, upload-time = "2025-06-06T14:05:28.24Z" }, - { url = "https://files.pythonhosted.org/packages/4f/31/f570fab1239b0d9441024b92b6ad03bb414ffa69101a985e4c83d37608bd/h5py-3.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9603a501a04fcd0ba28dd8f0995303d26a77a980a1f9474b3417543d4c6174", size = 2807335, upload-time = "2025-06-06T14:05:31.997Z" }, - { url = "https://files.pythonhosted.org/packages/0d/ce/3a21d87896bc7e3e9255e0ad5583ae31ae9e6b4b00e0bcb2a67e2b6acdbc/h5py-3.14.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8cbaf6910fa3983c46172666b0b8da7b7bd90d764399ca983236f2400436eeb", size = 4700675, upload-time = "2025-06-06T14:05:37.38Z" }, - { url = "https://files.pythonhosted.org/packages/e7/ec/86f59025306dcc6deee5fda54d980d077075b8d9889aac80f158bd585f1b/h5py-3.14.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d90e6445ab7c146d7f7981b11895d70bc1dd91278a4f9f9028bc0c95e4a53f13", size = 4921632, upload-time = "2025-06-06T14:05:43.464Z" }, - { url = "https://files.pythonhosted.org/packages/3f/6d/0084ed0b78d4fd3e7530c32491f2884140d9b06365dac8a08de726421d4a/h5py-3.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:ae18e3de237a7a830adb76aaa68ad438d85fe6e19e0d99944a3ce46b772c69b3", size = 2852929, upload-time = "2025-06-06T14:05:47.659Z" }, - { url = "https://files.pythonhosted.org/packages/ec/ac/9ea82488c8790ee5b6ad1a807cd7dc3b9dadfece1cd0e0e369f68a7a8937/h5py-3.14.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5cc1601e78027cedfec6dd50efb4802f018551754191aeb58d948bd3ec3bd7a", size = 3345097, upload-time = "2025-06-06T14:05:51.984Z" }, - { url = "https://files.pythonhosted.org/packages/6c/bc/a172ecaaf287e3af2f837f23b470b0a2229c79555a0da9ac8b5cc5bed078/h5py-3.14.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e59d2136a8b302afd25acdf7a89b634e0eb7c66b1a211ef2d0457853768a2ef", size = 2843320, upload-time = "2025-06-06T14:05:55.754Z" }, - { url = "https://files.pythonhosted.org/packages/66/40/b423b57696514e05aa7bb06150ef96667d0e0006cc6de7ab52c71734ab51/h5py-3.14.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:573c33ad056ac7c1ab6d567b6db9df3ffc401045e3f605736218f96c1e0490c6", size = 4326368, upload-time = "2025-06-06T14:06:00.782Z" }, - { url = "https://files.pythonhosted.org/packages/f7/07/e088f89f04fdbe57ddf9de377f857158d3daa38cf5d0fb20ef9bd489e313/h5py-3.14.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ccbe17dc187c0c64178f1a10aa274ed3a57d055117588942b8a08793cc448216", size = 4559686, upload-time = "2025-06-06T14:06:07.416Z" }, - { url = "https://files.pythonhosted.org/packages/b4/e4/fb8032d0e5480b1db9b419b5b50737b61bb3c7187c49d809975d62129fb0/h5py-3.14.0-cp39-cp39-win_amd64.whl", hash = "sha256:4f025cf30ae738c4c4e38c7439a761a71ccfcce04c2b87b2a2ac64e8c5171d43", size = 2877166, upload-time = "2025-06-06T14:06:13.05Z" }, -] - [[package]] name = "h5py" version = "3.15.1" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.10.*'", -] dependencies = [ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, { name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, @@ -1912,29 +1830,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/44/87/b444f934f62ee2a1be45bb52563cf17a66b0d790eba43af4df9929e7107f/junitparser-4.0.2-py3-none-any.whl", hash = "sha256:94c3570e41fcaedc64cc3c634ca99457fe41a84dd1aa8ff74e9e12e66223a155", size = 14592, upload-time = "2025-06-24T04:37:31.322Z" }, ] -[[package]] -name = "keras" -version = "3.10.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.9.2' and python_full_version < '3.10'", - "python_full_version < '3.9.2'", -] -dependencies = [ - { name = "absl-py", version = "2.3.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "h5py", version = "3.14.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "ml-dtypes", marker = "python_full_version < '3.10'" }, - { name = "namex", marker = "python_full_version < '3.10'" }, - { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "optree", marker = "python_full_version < '3.10'" }, - { name = "packaging", marker = "python_full_version < '3.10'" }, - { name = "rich", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f3/fe/2946daf8477ae38a4b480c8889c72ede4f36eb28f9e1a27fc355cd633c3d/keras-3.10.0.tar.gz", hash = "sha256:6e9100bf66eaf6de4b7f288d34ef9bb8b5dcdd62f42c64cfd910226bb34ad2d2", size = 1040781, upload-time = "2025-05-19T22:58:30.833Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/e6/4179c461a5fc43e3736880f64dbdc9b1a5349649f0ae32ded927c0e3a227/keras-3.10.0-py3-none-any.whl", hash = "sha256:c095a6bf90cd50defadf73d4859ff794fad76b775357ef7bd1dbf96388dae7d3", size = 1380082, upload-time = "2025-05-19T22:58:28.938Z" }, -] - [[package]] name = "keras" version = "3.12.1" @@ -1943,8 +1838,8 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "absl-py", version = "2.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, - { name = "h5py", version = "3.15.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, + { name = "absl-py", marker = "python_full_version == '3.10.*'" }, + { name = "h5py", marker = "python_full_version == '3.10.*'" }, { name = "ml-dtypes", marker = "python_full_version == '3.10.*'" }, { name = "namex", marker = "python_full_version == '3.10.*'" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, @@ -1976,8 +1871,8 @@ resolution-markers = [ "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] dependencies = [ - { name = "absl-py", version = "2.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, - { name = "h5py", version = "3.15.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "absl-py", marker = "python_full_version >= '3.11'" }, + { name = "h5py", marker = "python_full_version >= '3.11'" }, { name = "ml-dtypes", marker = "python_full_version >= '3.11'" }, { name = "namex", marker = "python_full_version >= '3.11'" }, { name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, @@ -2470,41 +2365,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1f/c9/e0f8e4e6e8a69e5959b06499582dca6349db6769cc7fdfb8a02a7c75a9ae/lxml_stubs-0.5.1-py3-none-any.whl", hash = "sha256:1f689e5dbc4b9247cb09ae820c7d34daeb1fdbd1db06123814b856dae7787272", size = 13584, upload-time = "2024-01-10T09:37:44.931Z" }, ] -[[package]] -name = "markdown" -version = "3.9" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.9.2' and python_full_version < '3.10'", - "python_full_version < '3.9.2'", -] -dependencies = [ - { name = "importlib-metadata", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8d/37/02347f6d6d8279247a5837082ebc26fc0d5aaeaf75aa013fcbb433c777ab/markdown-3.9.tar.gz", hash = "sha256:d2900fe1782bd33bdbbd56859defef70c2e78fc46668f8eb9df3128138f2cb6a", size = 364585, upload-time = "2025-09-04T20:25:22.885Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/70/ae/44c4a6a4cbb496d93c6257954260fe3a6e91b7bed2240e5dad2a717f5111/markdown-3.9-py3-none-any.whl", hash = "sha256:9f4d91ed810864ea88a6f32c07ba8bee1346c0cc1f6b1f9f6c822f2a9667d280", size = 107441, upload-time = "2025-09-04T20:25:21.784Z" }, -] - [[package]] name = "markdown" version = "3.10.2" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.10.*'", -] sdist = { url = "https://files.pythonhosted.org/packages/2b/f4/69fa6ed85ae003c2378ffa8f6d2e3234662abd02c10d216c0ba96081a238/markdown-3.10.2.tar.gz", hash = "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950", size = 368805, upload-time = "2026-02-09T14:57:26.942Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36", size = 108180, upload-time = "2026-02-09T14:57:25.787Z" }, @@ -3313,7 +3177,7 @@ name = "optree" version = "0.18.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/83/8e/09d899ad531d50b79aa24e7558f604980fe4048350172e643bb1b9983aec/optree-0.18.0.tar.gz", hash = "sha256:3804fb6ddc923855db2dc4805b4524c66e00f1ef30b166be4aadd52822b13e06", size = 165178, upload-time = "2025-11-14T08:58:31.234Z" } wheels = [ @@ -3653,149 +3517,17 @@ name = "pexpect" version = "4.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "ptyprocess" }, + { name = "ptyprocess", marker = "(python_full_version < '3.11' and sys_platform == 'emscripten') or (python_full_version < '3.11' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, ] -[[package]] -name = "pillow" -version = "11.3.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.9.2' and python_full_version < '3.10'", - "python_full_version < '3.9.2'", -] -sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/d0d6dea55cd152ce3d6767bb38a8fc10e33796ba4ba210cbab9354b6d238/pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523", size = 47113069, upload-time = "2025-07-01T09:16:30.666Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4c/5d/45a3553a253ac8763f3561371432a90bdbe6000fbdcf1397ffe502aa206c/pillow-11.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860", size = 5316554, upload-time = "2025-07-01T09:13:39.342Z" }, - { url = "https://files.pythonhosted.org/packages/7c/c8/67c12ab069ef586a25a4a79ced553586748fad100c77c0ce59bb4983ac98/pillow-11.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad", size = 4686548, upload-time = "2025-07-01T09:13:41.835Z" }, - { url = "https://files.pythonhosted.org/packages/2f/bd/6741ebd56263390b382ae4c5de02979af7f8bd9807346d068700dd6d5cf9/pillow-11.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7107195ddc914f656c7fc8e4a5e1c25f32e9236ea3ea860f257b0436011fddd0", size = 5859742, upload-time = "2025-07-03T13:09:47.439Z" }, - { url = "https://files.pythonhosted.org/packages/ca/0b/c412a9e27e1e6a829e6ab6c2dca52dd563efbedf4c9c6aa453d9a9b77359/pillow-11.3.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc3e831b563b3114baac7ec2ee86819eb03caa1a2cef0b481a5675b59c4fe23b", size = 7633087, upload-time = "2025-07-03T13:09:51.796Z" }, - { url = "https://files.pythonhosted.org/packages/59/9d/9b7076aaf30f5dd17e5e5589b2d2f5a5d7e30ff67a171eb686e4eecc2adf/pillow-11.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f1f182ebd2303acf8c380a54f615ec883322593320a9b00438eb842c1f37ae50", size = 5963350, upload-time = "2025-07-01T09:13:43.865Z" }, - { url = "https://files.pythonhosted.org/packages/f0/16/1a6bf01fb622fb9cf5c91683823f073f053005c849b1f52ed613afcf8dae/pillow-11.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4445fa62e15936a028672fd48c4c11a66d641d2c05726c7ec1f8ba6a572036ae", size = 6631840, upload-time = "2025-07-01T09:13:46.161Z" }, - { url = "https://files.pythonhosted.org/packages/7b/e6/6ff7077077eb47fde78739e7d570bdcd7c10495666b6afcd23ab56b19a43/pillow-11.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:71f511f6b3b91dd543282477be45a033e4845a40278fa8dcdbfdb07109bf18f9", size = 6074005, upload-time = "2025-07-01T09:13:47.829Z" }, - { url = "https://files.pythonhosted.org/packages/c3/3a/b13f36832ea6d279a697231658199e0a03cd87ef12048016bdcc84131601/pillow-11.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040a5b691b0713e1f6cbe222e0f4f74cd233421e105850ae3b3c0ceda520f42e", size = 6708372, upload-time = "2025-07-01T09:13:52.145Z" }, - { url = "https://files.pythonhosted.org/packages/6c/e4/61b2e1a7528740efbc70b3d581f33937e38e98ef3d50b05007267a55bcb2/pillow-11.3.0-cp310-cp310-win32.whl", hash = "sha256:89bd777bc6624fe4115e9fac3352c79ed60f3bb18651420635f26e643e3dd1f6", size = 6277090, upload-time = "2025-07-01T09:13:53.915Z" }, - { url = "https://files.pythonhosted.org/packages/a9/d3/60c781c83a785d6afbd6a326ed4d759d141de43aa7365725cbcd65ce5e54/pillow-11.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:19d2ff547c75b8e3ff46f4d9ef969a06c30ab2d4263a9e287733aa8b2429ce8f", size = 6985988, upload-time = "2025-07-01T09:13:55.699Z" }, - { url = "https://files.pythonhosted.org/packages/9f/28/4f4a0203165eefb3763939c6789ba31013a2e90adffb456610f30f613850/pillow-11.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:819931d25e57b513242859ce1876c58c59dc31587847bf74cfe06b2e0cb22d2f", size = 2422899, upload-time = "2025-07-01T09:13:57.497Z" }, - { url = "https://files.pythonhosted.org/packages/db/26/77f8ed17ca4ffd60e1dcd220a6ec6d71210ba398cfa33a13a1cd614c5613/pillow-11.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1cd110edf822773368b396281a2293aeb91c90a2db00d78ea43e7e861631b722", size = 5316531, upload-time = "2025-07-01T09:13:59.203Z" }, - { url = "https://files.pythonhosted.org/packages/cb/39/ee475903197ce709322a17a866892efb560f57900d9af2e55f86db51b0a5/pillow-11.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c412fddd1b77a75aa904615ebaa6001f169b26fd467b4be93aded278266b288", size = 4686560, upload-time = "2025-07-01T09:14:01.101Z" }, - { url = "https://files.pythonhosted.org/packages/d5/90/442068a160fd179938ba55ec8c97050a612426fae5ec0a764e345839f76d/pillow-11.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1aa4de119a0ecac0a34a9c8bde33f34022e2e8f99104e47a3ca392fd60e37d", size = 5870978, upload-time = "2025-07-03T13:09:55.638Z" }, - { url = "https://files.pythonhosted.org/packages/13/92/dcdd147ab02daf405387f0218dcf792dc6dd5b14d2573d40b4caeef01059/pillow-11.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:91da1d88226663594e3f6b4b8c3c8d85bd504117d043740a8e0ec449087cc494", size = 7641168, upload-time = "2025-07-03T13:10:00.37Z" }, - { url = "https://files.pythonhosted.org/packages/6e/db/839d6ba7fd38b51af641aa904e2960e7a5644d60ec754c046b7d2aee00e5/pillow-11.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:643f189248837533073c405ec2f0bb250ba54598cf80e8c1e043381a60632f58", size = 5973053, upload-time = "2025-07-01T09:14:04.491Z" }, - { url = "https://files.pythonhosted.org/packages/f2/2f/d7675ecae6c43e9f12aa8d58b6012683b20b6edfbdac7abcb4e6af7a3784/pillow-11.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:106064daa23a745510dabce1d84f29137a37224831d88eb4ce94bb187b1d7e5f", size = 6640273, upload-time = "2025-07-01T09:14:06.235Z" }, - { url = "https://files.pythonhosted.org/packages/45/ad/931694675ede172e15b2ff03c8144a0ddaea1d87adb72bb07655eaffb654/pillow-11.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd8ff254faf15591e724dc7c4ddb6bf4793efcbe13802a4ae3e863cd300b493e", size = 6082043, upload-time = "2025-07-01T09:14:07.978Z" }, - { url = "https://files.pythonhosted.org/packages/3a/04/ba8f2b11fc80d2dd462d7abec16351b45ec99cbbaea4387648a44190351a/pillow-11.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:932c754c2d51ad2b2271fd01c3d121daaa35e27efae2a616f77bf164bc0b3e94", size = 6715516, upload-time = "2025-07-01T09:14:10.233Z" }, - { url = "https://files.pythonhosted.org/packages/48/59/8cd06d7f3944cc7d892e8533c56b0acb68399f640786313275faec1e3b6f/pillow-11.3.0-cp311-cp311-win32.whl", hash = "sha256:b4b8f3efc8d530a1544e5962bd6b403d5f7fe8b9e08227c6b255f98ad82b4ba0", size = 6274768, upload-time = "2025-07-01T09:14:11.921Z" }, - { url = "https://files.pythonhosted.org/packages/f1/cc/29c0f5d64ab8eae20f3232da8f8571660aa0ab4b8f1331da5c2f5f9a938e/pillow-11.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:1a992e86b0dd7aeb1f053cd506508c0999d710a8f07b4c791c63843fc6a807ac", size = 6986055, upload-time = "2025-07-01T09:14:13.623Z" }, - { url = "https://files.pythonhosted.org/packages/c6/df/90bd886fabd544c25addd63e5ca6932c86f2b701d5da6c7839387a076b4a/pillow-11.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:30807c931ff7c095620fe04448e2c2fc673fcbb1ffe2a7da3fb39613489b1ddd", size = 2423079, upload-time = "2025-07-01T09:14:15.268Z" }, - { url = "https://files.pythonhosted.org/packages/40/fe/1bc9b3ee13f68487a99ac9529968035cca2f0a51ec36892060edcc51d06a/pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4", size = 5278800, upload-time = "2025-07-01T09:14:17.648Z" }, - { url = "https://files.pythonhosted.org/packages/2c/32/7e2ac19b5713657384cec55f89065fb306b06af008cfd87e572035b27119/pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69", size = 4686296, upload-time = "2025-07-01T09:14:19.828Z" }, - { url = "https://files.pythonhosted.org/packages/8e/1e/b9e12bbe6e4c2220effebc09ea0923a07a6da1e1f1bfbc8d7d29a01ce32b/pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d", size = 5871726, upload-time = "2025-07-03T13:10:04.448Z" }, - { url = "https://files.pythonhosted.org/packages/8d/33/e9200d2bd7ba00dc3ddb78df1198a6e80d7669cce6c2bdbeb2530a74ec58/pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6", size = 7644652, upload-time = "2025-07-03T13:10:10.391Z" }, - { url = "https://files.pythonhosted.org/packages/41/f1/6f2427a26fc683e00d985bc391bdd76d8dd4e92fac33d841127eb8fb2313/pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7", size = 5977787, upload-time = "2025-07-01T09:14:21.63Z" }, - { url = "https://files.pythonhosted.org/packages/e4/c9/06dd4a38974e24f932ff5f98ea3c546ce3f8c995d3f0985f8e5ba48bba19/pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024", size = 6645236, upload-time = "2025-07-01T09:14:23.321Z" }, - { url = "https://files.pythonhosted.org/packages/40/e7/848f69fb79843b3d91241bad658e9c14f39a32f71a301bcd1d139416d1be/pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809", size = 6086950, upload-time = "2025-07-01T09:14:25.237Z" }, - { url = "https://files.pythonhosted.org/packages/0b/1a/7cff92e695a2a29ac1958c2a0fe4c0b2393b60aac13b04a4fe2735cad52d/pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d", size = 6723358, upload-time = "2025-07-01T09:14:27.053Z" }, - { url = "https://files.pythonhosted.org/packages/26/7d/73699ad77895f69edff76b0f332acc3d497f22f5d75e5360f78cbcaff248/pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149", size = 6275079, upload-time = "2025-07-01T09:14:30.104Z" }, - { url = "https://files.pythonhosted.org/packages/8c/ce/e7dfc873bdd9828f3b6e5c2bbb74e47a98ec23cc5c74fc4e54462f0d9204/pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d", size = 6986324, upload-time = "2025-07-01T09:14:31.899Z" }, - { url = "https://files.pythonhosted.org/packages/16/8f/b13447d1bf0b1f7467ce7d86f6e6edf66c0ad7cf44cf5c87a37f9bed9936/pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542", size = 2423067, upload-time = "2025-07-01T09:14:33.709Z" }, - { url = "https://files.pythonhosted.org/packages/1e/93/0952f2ed8db3a5a4c7a11f91965d6184ebc8cd7cbb7941a260d5f018cd2d/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd", size = 2128328, upload-time = "2025-07-01T09:14:35.276Z" }, - { url = "https://files.pythonhosted.org/packages/4b/e8/100c3d114b1a0bf4042f27e0f87d2f25e857e838034e98ca98fe7b8c0a9c/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8", size = 2170652, upload-time = "2025-07-01T09:14:37.203Z" }, - { url = "https://files.pythonhosted.org/packages/aa/86/3f758a28a6e381758545f7cdb4942e1cb79abd271bea932998fc0db93cb6/pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f", size = 2227443, upload-time = "2025-07-01T09:14:39.344Z" }, - { url = "https://files.pythonhosted.org/packages/01/f4/91d5b3ffa718df2f53b0dc109877993e511f4fd055d7e9508682e8aba092/pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c", size = 5278474, upload-time = "2025-07-01T09:14:41.843Z" }, - { url = "https://files.pythonhosted.org/packages/f9/0e/37d7d3eca6c879fbd9dba21268427dffda1ab00d4eb05b32923d4fbe3b12/pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd", size = 4686038, upload-time = "2025-07-01T09:14:44.008Z" }, - { url = "https://files.pythonhosted.org/packages/ff/b0/3426e5c7f6565e752d81221af9d3676fdbb4f352317ceafd42899aaf5d8a/pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e", size = 5864407, upload-time = "2025-07-03T13:10:15.628Z" }, - { url = "https://files.pythonhosted.org/packages/fc/c1/c6c423134229f2a221ee53f838d4be9d82bab86f7e2f8e75e47b6bf6cd77/pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1", size = 7639094, upload-time = "2025-07-03T13:10:21.857Z" }, - { url = "https://files.pythonhosted.org/packages/ba/c9/09e6746630fe6372c67c648ff9deae52a2bc20897d51fa293571977ceb5d/pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805", size = 5973503, upload-time = "2025-07-01T09:14:45.698Z" }, - { url = "https://files.pythonhosted.org/packages/d5/1c/a2a29649c0b1983d3ef57ee87a66487fdeb45132df66ab30dd37f7dbe162/pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8", size = 6642574, upload-time = "2025-07-01T09:14:47.415Z" }, - { url = "https://files.pythonhosted.org/packages/36/de/d5cc31cc4b055b6c6fd990e3e7f0f8aaf36229a2698501bcb0cdf67c7146/pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2", size = 6084060, upload-time = "2025-07-01T09:14:49.636Z" }, - { url = "https://files.pythonhosted.org/packages/d5/ea/502d938cbaeec836ac28a9b730193716f0114c41325db428e6b280513f09/pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b", size = 6721407, upload-time = "2025-07-01T09:14:51.962Z" }, - { url = "https://files.pythonhosted.org/packages/45/9c/9c5e2a73f125f6cbc59cc7087c8f2d649a7ae453f83bd0362ff7c9e2aee2/pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3", size = 6273841, upload-time = "2025-07-01T09:14:54.142Z" }, - { url = "https://files.pythonhosted.org/packages/23/85/397c73524e0cd212067e0c969aa245b01d50183439550d24d9f55781b776/pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51", size = 6978450, upload-time = "2025-07-01T09:14:56.436Z" }, - { url = "https://files.pythonhosted.org/packages/17/d2/622f4547f69cd173955194b78e4d19ca4935a1b0f03a302d655c9f6aae65/pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580", size = 2423055, upload-time = "2025-07-01T09:14:58.072Z" }, - { url = "https://files.pythonhosted.org/packages/dd/80/a8a2ac21dda2e82480852978416cfacd439a4b490a501a288ecf4fe2532d/pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e", size = 5281110, upload-time = "2025-07-01T09:14:59.79Z" }, - { url = "https://files.pythonhosted.org/packages/44/d6/b79754ca790f315918732e18f82a8146d33bcd7f4494380457ea89eb883d/pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d", size = 4689547, upload-time = "2025-07-01T09:15:01.648Z" }, - { url = "https://files.pythonhosted.org/packages/49/20/716b8717d331150cb00f7fdd78169c01e8e0c219732a78b0e59b6bdb2fd6/pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced", size = 5901554, upload-time = "2025-07-03T13:10:27.018Z" }, - { url = "https://files.pythonhosted.org/packages/74/cf/a9f3a2514a65bb071075063a96f0a5cf949c2f2fce683c15ccc83b1c1cab/pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c", size = 7669132, upload-time = "2025-07-03T13:10:33.01Z" }, - { url = "https://files.pythonhosted.org/packages/98/3c/da78805cbdbee9cb43efe8261dd7cc0b4b93f2ac79b676c03159e9db2187/pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8", size = 6005001, upload-time = "2025-07-01T09:15:03.365Z" }, - { url = "https://files.pythonhosted.org/packages/6c/fa/ce044b91faecf30e635321351bba32bab5a7e034c60187fe9698191aef4f/pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59", size = 6668814, upload-time = "2025-07-01T09:15:05.655Z" }, - { url = "https://files.pythonhosted.org/packages/7b/51/90f9291406d09bf93686434f9183aba27b831c10c87746ff49f127ee80cb/pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe", size = 6113124, upload-time = "2025-07-01T09:15:07.358Z" }, - { url = "https://files.pythonhosted.org/packages/cd/5a/6fec59b1dfb619234f7636d4157d11fb4e196caeee220232a8d2ec48488d/pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c", size = 6747186, upload-time = "2025-07-01T09:15:09.317Z" }, - { url = "https://files.pythonhosted.org/packages/49/6b/00187a044f98255225f172de653941e61da37104a9ea60e4f6887717e2b5/pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788", size = 6277546, upload-time = "2025-07-01T09:15:11.311Z" }, - { url = "https://files.pythonhosted.org/packages/e8/5c/6caaba7e261c0d75bab23be79f1d06b5ad2a2ae49f028ccec801b0e853d6/pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31", size = 6985102, upload-time = "2025-07-01T09:15:13.164Z" }, - { url = "https://files.pythonhosted.org/packages/f3/7e/b623008460c09a0cb38263c93b828c666493caee2eb34ff67f778b87e58c/pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e", size = 2424803, upload-time = "2025-07-01T09:15:15.695Z" }, - { url = "https://files.pythonhosted.org/packages/73/f4/04905af42837292ed86cb1b1dabe03dce1edc008ef14c473c5c7e1443c5d/pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12", size = 5278520, upload-time = "2025-07-01T09:15:17.429Z" }, - { url = "https://files.pythonhosted.org/packages/41/b0/33d79e377a336247df6348a54e6d2a2b85d644ca202555e3faa0cf811ecc/pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a", size = 4686116, upload-time = "2025-07-01T09:15:19.423Z" }, - { url = "https://files.pythonhosted.org/packages/49/2d/ed8bc0ab219ae8768f529597d9509d184fe8a6c4741a6864fea334d25f3f/pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632", size = 5864597, upload-time = "2025-07-03T13:10:38.404Z" }, - { url = "https://files.pythonhosted.org/packages/b5/3d/b932bb4225c80b58dfadaca9d42d08d0b7064d2d1791b6a237f87f661834/pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673", size = 7638246, upload-time = "2025-07-03T13:10:44.987Z" }, - { url = "https://files.pythonhosted.org/packages/09/b5/0487044b7c096f1b48f0d7ad416472c02e0e4bf6919541b111efd3cae690/pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027", size = 5973336, upload-time = "2025-07-01T09:15:21.237Z" }, - { url = "https://files.pythonhosted.org/packages/a8/2d/524f9318f6cbfcc79fbc004801ea6b607ec3f843977652fdee4857a7568b/pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77", size = 6642699, upload-time = "2025-07-01T09:15:23.186Z" }, - { url = "https://files.pythonhosted.org/packages/6f/d2/a9a4f280c6aefedce1e8f615baaa5474e0701d86dd6f1dede66726462bbd/pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874", size = 6083789, upload-time = "2025-07-01T09:15:25.1Z" }, - { url = "https://files.pythonhosted.org/packages/fe/54/86b0cd9dbb683a9d5e960b66c7379e821a19be4ac5810e2e5a715c09a0c0/pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a", size = 6720386, upload-time = "2025-07-01T09:15:27.378Z" }, - { url = "https://files.pythonhosted.org/packages/e7/95/88efcaf384c3588e24259c4203b909cbe3e3c2d887af9e938c2022c9dd48/pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214", size = 6370911, upload-time = "2025-07-01T09:15:29.294Z" }, - { url = "https://files.pythonhosted.org/packages/2e/cc/934e5820850ec5eb107e7b1a72dd278140731c669f396110ebc326f2a503/pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635", size = 7117383, upload-time = "2025-07-01T09:15:31.128Z" }, - { url = "https://files.pythonhosted.org/packages/d6/e9/9c0a616a71da2a5d163aa37405e8aced9a906d574b4a214bede134e731bc/pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6", size = 2511385, upload-time = "2025-07-01T09:15:33.328Z" }, - { url = "https://files.pythonhosted.org/packages/1a/33/c88376898aff369658b225262cd4f2659b13e8178e7534df9e6e1fa289f6/pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae", size = 5281129, upload-time = "2025-07-01T09:15:35.194Z" }, - { url = "https://files.pythonhosted.org/packages/1f/70/d376247fb36f1844b42910911c83a02d5544ebd2a8bad9efcc0f707ea774/pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653", size = 4689580, upload-time = "2025-07-01T09:15:37.114Z" }, - { url = "https://files.pythonhosted.org/packages/eb/1c/537e930496149fbac69efd2fc4329035bbe2e5475b4165439e3be9cb183b/pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6", size = 5902860, upload-time = "2025-07-03T13:10:50.248Z" }, - { url = "https://files.pythonhosted.org/packages/bd/57/80f53264954dcefeebcf9dae6e3eb1daea1b488f0be8b8fef12f79a3eb10/pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36", size = 7670694, upload-time = "2025-07-03T13:10:56.432Z" }, - { url = "https://files.pythonhosted.org/packages/70/ff/4727d3b71a8578b4587d9c276e90efad2d6fe0335fd76742a6da08132e8c/pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b", size = 6005888, upload-time = "2025-07-01T09:15:39.436Z" }, - { url = "https://files.pythonhosted.org/packages/05/ae/716592277934f85d3be51d7256f3636672d7b1abfafdc42cf3f8cbd4b4c8/pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477", size = 6670330, upload-time = "2025-07-01T09:15:41.269Z" }, - { url = "https://files.pythonhosted.org/packages/e7/bb/7fe6cddcc8827b01b1a9766f5fdeb7418680744f9082035bdbabecf1d57f/pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50", size = 6114089, upload-time = "2025-07-01T09:15:43.13Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f5/06bfaa444c8e80f1a8e4bff98da9c83b37b5be3b1deaa43d27a0db37ef84/pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b", size = 6748206, upload-time = "2025-07-01T09:15:44.937Z" }, - { url = "https://files.pythonhosted.org/packages/f0/77/bc6f92a3e8e6e46c0ca78abfffec0037845800ea38c73483760362804c41/pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12", size = 6377370, upload-time = "2025-07-01T09:15:46.673Z" }, - { url = "https://files.pythonhosted.org/packages/4a/82/3a721f7d69dca802befb8af08b7c79ebcab461007ce1c18bd91a5d5896f9/pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db", size = 7121500, upload-time = "2025-07-01T09:15:48.512Z" }, - { url = "https://files.pythonhosted.org/packages/89/c7/5572fa4a3f45740eaab6ae86fcdf7195b55beac1371ac8c619d880cfe948/pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa", size = 2512835, upload-time = "2025-07-01T09:15:50.399Z" }, - { url = "https://files.pythonhosted.org/packages/9e/8e/9c089f01677d1264ab8648352dcb7773f37da6ad002542760c80107da816/pillow-11.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:48d254f8a4c776de343051023eb61ffe818299eeac478da55227d96e241de53f", size = 5316478, upload-time = "2025-07-01T09:15:52.209Z" }, - { url = "https://files.pythonhosted.org/packages/b5/a9/5749930caf674695867eb56a581e78eb5f524b7583ff10b01b6e5048acb3/pillow-11.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7aee118e30a4cf54fdd873bd3a29de51e29105ab11f9aad8c32123f58c8f8081", size = 4686522, upload-time = "2025-07-01T09:15:54.162Z" }, - { url = "https://files.pythonhosted.org/packages/43/46/0b85b763eb292b691030795f9f6bb6fcaf8948c39413c81696a01c3577f7/pillow-11.3.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:23cff760a9049c502721bdb743a7cb3e03365fafcdfc2ef9784610714166e5a4", size = 5853376, upload-time = "2025-07-03T13:11:01.066Z" }, - { url = "https://files.pythonhosted.org/packages/5e/c6/1a230ec0067243cbd60bc2dad5dc3ab46a8a41e21c15f5c9b52b26873069/pillow-11.3.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6359a3bc43f57d5b375d1ad54a0074318a0844d11b76abccf478c37c986d3cfc", size = 7626020, upload-time = "2025-07-03T13:11:06.479Z" }, - { url = "https://files.pythonhosted.org/packages/63/dd/f296c27ffba447bfad76c6a0c44c1ea97a90cb9472b9304c94a732e8dbfb/pillow-11.3.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:092c80c76635f5ecb10f3f83d76716165c96f5229addbd1ec2bdbbda7d496e06", size = 5956732, upload-time = "2025-07-01T09:15:56.111Z" }, - { url = "https://files.pythonhosted.org/packages/a5/a0/98a3630f0b57f77bae67716562513d3032ae70414fcaf02750279c389a9e/pillow-11.3.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cadc9e0ea0a2431124cde7e1697106471fc4c1da01530e679b2391c37d3fbb3a", size = 6624404, upload-time = "2025-07-01T09:15:58.245Z" }, - { url = "https://files.pythonhosted.org/packages/de/e6/83dfba5646a290edd9a21964da07674409e410579c341fc5b8f7abd81620/pillow-11.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6a418691000f2a418c9135a7cf0d797c1bb7d9a485e61fe8e7722845b95ef978", size = 6067760, upload-time = "2025-07-01T09:16:00.003Z" }, - { url = "https://files.pythonhosted.org/packages/bc/41/15ab268fe6ee9a2bc7391e2bbb20a98d3974304ab1a406a992dcb297a370/pillow-11.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:97afb3a00b65cc0804d1c7abddbf090a81eaac02768af58cbdcaaa0a931e0b6d", size = 6700534, upload-time = "2025-07-01T09:16:02.29Z" }, - { url = "https://files.pythonhosted.org/packages/64/79/6d4f638b288300bed727ff29f2a3cb63db054b33518a95f27724915e3fbc/pillow-11.3.0-cp39-cp39-win32.whl", hash = "sha256:ea944117a7974ae78059fcc1800e5d3295172bb97035c0c1d9345fca1419da71", size = 6277091, upload-time = "2025-07-01T09:16:04.4Z" }, - { url = "https://files.pythonhosted.org/packages/46/05/4106422f45a05716fd34ed21763f8ec182e8ea00af6e9cb05b93a247361a/pillow-11.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:e5c5858ad8ec655450a7c7df532e9842cf8df7cc349df7225c60d5d348c8aada", size = 6986091, upload-time = "2025-07-01T09:16:06.342Z" }, - { url = "https://files.pythonhosted.org/packages/63/c6/287fd55c2c12761d0591549d48885187579b7c257bef0c6660755b0b59ae/pillow-11.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:6abdbfd3aea42be05702a8dd98832329c167ee84400a1d1f61ab11437f1717eb", size = 2422632, upload-time = "2025-07-01T09:16:08.142Z" }, - { url = "https://files.pythonhosted.org/packages/6f/8b/209bd6b62ce8367f47e68a218bffac88888fdf2c9fcf1ecadc6c3ec1ebc7/pillow-11.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3cee80663f29e3843b68199b9d6f4f54bd1d4a6b59bdd91bceefc51238bcb967", size = 5270556, upload-time = "2025-07-01T09:16:09.961Z" }, - { url = "https://files.pythonhosted.org/packages/2e/e6/231a0b76070c2cfd9e260a7a5b504fb72da0a95279410fa7afd99d9751d6/pillow-11.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b5f56c3f344f2ccaf0dd875d3e180f631dc60a51b314295a3e681fe8cf851fbe", size = 4654625, upload-time = "2025-07-01T09:16:11.913Z" }, - { url = "https://files.pythonhosted.org/packages/13/f4/10cf94fda33cb12765f2397fc285fa6d8eb9c29de7f3185165b702fc7386/pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e67d793d180c9df62f1f40aee3accca4829d3794c95098887edc18af4b8b780c", size = 4874207, upload-time = "2025-07-03T13:11:10.201Z" }, - { url = "https://files.pythonhosted.org/packages/72/c9/583821097dc691880c92892e8e2d41fe0a5a3d6021f4963371d2f6d57250/pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d000f46e2917c705e9fb93a3606ee4a819d1e3aa7a9b442f6444f07e77cf5e25", size = 6583939, upload-time = "2025-07-03T13:11:15.68Z" }, - { url = "https://files.pythonhosted.org/packages/3b/8e/5c9d410f9217b12320efc7c413e72693f48468979a013ad17fd690397b9a/pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:527b37216b6ac3a12d7838dc3bd75208ec57c1c6d11ef01902266a5a0c14fc27", size = 4957166, upload-time = "2025-07-01T09:16:13.74Z" }, - { url = "https://files.pythonhosted.org/packages/62/bb/78347dbe13219991877ffb3a91bf09da8317fbfcd4b5f9140aeae020ad71/pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be5463ac478b623b9dd3937afd7fb7ab3d79dd290a28e2b6df292dc75063eb8a", size = 5581482, upload-time = "2025-07-01T09:16:16.107Z" }, - { url = "https://files.pythonhosted.org/packages/d9/28/1000353d5e61498aaeaaf7f1e4b49ddb05f2c6575f9d4f9f914a3538b6e1/pillow-11.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8dc70ca24c110503e16918a658b869019126ecfe03109b754c402daff12b3d9f", size = 6984596, upload-time = "2025-07-01T09:16:18.07Z" }, - { url = "https://files.pythonhosted.org/packages/9e/e3/6fa84033758276fb31da12e5fb66ad747ae83b93c67af17f8c6ff4cc8f34/pillow-11.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c8ec7a017ad1bd562f93dbd8505763e688d388cde6e4a010ae1486916e713e6", size = 5270566, upload-time = "2025-07-01T09:16:19.801Z" }, - { url = "https://files.pythonhosted.org/packages/5b/ee/e8d2e1ab4892970b561e1ba96cbd59c0d28cf66737fc44abb2aec3795a4e/pillow-11.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9ab6ae226de48019caa8074894544af5b53a117ccb9d3b3dcb2871464c829438", size = 4654618, upload-time = "2025-07-01T09:16:21.818Z" }, - { url = "https://files.pythonhosted.org/packages/f2/6d/17f80f4e1f0761f02160fc433abd4109fa1548dcfdca46cfdadaf9efa565/pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fe27fb049cdcca11f11a7bfda64043c37b30e6b91f10cb5bab275806c32f6ab3", size = 4874248, upload-time = "2025-07-03T13:11:20.738Z" }, - { url = "https://files.pythonhosted.org/packages/de/5f/c22340acd61cef960130585bbe2120e2fd8434c214802f07e8c03596b17e/pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:465b9e8844e3c3519a983d58b80be3f668e2a7a5db97f2784e7079fbc9f9822c", size = 6583963, upload-time = "2025-07-03T13:11:26.283Z" }, - { url = "https://files.pythonhosted.org/packages/31/5e/03966aedfbfcbb4d5f8aa042452d3361f325b963ebbadddac05b122e47dd/pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5418b53c0d59b3824d05e029669efa023bbef0f3e92e75ec8428f3799487f361", size = 4957170, upload-time = "2025-07-01T09:16:23.762Z" }, - { url = "https://files.pythonhosted.org/packages/cc/2d/e082982aacc927fc2cab48e1e731bdb1643a1406acace8bed0900a61464e/pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:504b6f59505f08ae014f724b6207ff6222662aab5cc9542577fb084ed0676ac7", size = 5581505, upload-time = "2025-07-01T09:16:25.593Z" }, - { url = "https://files.pythonhosted.org/packages/34/e7/ae39f538fd6844e982063c3a5e4598b8ced43b9633baa3a85ef33af8c05c/pillow-11.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8", size = 6984598, upload-time = "2025-07-01T09:16:27.732Z" }, -] - [[package]] name = "pillow" version = "12.1.1" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.10.*'", -] sdist = { url = "https://files.pythonhosted.org/packages/1f/42/5c74462b4fd957fcd7b13b04fb3205ff8349236ea74c7c375766d6c82288/pillow-12.1.1.tar.gz", hash = "sha256:9ad8fa5937ab05218e2b6a4cff30295ad35afd2f83ac592e68c0d871bb0fdbc4", size = 46980264, upload-time = "2026-02-11T04:23:07.146Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/1d/30/5bd3d794762481f8c8ae9c80e7b76ecea73b916959eb587521358ef0b2f9/pillow-12.1.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1f1625b72740fdda5d77b4def688eb8fd6490975d06b909fd19f13f391e077e0", size = 5304099, upload-time = "2026-02-11T04:20:06.13Z" }, @@ -5376,21 +5108,17 @@ name = "tensorboard" version = "2.20.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "absl-py", version = "2.3.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "absl-py", version = "2.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "grpcio" }, - { name = "markdown", version = "3.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "markdown", version = "3.10.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "absl-py", marker = "python_full_version >= '3.10'" }, + { name = "grpcio", marker = "python_full_version >= '3.10'" }, + { name = "markdown", marker = "python_full_version >= '3.10'" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, { name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, - { name = "packaging" }, - { name = "pillow", version = "11.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "pillow", version = "12.1.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "protobuf" }, - { name = "setuptools" }, - { name = "tensorboard-data-server" }, - { name = "werkzeug" }, + { name = "packaging", marker = "python_full_version >= '3.10'" }, + { name = "pillow", marker = "python_full_version >= '3.10'" }, + { name = "protobuf", marker = "python_full_version >= '3.10'" }, + { name = "setuptools", marker = "python_full_version >= '3.10'" }, + { name = "tensorboard-data-server", marker = "python_full_version >= '3.10'" }, + { name = "werkzeug", marker = "python_full_version >= '3.10'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/9c/d9/a5db55f88f258ac669a92858b70a714bbbd5acd993820b41ec4a96a4d77f/tensorboard-2.20.0-py3-none-any.whl", hash = "sha256:9dc9f978cb84c0723acf9a345d96c184f0293d18f166bb8d59ee098e6cfaaba6", size = 5525680, upload-time = "2025-07-17T19:20:49.638Z" }, @@ -5411,34 +5139,29 @@ name = "tensorflow" version = "2.20.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "absl-py", version = "2.3.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "absl-py", version = "2.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "astunparse" }, - { name = "flatbuffers" }, - { name = "gast" }, - { name = "google-pasta" }, - { name = "grpcio" }, - { name = "h5py", version = "3.14.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "h5py", version = "3.15.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "keras", version = "3.10.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "absl-py", marker = "python_full_version >= '3.10'" }, + { name = "astunparse", marker = "python_full_version >= '3.10'" }, + { name = "flatbuffers", marker = "python_full_version >= '3.10'" }, + { name = "gast", marker = "python_full_version >= '3.10'" }, + { name = "google-pasta", marker = "python_full_version >= '3.10'" }, + { name = "grpcio", marker = "python_full_version >= '3.10'" }, + { name = "h5py", marker = "python_full_version >= '3.10'" }, { name = "keras", version = "3.12.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, { name = "keras", version = "3.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, - { name = "libclang" }, - { name = "ml-dtypes" }, - { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "libclang", marker = "python_full_version >= '3.10'" }, + { name = "ml-dtypes", marker = "python_full_version >= '3.10'" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, { name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, - { name = "opt-einsum" }, - { name = "packaging" }, - { name = "protobuf" }, - { name = "requests" }, - { name = "setuptools" }, - { name = "six" }, - { name = "tensorboard" }, - { name = "termcolor", version = "3.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "termcolor", version = "3.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "typing-extensions" }, - { name = "wrapt" }, + { name = "opt-einsum", marker = "python_full_version >= '3.10'" }, + { name = "packaging", marker = "python_full_version >= '3.10'" }, + { name = "protobuf", marker = "python_full_version >= '3.10'" }, + { name = "requests", marker = "python_full_version >= '3.10'" }, + { name = "setuptools", marker = "python_full_version >= '3.10'" }, + { name = "six", marker = "python_full_version >= '3.10'" }, + { name = "tensorboard", marker = "python_full_version >= '3.10'" }, + { name = "termcolor", marker = "python_full_version >= '3.10'" }, + { name = "typing-extensions", marker = "python_full_version >= '3.10'" }, + { name = "wrapt", marker = "python_full_version >= '3.10'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/16/0e/9408083cb80d85024829eb78aa0aa799ca9f030a348acac35631b5191d4b/tensorflow-2.20.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:e5f169f8f5130ab255bbe854c5f0ae152e93d3d1ac44f42cb1866003b81a5357", size = 200387116, upload-time = "2025-08-13T16:50:38.945Z" }, @@ -5463,38 +5186,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/16/25/b2d7ef3b6570d2827d06066cdfdbc719367c5fe4bce7910901951e5652eb/tensorflow-2.20.0-cp39-cp39-win_amd64.whl", hash = "sha256:dd71a7e7c3270239f4185915e8f2c5d39608c5e18973d6e1d101b153993841eb", size = 331661805, upload-time = "2025-08-13T16:54:50.512Z" }, ] -[[package]] -name = "termcolor" -version = "3.1.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.9.2' and python_full_version < '3.10'", - "python_full_version < '3.9.2'", -] -sdist = { url = "https://files.pythonhosted.org/packages/ca/6c/3d75c196ac07ac8749600b60b03f4f6094d54e132c4d94ebac6ee0e0add0/termcolor-3.1.0.tar.gz", hash = "sha256:6a6dd7fbee581909eeec6a756cff1d7f7c376063b14e4a298dc4980309e55970", size = 14324, upload-time = "2025-04-30T11:37:53.791Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4f/bd/de8d508070629b6d84a30d01d57e4a65c69aa7f5abe7560b8fad3b50ea59/termcolor-3.1.0-py3-none-any.whl", hash = "sha256:591dd26b5c2ce03b9e43f391264626557873ce1d379019786f99b0c2bee140aa", size = 7684, upload-time = "2025-04-30T11:37:52.382Z" }, -] - [[package]] name = "termcolor" version = "3.3.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.10.*'", -] sdist = { url = "https://files.pythonhosted.org/packages/46/79/cf31d7a93a8fdc6aa0fbb665be84426a8c5a557d9240b6239e9e11e35fc5/termcolor-3.3.0.tar.gz", hash = "sha256:348871ca648ec6a9a983a13ab626c0acce02f515b9e1983332b17af7979521c5", size = 14434, upload-time = "2025-12-29T12:55:21.882Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/33/d1/8bb87d21e9aeb323cc03034f5eaf2c8f69841e40e4853c2627edf8111ed3/termcolor-3.3.0-py3-none-any.whl", hash = "sha256:cf642efadaf0a8ebbbf4bc7a31cec2f9b5f21a9f726f4ccbb08192c9c26f43a5", size = 7734, upload-time = "2025-12-29T12:55:20.718Z" }, @@ -6273,7 +5968,7 @@ name = "werkzeug" version = "3.1.5" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "markupsafe" }, + { name = "markupsafe", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5a/70/1469ef1d3542ae7c2c7b72bd5e3a4e6ee69d7978fa8a3af05a38eca5becf/werkzeug-3.1.5.tar.gz", hash = "sha256:6a548b0e88955dd07ccb25539d7d0cc97417ee9e179677d22c7041c8f078ce67", size = 864754, upload-time = "2026-01-08T17:49:23.247Z" } wheels = [ @@ -6285,7 +5980,7 @@ name = "wheel" version = "0.46.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "packaging" }, + { name = "packaging", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/89/24/a2eb353a6edac9a0303977c4cb048134959dd2a51b48a269dfc9dde00c8a/wheel-0.46.3.tar.gz", hash = "sha256:e3e79874b07d776c40bd6033f8ddf76a7dad46a7b8aa1b2787a83083519a1803", size = 60605, upload-time = "2026-01-22T12:39:49.136Z" } wheels = [ From d09fa5ceaa732496357c61a898e52375bd5c4d14 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 01:32:55 -0500 Subject: [PATCH 069/100] ci: add Windows to unit tests matrix Run unit tests on Windows with Python 3.13 in addition to all Python versions (3.9-3.14) on Ubuntu. This ensures cross-platform compatibility is tested while keeping Windows test duration reasonable. --- .github/workflows/unit-tests.yaml | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/.github/workflows/unit-tests.yaml b/.github/workflows/unit-tests.yaml index 88130cd03..48f40f6ae 100644 --- a/.github/workflows/unit-tests.yaml +++ b/.github/workflows/unit-tests.yaml @@ -15,9 +15,23 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] + include: + - os: ubuntu-latest + python-version: "3.9" + - os: ubuntu-latest + python-version: "3.10" + - os: ubuntu-latest + python-version: "3.11" + - os: ubuntu-latest + python-version: "3.12" + - os: ubuntu-latest + python-version: "3.13" + - os: ubuntu-latest + python-version: "3.14" + - os: windows-latest + python-version: "3.13" continue-on-error: true - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 with: From 81997282d2474f8d40c2f204b4c465ca254efefd Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 01:36:11 -0500 Subject: [PATCH 070/100] ci: consolidate Windows tests into main unit-tests workflow Remove redundant windows-unit-tests.yml and add Windows Python 3.13 job to the main unit-tests.yaml workflow. Add PYTHONIOENCODING env var for Windows compatibility. --- .github/workflows/unit-tests.yaml | 2 ++ .github/workflows/windows-unit-tests.yml | 34 ------------------------ 2 files changed, 2 insertions(+), 34 deletions(-) delete mode 100644 .github/workflows/windows-unit-tests.yml diff --git a/.github/workflows/unit-tests.yaml b/.github/workflows/unit-tests.yaml index 48f40f6ae..05ca30752 100644 --- a/.github/workflows/unit-tests.yaml +++ b/.github/workflows/unit-tests.yaml @@ -32,6 +32,8 @@ jobs: python-version: "3.13" continue-on-error: true runs-on: ${{ matrix.os }} + env: + PYTHONIOENCODING: utf-8 steps: - uses: actions/checkout@v4 with: diff --git a/.github/workflows/windows-unit-tests.yml b/.github/workflows/windows-unit-tests.yml deleted file mode 100644 index 20b2da52e..000000000 --- a/.github/workflows/windows-unit-tests.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: windows-unit-tests - -on: - push: - branches: [main] - pull_request: - workflow_dispatch: - -concurrency: - group: ${{ github.workflow }}-${{ github.ref_name }} - cancel-in-progress: true - -jobs: - windows-unit-tests: - continue-on-error: true - runs-on: windows-latest - env: - PYTHONIOENCODING: utf-8 - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Install uv - uses: astral-sh/setup-uv@v6 - with: - python-version: "3.13" - - - name: install dependencies - run: uv sync - - - name: Unit tests - run: uv run pytest tests/ From 09613b62697419c322dbf9c9663b34b1e03716a1 Mon Sep 17 00:00:00 2001 From: misrasaurabh1 Date: Wed, 18 Feb 2026 22:38:40 -0800 Subject: [PATCH 071/100] version bump --- codeflash-benchmark/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codeflash-benchmark/pyproject.toml b/codeflash-benchmark/pyproject.toml index bc5e9040d..e0ea5cf70 100644 --- a/codeflash-benchmark/pyproject.toml +++ b/codeflash-benchmark/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "codeflash-benchmark" -version = "0.2.0" +version = "0.3.0" description = "Pytest benchmarking plugin for codeflash.ai - automatic code performance optimization" authors = [{ name = "CodeFlash Inc.", email = "contact@codeflash.ai" }] requires-python = ">=3.9" From f1c707a7c4ea82f8e6f1e854e8a986e54bfc5717 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 01:51:49 -0500 Subject: [PATCH 072/100] Simplify dependency summary output --- codeflash/cli_cmds/console.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/codeflash/cli_cmds/console.py b/codeflash/cli_cmds/console.py index 305ad458b..f44aff44e 100644 --- a/codeflash/cli_cmds/console.py +++ b/codeflash/cli_cmds/console.py @@ -336,11 +336,12 @@ def call_graph_summary(call_graph: DependencyResolver, file_to_funcs: dict[Path, leaf_functions = total_functions - with_context avg_callees = total_callees / total_functions + function_label = "function" if total_functions == 1 else "functions" + summary = ( - f"{total_functions} functions ready for optimization · " - f"avg {avg_callees:.1f} dependencies/function\n" - f"{with_context} call other functions · " - f"{leaf_functions} are self-contained" + f"{total_functions} {function_label} ready for optimization\n" + f"Uses other functions: {with_context} · " + f"Standalone: {leaf_functions}" ) if is_LSP_enabled(): From 12f36fb064b6015181079aeed571f70991e78bfa Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 01:57:41 -0500 Subject: [PATCH 073/100] Clarify call graph UI text --- codeflash/cli_cmds/console.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/codeflash/cli_cmds/console.py b/codeflash/cli_cmds/console.py index f44aff44e..fdc5a420a 100644 --- a/codeflash/cli_cmds/console.py +++ b/codeflash/cli_cmds/console.py @@ -235,8 +235,8 @@ def call_graph_live_display( results: deque[IndexResult] = deque(maxlen=MAX_TREE_ENTRIES) stats = {"indexed": 0, "cached": 0, "edges": 0, "external": 0, "errors": 0} - tree = Tree("[bold]Dependencies[/bold]") - stats_text = Text("0 dependencies found", style="dim") + tree = Tree("[bold]Recent Files[/bold]") + stats_text = Text("0 calls found", style="dim") panel = Panel( Group(progress, Text(""), tree, Text(""), stats_text), title="Building Call Graph", border_style="cyan" ) @@ -260,11 +260,11 @@ def create_tree_node(result: IndexResult) -> Tree: edge_info = [] if local_edges: - edge_info.append(f"{local_edges} in same file") + edge_info.append(f"{local_edges} calls in same file") if result.cross_file_edges: - edge_info.append(f"{result.cross_file_edges} from other modules") + edge_info.append(f"{result.cross_file_edges} calls from other modules") - label = ", ".join(edge_info) if edge_info else "no dependencies" + label = ", ".join(edge_info) if edge_info else "no calls" return Tree(f"[cyan]{name}[/cyan] [dim]{label}[/dim]") def refresh_display() -> None: @@ -279,9 +279,9 @@ def refresh_display() -> None: stat_parts.append(f"{stats['cached']} cached") if stats["errors"]: stat_parts.append(f"{stats['errors']} errors") - stat_parts.append(f"{stats['edges']} dependencies found") + stat_parts.append(f"{stats['edges']} calls found") if stats["external"]: - stat_parts.append(f"{stats['external']} from other modules") + stat_parts.append(f"{stats['external']} cross-file calls") stats_text.truncate(0) stats_text.append(" · ".join(stat_parts), style="dim") @@ -312,7 +312,7 @@ def update(result: IndexResult) -> None: if len(batch) >= 8: process_batch() - with Live(panel, console=console, transient=True, auto_refresh=False) as live: + with Live(panel, console=console, transient=False, auto_refresh=False) as live: yield update if batch: process_batch() @@ -348,4 +348,4 @@ def call_graph_summary(call_graph: DependencyResolver, file_to_funcs: dict[Path, lsp_log(LspTextMessage(text=summary)) return - console.print(Panel(summary, title="Dependency Summary", border_style="cyan")) + console.print(Panel(summary, title="Call Graph Summary", border_style="cyan")) From 09ad2f59d1555e4383eefd7c00a30c12ce6a5326 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 02:26:20 -0500 Subject: [PATCH 074/100] Rename Python call graph to reference graph --- codeflash/languages/python/__init__.py | 4 ++-- .../python/{call_graph.py => reference_graph.py} | 13 +++++++------ codeflash/languages/python/support.py | 6 +++--- 3 files changed, 12 insertions(+), 11 deletions(-) rename codeflash/languages/python/{call_graph.py => reference_graph.py} (97%) diff --git a/codeflash/languages/python/__init__.py b/codeflash/languages/python/__init__.py index 50eb1a51e..939d5941f 100644 --- a/codeflash/languages/python/__init__.py +++ b/codeflash/languages/python/__init__.py @@ -5,7 +5,7 @@ to the LanguageSupport protocol. """ -from codeflash.languages.python.call_graph import CallGraph +from codeflash.languages.python.reference_graph import ReferenceGraph from codeflash.languages.python.support import PythonSupport -__all__ = ["CallGraph", "PythonSupport"] +__all__ = ["PythonSupport", "ReferenceGraph"] diff --git a/codeflash/languages/python/call_graph.py b/codeflash/languages/python/reference_graph.py similarity index 97% rename from codeflash/languages/python/call_graph.py rename to codeflash/languages/python/reference_graph.py index f9641d2e0..4f389fd66 100644 --- a/codeflash/languages/python/call_graph.py +++ b/codeflash/languages/python/reference_graph.py @@ -21,6 +21,7 @@ # --------------------------------------------------------------------------- # Module-level helpers (must be top-level for ProcessPoolExecutor pickling) # --------------------------------------------------------------------------- +# TODO: create call graph. _PARALLEL_THRESHOLD = 8 @@ -179,7 +180,7 @@ def _index_file_worker(args: tuple[str, str]) -> tuple[str, str, set[tuple[str, # --------------------------------------------------------------------------- -class CallGraph: +class ReferenceGraph: SCHEMA_VERSION = 2 def __init__(self, project_root: Path, language: str = "python", db_path: Path | None = None) -> None: @@ -365,7 +366,7 @@ def index_file(self, file_path: Path, file_hash: str, resolved: str | None = Non resolved = str(file_path.resolve()) edges, had_error = _analyze_file(file_path, self.jedi_project, self.project_root_str) if had_error: - logger.debug(f"CallGraph: failed to parse {file_path}") + logger.debug(f"ReferenceGraph: failed to parse {file_path}") return self._persist_edges(file_path, resolved, file_hash, edges, had_error) def _persist_edges( @@ -493,7 +494,7 @@ def _build_index_parallel( path_info: dict[str, tuple[Path, str]] = {resolved: (fp, fh) for fp, resolved, fh in to_index} worker_args = [(resolved, fh) for _fp, resolved, fh in to_index] - logger.debug(f"CallGraph: indexing {len(to_index)} files across {max_workers} workers") + logger.debug(f"ReferenceGraph: indexing {len(to_index)} files across {max_workers} workers") try: with ProcessPoolExecutor( @@ -508,7 +509,7 @@ def _build_index_parallel( try: _, _, edges, had_error = future.result() except Exception: - logger.debug(f"CallGraph: worker failed for {file_path}") + logger.debug(f"ReferenceGraph: worker failed for {file_path}") self._persist_edges(file_path, resolved, file_hash, set(), had_error=True) self._report_progress( on_progress, @@ -519,13 +520,13 @@ def _build_index_parallel( continue if had_error: - logger.debug(f"CallGraph: failed to parse {file_path}") + logger.debug(f"ReferenceGraph: failed to parse {file_path}") result = self._persist_edges(file_path, resolved, file_hash, edges, had_error) self._report_progress(on_progress, result) except Exception: - logger.debug("CallGraph: parallel indexing failed, falling back to sequential") + logger.debug("ReferenceGraph: parallel indexing failed, falling back to sequential") self._fallback_sequential_index(to_index, on_progress) def _fallback_sequential_index( diff --git a/codeflash/languages/python/support.py b/codeflash/languages/python/support.py index 1480e690c..b026e99e5 100644 --- a/codeflash/languages/python/support.py +++ b/codeflash/languages/python/support.py @@ -753,12 +753,12 @@ def ensure_runtime_environment(self, project_root: Path) -> bool: return True def create_dependency_resolver(self, project_root: Path) -> DependencyResolver | None: - from codeflash.languages.python.call_graph import CallGraph + from codeflash.languages.python.reference_graph import ReferenceGraph try: - return CallGraph(project_root, language=self.language.value) + return ReferenceGraph(project_root, language=self.language.value) except Exception: - logger.debug("Failed to initialize CallGraph, falling back to per-function Jedi analysis") + logger.debug("Failed to initialize ReferenceGraph, falling back to per-function Jedi analysis") return None def instrument_existing_test( From cb9115831251a83967233558276ea12a0c82afb4 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 02:30:27 -0500 Subject: [PATCH 075/100] refactor: rename test file and imports to match reference graph rename --- ..._call_graph.py => test_reference_graph.py} | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) rename tests/{test_call_graph.py => test_reference_graph.py} (92%) diff --git a/tests/test_call_graph.py b/tests/test_reference_graph.py similarity index 92% rename from tests/test_call_graph.py rename to tests/test_reference_graph.py index 9dda10e97..6e3ab0c65 100644 --- a/tests/test_call_graph.py +++ b/tests/test_reference_graph.py @@ -8,7 +8,7 @@ from pathlib import Path from codeflash.languages.base import IndexResult -from codeflash.languages.python.call_graph import CallGraph +from codeflash.languages.python.reference_graph import ReferenceGraph @pytest.fixture @@ -46,7 +46,7 @@ def caller(): return helper() """, ) - cg = CallGraph(project, db_path=db_path) + cg = ReferenceGraph(project, db_path=db_path) try: _, result_list = cg.get_callees({project / "mod.py": {"caller"}}) callee_qns = {fs.qualified_name for fs in result_list} @@ -74,7 +74,7 @@ def caller(): return utility() """, ) - cg = CallGraph(project, db_path=db_path) + cg = ReferenceGraph(project, db_path=db_path) try: _, result_list = cg.get_callees({project / "main.py": {"caller"}}) callee_qns = {fs.qualified_name for fs in result_list} @@ -100,7 +100,7 @@ def caller(): return obj """, ) - cg = CallGraph(project, db_path=db_path) + cg = ReferenceGraph(project, db_path=db_path) try: _, result_list = cg.get_callees({project / "mod.py": {"caller"}}) callee_types = {fs.definition_type for fs in result_list} @@ -120,7 +120,7 @@ def inner(): return inner() """, ) - cg = CallGraph(project, db_path=db_path) + cg = ReferenceGraph(project, db_path=db_path) try: _, result_list = cg.get_callees({project / "mod.py": {"caller"}}) assert len(result_list) == 0 @@ -139,7 +139,7 @@ def helper(): x = helper() """, ) - cg = CallGraph(project, db_path=db_path) + cg = ReferenceGraph(project, db_path=db_path) try: # Module level calls have no enclosing function, so no edges _, result_list = cg.get_callees({project / "mod.py": {"helper"}}) @@ -160,7 +160,7 @@ def caller(): return os.path.join("a", "b") """, ) - cg = CallGraph(project, db_path=db_path) + cg = ReferenceGraph(project, db_path=db_path) try: _, result_list = cg.get_callees({project / "mod.py": {"caller"}}) # os.path.join is stdlib, should not appear @@ -171,7 +171,7 @@ def caller(): def test_empty_file(project: Path, db_path: Path) -> None: write_file(project, "mod.py", "") - cg = CallGraph(project, db_path=db_path) + cg = ReferenceGraph(project, db_path=db_path) try: _, result_list = cg.get_callees({project / "mod.py": set()}) assert len(result_list) == 0 @@ -181,7 +181,7 @@ def test_empty_file(project: Path, db_path: Path) -> None: def test_syntax_error_file(project: Path, db_path: Path) -> None: write_file(project, "mod.py", "def broken(\n") - cg = CallGraph(project, db_path=db_path) + cg = ReferenceGraph(project, db_path=db_path) try: _, result_list = cg.get_callees({project / "mod.py": {"broken"}}) assert len(result_list) == 0 @@ -206,7 +206,7 @@ def caller(): return helper() """, ) - cg = CallGraph(project, db_path=db_path) + cg = ReferenceGraph(project, db_path=db_path) try: cg.get_callees({project / "mod.py": {"caller"}}) # Second call should use in-memory cache (hash unchanged) @@ -231,7 +231,7 @@ def caller(): return helper() """, ) - cg = CallGraph(project, db_path=db_path) + cg = ReferenceGraph(project, db_path=db_path) try: _, result_list = cg.get_callees({project / "mod.py": {"caller"}}) assert any(fs.qualified_name == "helper" for fs in result_list) @@ -270,7 +270,7 @@ def caller(): """, ) # First session: index the file - cg1 = CallGraph(project, db_path=db_path) + cg1 = ReferenceGraph(project, db_path=db_path) try: _, result_list = cg1.get_callees({project / "mod.py": {"caller"}}) assert any(fs.qualified_name == "helper" for fs in result_list) @@ -278,7 +278,7 @@ def caller(): cg1.close() # Second session: should read from DB without re-indexing - cg2 = CallGraph(project, db_path=db_path) + cg2 = ReferenceGraph(project, db_path=db_path) try: assert len(cg2.indexed_file_hashes) == 0 # in-memory cache is empty _, result_list = cg2.get_callees({project / "mod.py": {"caller"}}) @@ -310,7 +310,7 @@ def caller_b(): """, ) - cg = CallGraph(project, db_path=db_path) + cg = ReferenceGraph(project, db_path=db_path) try: progress_calls: list[IndexResult] = [] files = [project / "a.py", project / "b.py"] @@ -359,7 +359,7 @@ def caller_b(): """, ) - cg = CallGraph(project, db_path=db_path) + cg = ReferenceGraph(project, db_path=db_path) try: files = [project / "a.py", project / "b.py"] # First pass — fresh indexing @@ -400,7 +400,7 @@ def caller(): """, ) - cg = CallGraph(project, db_path=db_path) + cg = ReferenceGraph(project, db_path=db_path) try: progress_calls: list[IndexResult] = [] cg.build_index([project / "utils.py", project / "main.py"], on_progress=progress_calls.append) @@ -436,7 +436,7 @@ def leaf(): """, ) - cg = CallGraph(project, db_path=db_path) + cg = ReferenceGraph(project, db_path=db_path) try: cg.build_index([project / "mod.py"]) mod_path = project / "mod.py" @@ -461,7 +461,7 @@ def caller(): """, ) - cg = CallGraph(project, db_path=db_path) + cg = ReferenceGraph(project, db_path=db_path) try: progress_calls: list[IndexResult] = [] cg.build_index([project / "mod.py"], on_progress=progress_calls.append) From 82783f8c92a911dbe28787a2b801f263559ed974 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 02:40:03 -0500 Subject: [PATCH 076/100] disable it for now --- codeflash/optimization/optimizer.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/codeflash/optimization/optimizer.py b/codeflash/optimization/optimizer.py index 680efdf1e..941502a4d 100644 --- a/codeflash/optimization/optimizer.py +++ b/codeflash/optimization/optimizer.py @@ -572,16 +572,17 @@ def run(self) -> None: # Skip in CI — the cache DB doesn't persist between runs on ephemeral runners lang_support = current_language_support() resolver = None - if lang_support and not env_utils.is_ci(): - resolver = lang_support.create_dependency_resolver(self.args.project_root) - - if resolver is not None and lang_support is not None and file_to_funcs_to_optimize: - supported_exts = lang_support.file_extensions - source_files = [f for f in file_to_funcs_to_optimize if f.suffix in supported_exts] - with call_graph_live_display(len(source_files), project_root=self.args.project_root) as on_progress: - resolver.build_index(source_files, on_progress=on_progress) - console.rule() - call_graph_summary(resolver, file_to_funcs_to_optimize) + # CURRENTLY DISABLED: The resolver is currently not used for anything until i clean up the repo structure for python + # if lang_support and not env_utils.is_ci(): + # resolver = lang_support.create_dependency_resolver(self.args.project_root) + + # if resolver is not None and lang_support is not None and file_to_funcs_to_optimize: + # supported_exts = lang_support.file_extensions + # source_files = [f for f in file_to_funcs_to_optimize if f.suffix in supported_exts] + # with call_graph_live_display(len(source_files), project_root=self.args.project_root) as on_progress: + # resolver.build_index(source_files, on_progress=on_progress) + # console.rule() + # call_graph_summary(resolver, file_to_funcs_to_optimize) optimizations_found: int = 0 self.test_cfg.concolic_test_root_dir = Path( From d2dea5c1c13089333664daecced168b3b7970f6a Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 02:44:38 -0500 Subject: [PATCH 077/100] fix: remove stale jedi_definition argument from FunctionSource calls --- .../languages/python/context/code_context_extractor.py | 3 --- codeflash/optimization/optimizer.py | 8 +++++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/codeflash/languages/python/context/code_context_extractor.py b/codeflash/languages/python/context/code_context_extractor.py index 5ef02d788..0e42022f6 100644 --- a/codeflash/languages/python/context/code_context_extractor.py +++ b/codeflash/languages/python/context/code_context_extractor.py @@ -255,7 +255,6 @@ def get_code_optimization_context_for_language( fully_qualified_name=helper.qualified_name, only_function_name=helper.name, source_code=helper.source_code, - jedi_definition=None, ) ) @@ -477,7 +476,6 @@ def get_function_to_optimize_as_function_source( fully_qualified_name=name.full_name, only_function_name=name.name, source_code=name.get_line_code(), - jedi_definition=name, ) except Exception as e: logger.exception(f"Error while getting function source: {e}") @@ -545,7 +543,6 @@ def get_function_sources_from_jedi( fully_qualified_name=fqn, only_function_name=func_name, source_code=definition.get_line_code(), - jedi_definition=definition, ) file_path_to_function_source[definition_path].add(function_source) function_source_list.append(function_source) diff --git a/codeflash/optimization/optimizer.py b/codeflash/optimization/optimizer.py index 941502a4d..3211ab59b 100644 --- a/codeflash/optimization/optimizer.py +++ b/codeflash/optimization/optimizer.py @@ -11,7 +11,13 @@ from codeflash.api.aiservice import AiServiceClient, LocalAiServiceClient from codeflash.api.cfapi import send_completion_email -from codeflash.cli_cmds.console import call_graph_live_display, call_graph_summary, console, logger, progress_bar +from codeflash.cli_cmds.console import ( # noqa: F401 + call_graph_live_display, + call_graph_summary, + console, + logger, + progress_bar, +) from codeflash.code_utils import env_utils from codeflash.code_utils.code_utils import cleanup_paths, get_run_tmp_file from codeflash.code_utils.env_utils import get_pr_number, is_pr_draft From 84473944b9e6d7e07cedcefdef20a86040f8bbe7 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 02:53:40 -0500 Subject: [PATCH 078/100] docs: add PR review guidance for stale feedback --- CLAUDE.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 622351db4..c4628e91a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -28,6 +28,10 @@ Discovery → Ranking → Context Extraction → Test Gen + Optimization → Bas - **Tracer**: Profiling system that records function call trees and timings (`tracing/`, `tracer.py`) - **Worktree mode**: Git worktree-based parallel optimization (`--worktree` flag) +## PR Reviews + +- GitHub PR comments and review feedback can be stale — they may reference issues already fixed by a later commit. Before acting on review feedback, verify it still applies to the current code. If the issue no longer exists, resolve the conversation in the GitHub UI. + # Agent Rules From 51911cf851ba7de2e9b8bba2662060f3087d5702 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 03:12:03 -0500 Subject: [PATCH 079/100] Update uv.lock --- uv.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uv.lock b/uv.lock index ef5f11206..05b79c606 100644 --- a/uv.lock +++ b/uv.lock @@ -605,7 +605,7 @@ tests = [ [[package]] name = "codeflash-benchmark" -version = "0.2.0" +version = "0.3.0" source = { editable = "codeflash-benchmark" } dependencies = [ { name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, From 9431952ca27fdb7d81ff225a2cffb0ef9f425bb1 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 03:16:51 -0500 Subject: [PATCH 080/100] refactor: move static_analysis, concolic_utils, coverage_utils to languages/python/static_analysis/ --- .../python/static_analysis}/concolic_utils.py | 0 .../python/static_analysis}/coverage_utils.py | 0 .../python/static_analysis}/static_analysis.py | 0 codeflash/optimization/function_optimizer.py | 2 +- codeflash/optimization/optimizer.py | 4 ++-- codeflash/verification/concolic_testing.py | 4 ++-- codeflash/verification/coverage_utils.py | 2 +- codeflash/verification/test_runner.py | 2 +- tests/code_utils/test_concolic_utils.py | 2 +- tests/code_utils/test_coverage_utils.py | 2 +- tests/test_code_utils.py | 6 +++--- tests/test_static_analysis.py | 10 +++++----- 12 files changed, 17 insertions(+), 17 deletions(-) rename codeflash/{code_utils => languages/python/static_analysis}/concolic_utils.py (100%) rename codeflash/{code_utils => languages/python/static_analysis}/coverage_utils.py (100%) rename codeflash/{code_utils => languages/python/static_analysis}/static_analysis.py (100%) diff --git a/codeflash/code_utils/concolic_utils.py b/codeflash/languages/python/static_analysis/concolic_utils.py similarity index 100% rename from codeflash/code_utils/concolic_utils.py rename to codeflash/languages/python/static_analysis/concolic_utils.py diff --git a/codeflash/code_utils/coverage_utils.py b/codeflash/languages/python/static_analysis/coverage_utils.py similarity index 100% rename from codeflash/code_utils/coverage_utils.py rename to codeflash/languages/python/static_analysis/coverage_utils.py diff --git a/codeflash/code_utils/static_analysis.py b/codeflash/languages/python/static_analysis/static_analysis.py similarity index 100% rename from codeflash/code_utils/static_analysis.py rename to codeflash/languages/python/static_analysis/static_analysis.py diff --git a/codeflash/optimization/function_optimizer.py b/codeflash/optimization/function_optimizer.py index 55dfa314e..9a183dde0 100644 --- a/codeflash/optimization/function_optimizer.py +++ b/codeflash/optimization/function_optimizer.py @@ -72,7 +72,7 @@ from codeflash.code_utils.instrument_existing_tests import inject_profiling_into_existing_test from codeflash.code_utils.line_profile_utils import add_decorator_imports, contains_jit_decorator from codeflash.code_utils.shell_utils import make_env_with_project_root -from codeflash.code_utils.static_analysis import get_first_top_level_function_or_method_ast +from codeflash.languages.python.static_analysis.static_analysis import get_first_top_level_function_or_method_ast from codeflash.code_utils.time_utils import humanize_runtime from codeflash.discovery.functions_to_optimize import was_function_previously_optimized from codeflash.either import Failure, Success, is_successful diff --git a/codeflash/optimization/optimizer.py b/codeflash/optimization/optimizer.py index 3211ab59b..6a57dd8db 100644 --- a/codeflash/optimization/optimizer.py +++ b/codeflash/optimization/optimizer.py @@ -250,7 +250,7 @@ def create_function_optimizer( original_module_path: Path | None = None, call_graph: DependencyResolver | None = None, ) -> FunctionOptimizer | None: - from codeflash.code_utils.static_analysis import get_first_top_level_function_or_method_ast + from codeflash.languages.python.static_analysis.static_analysis import get_first_top_level_function_or_method_ast from codeflash.optimization.function_optimizer import FunctionOptimizer if function_to_optimize_ast is None and original_module_ast is not None: @@ -294,7 +294,7 @@ def prepare_module_for_optimization( self, original_module_path: Path ) -> tuple[dict[Path, ValidCode], ast.Module | None] | None: from codeflash.code_utils.code_replacer import normalize_code, normalize_node - from codeflash.code_utils.static_analysis import analyze_imported_modules + from codeflash.languages.python.static_analysis.static_analysis import analyze_imported_modules logger.info(f"loading|Examining file {original_module_path!s}") console.rule() diff --git a/codeflash/verification/concolic_testing.py b/codeflash/verification/concolic_testing.py index 05cad9f7a..c648c5cf6 100644 --- a/codeflash/verification/concolic_testing.py +++ b/codeflash/verification/concolic_testing.py @@ -10,9 +10,9 @@ from codeflash.cli_cmds.console import console, logger from codeflash.code_utils.compat import SAFE_SYS_EXECUTABLE -from codeflash.code_utils.concolic_utils import clean_concolic_tests, is_valid_concolic_test +from codeflash.languages.python.static_analysis.concolic_utils import clean_concolic_tests, is_valid_concolic_test from codeflash.code_utils.shell_utils import make_env_with_project_root -from codeflash.code_utils.static_analysis import has_typed_parameters +from codeflash.languages.python.static_analysis.static_analysis import has_typed_parameters from codeflash.discovery.discover_unit_tests import discover_unit_tests from codeflash.languages import is_python from codeflash.lsp.helpers import is_LSP_enabled diff --git a/codeflash/verification/coverage_utils.py b/codeflash/verification/coverage_utils.py index 20535b9f7..08490914e 100644 --- a/codeflash/verification/coverage_utils.py +++ b/codeflash/verification/coverage_utils.py @@ -7,7 +7,7 @@ from coverage.exceptions import NoDataError from codeflash.cli_cmds.console import logger -from codeflash.code_utils.coverage_utils import ( +from codeflash.languages.python.static_analysis.coverage_utils import ( build_fully_qualified_name, extract_dependent_function, generate_candidates, diff --git a/codeflash/verification/test_runner.py b/codeflash/verification/test_runner.py index c0ecdc03d..87cb9e48e 100644 --- a/codeflash/verification/test_runner.py +++ b/codeflash/verification/test_runner.py @@ -13,7 +13,7 @@ from codeflash.code_utils.code_utils import custom_addopts, get_run_tmp_file from codeflash.code_utils.compat import IS_POSIX, SAFE_SYS_EXECUTABLE from codeflash.code_utils.config_consts import TOTAL_LOOPING_TIME_EFFECTIVE -from codeflash.code_utils.coverage_utils import prepare_coverage_files +from codeflash.languages.python.static_analysis.coverage_utils import prepare_coverage_files from codeflash.code_utils.shell_utils import get_cross_platform_subprocess_run_args from codeflash.languages import is_python from codeflash.languages.registry import get_language_support, get_language_support_by_framework diff --git a/tests/code_utils/test_concolic_utils.py b/tests/code_utils/test_concolic_utils.py index 672bad38a..3a873fde0 100644 --- a/tests/code_utils/test_concolic_utils.py +++ b/tests/code_utils/test_concolic_utils.py @@ -2,7 +2,7 @@ import pytest -from codeflash.code_utils.concolic_utils import AssertCleanup, is_valid_concolic_test +from codeflash.languages.python.static_analysis.concolic_utils import AssertCleanup, is_valid_concolic_test class TestFirstTopLevelArg: diff --git a/tests/code_utils/test_coverage_utils.py b/tests/code_utils/test_coverage_utils.py index d637bac5e..3ca28e898 100644 --- a/tests/code_utils/test_coverage_utils.py +++ b/tests/code_utils/test_coverage_utils.py @@ -2,7 +2,7 @@ from typing import Any -from codeflash.code_utils.coverage_utils import build_fully_qualified_name, extract_dependent_function +from codeflash.languages.python.static_analysis.coverage_utils import build_fully_qualified_name, extract_dependent_function from codeflash.models.function_types import FunctionParent from codeflash.models.models import CodeOptimizationContext, CodeString, CodeStringsMarkdown from codeflash.verification.coverage_utils import CoverageUtils diff --git a/tests/test_code_utils.py b/tests/test_code_utils.py index 6844a16a1..3b794e59c 100644 --- a/tests/test_code_utils.py +++ b/tests/test_code_utils.py @@ -19,8 +19,8 @@ path_belongs_to_site_packages, validate_python_code, ) -from codeflash.code_utils.concolic_utils import clean_concolic_tests -from codeflash.code_utils.coverage_utils import extract_dependent_function, generate_candidates, prepare_coverage_files +from codeflash.languages.python.static_analysis.concolic_utils import clean_concolic_tests +from codeflash.languages.python.static_analysis.coverage_utils import extract_dependent_function, generate_candidates, prepare_coverage_files from codeflash.models.models import CodeStringsMarkdown from codeflash.verification.parse_test_output import resolve_test_file_from_class_path @@ -36,7 +36,7 @@ def multiple_existing_and_non_existing_files(tmp_path: Path) -> list[Path]: @pytest.fixture def mock_get_run_tmp_file() -> Generator[MagicMock, None, None]: - with patch("codeflash.code_utils.coverage_utils.get_run_tmp_file") as mock: + with patch("codeflash.languages.python.static_analysis.coverage_utils.get_run_tmp_file") as mock: yield mock diff --git a/tests/test_static_analysis.py b/tests/test_static_analysis.py index b997edeab..78790da69 100644 --- a/tests/test_static_analysis.py +++ b/tests/test_static_analysis.py @@ -1,7 +1,7 @@ import ast from pathlib import Path -from codeflash.code_utils.static_analysis import ( +from codeflash.languages.python.static_analysis.static_analysis import ( FunctionKind, ImportedInternalModuleAnalysis, analyze_imported_modules, @@ -23,10 +23,10 @@ def test_analyze_imported_modules() -> None: from typing import TYPE_CHECKING if TYPE_CHECKING: - from codeflash.code_utils.static_analysis import ImportedInternalModuleAnalysis + from codeflash.languages.python.static_analysis.static_analysis import ImportedInternalModuleAnalysis def a_function(): - from codeflash.code_utils.static_analysis import analyze_imported_modules + from codeflash.languages.python.static_analysis.static_analysis import analyze_imported_modules from returns.result import Failure, Success pass """ @@ -37,8 +37,8 @@ def a_function(): expected_imported_module_analysis = [ ImportedInternalModuleAnalysis( name="static_analysis", - full_name="codeflash.code_utils.static_analysis", - file_path=project_root / Path("codeflash/code_utils/static_analysis.py"), + full_name="codeflash.languages.python.static_analysis.static_analysis", + file_path=project_root / Path("codeflash/languages/python/static_analysis/static_analysis.py"), ), ImportedInternalModuleAnalysis( name="mymodule", full_name="tests.mymodule", file_path=project_root / Path("tests/mymodule.py") From ae2ee47142633ce361b843433e977948c35e76af Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 03:18:43 -0500 Subject: [PATCH 081/100] refactor: move line_profile_utils, edit_generated_tests to languages/python/static_analysis/ --- codeflash/code_utils/code_replacer.py | 2 +- .../python/static_analysis}/edit_generated_tests.py | 0 .../python/static_analysis}/line_profile_utils.py | 0 codeflash/optimization/function_optimizer.py | 4 ++-- tests/test_add_runtime_comments.py | 2 +- tests/test_instrument_line_profiler.py | 2 +- tests/test_instrument_tests.py | 2 +- tests/test_remove_functions_from_generated_tests.py | 2 +- 8 files changed, 7 insertions(+), 7 deletions(-) rename codeflash/{code_utils => languages/python/static_analysis}/edit_generated_tests.py (100%) rename codeflash/{code_utils => languages/python/static_analysis}/line_profile_utils.py (100%) diff --git a/codeflash/code_utils/code_replacer.py b/codeflash/code_utils/code_replacer.py index 3ad5eba2d..efc9e5798 100644 --- a/codeflash/code_utils/code_replacer.py +++ b/codeflash/code_utils/code_replacer.py @@ -17,7 +17,7 @@ ) from codeflash.code_utils.config_parser import find_conftest_files from codeflash.code_utils.formatter import sort_imports -from codeflash.code_utils.line_profile_utils import ImportAdder +from codeflash.languages.python.static_analysis.line_profile_utils import ImportAdder from codeflash.languages import is_python from codeflash.models.models import FunctionParent diff --git a/codeflash/code_utils/edit_generated_tests.py b/codeflash/languages/python/static_analysis/edit_generated_tests.py similarity index 100% rename from codeflash/code_utils/edit_generated_tests.py rename to codeflash/languages/python/static_analysis/edit_generated_tests.py diff --git a/codeflash/code_utils/line_profile_utils.py b/codeflash/languages/python/static_analysis/line_profile_utils.py similarity index 100% rename from codeflash/code_utils/line_profile_utils.py rename to codeflash/languages/python/static_analysis/line_profile_utils.py diff --git a/codeflash/optimization/function_optimizer.py b/codeflash/optimization/function_optimizer.py index 9a183dde0..64b6aa273 100644 --- a/codeflash/optimization/function_optimizer.py +++ b/codeflash/optimization/function_optimizer.py @@ -59,7 +59,7 @@ get_effort_value, ) from codeflash.code_utils.deduplicate_code import normalize_code -from codeflash.code_utils.edit_generated_tests import ( +from codeflash.languages.python.static_analysis.edit_generated_tests import ( add_runtime_comments_to_generated_tests, disable_ts_check, inject_test_globals, @@ -70,7 +70,7 @@ from codeflash.code_utils.formatter import format_code, format_generated_code, sort_imports from codeflash.code_utils.git_utils import git_root_dir from codeflash.code_utils.instrument_existing_tests import inject_profiling_into_existing_test -from codeflash.code_utils.line_profile_utils import add_decorator_imports, contains_jit_decorator +from codeflash.languages.python.static_analysis.line_profile_utils import add_decorator_imports, contains_jit_decorator from codeflash.code_utils.shell_utils import make_env_with_project_root from codeflash.languages.python.static_analysis.static_analysis import get_first_top_level_function_or_method_ast from codeflash.code_utils.time_utils import humanize_runtime diff --git a/tests/test_add_runtime_comments.py b/tests/test_add_runtime_comments.py index c79e379ce..c70187aa5 100644 --- a/tests/test_add_runtime_comments.py +++ b/tests/test_add_runtime_comments.py @@ -4,7 +4,7 @@ import pytest -from codeflash.code_utils.edit_generated_tests import add_runtime_comments_to_generated_tests +from codeflash.languages.python.static_analysis.edit_generated_tests import add_runtime_comments_to_generated_tests from codeflash.models.models import ( FunctionTestInvocation, GeneratedTests, diff --git a/tests/test_instrument_line_profiler.py b/tests/test_instrument_line_profiler.py index a355905e7..9b1716481 100644 --- a/tests/test_instrument_line_profiler.py +++ b/tests/test_instrument_line_profiler.py @@ -2,7 +2,7 @@ from pathlib import Path from tempfile import TemporaryDirectory -from codeflash.code_utils.line_profile_utils import add_decorator_imports, contains_jit_decorator +from codeflash.languages.python.static_analysis.line_profile_utils import add_decorator_imports, contains_jit_decorator from codeflash.discovery.functions_to_optimize import FunctionToOptimize from codeflash.models.models import CodeOptimizationContext from codeflash.optimization.function_optimizer import FunctionOptimizer diff --git a/tests/test_instrument_tests.py b/tests/test_instrument_tests.py index a8cd75b70..1e2b6073e 100644 --- a/tests/test_instrument_tests.py +++ b/tests/test_instrument_tests.py @@ -15,7 +15,7 @@ FunctionImportedAsVisitor, inject_profiling_into_existing_test, ) -from codeflash.code_utils.line_profile_utils import add_decorator_imports +from codeflash.languages.python.static_analysis.line_profile_utils import add_decorator_imports from codeflash.discovery.functions_to_optimize import FunctionToOptimize from codeflash.models.models import ( CodeOptimizationContext, diff --git a/tests/test_remove_functions_from_generated_tests.py b/tests/test_remove_functions_from_generated_tests.py index 9bb0b4c48..505f09a83 100644 --- a/tests/test_remove_functions_from_generated_tests.py +++ b/tests/test_remove_functions_from_generated_tests.py @@ -2,7 +2,7 @@ import pytest -from codeflash.code_utils.edit_generated_tests import remove_functions_from_generated_tests +from codeflash.languages.python.static_analysis.edit_generated_tests import remove_functions_from_generated_tests from codeflash.models.models import GeneratedTests, GeneratedTestsList From ef99747697c7bba0ca20a24b518a711c8f0f33e7 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 03:21:34 -0500 Subject: [PATCH 082/100] refactor: move code_extractor, code_replacer to languages/python/static_analysis/ --- .../languages/python/context/code_context_extractor.py | 2 +- .../languages/python/context/unused_definition_remover.py | 2 +- .../python/static_analysis}/code_extractor.py | 0 .../python/static_analysis}/code_replacer.py | 2 +- codeflash/languages/python/support.py | 2 +- codeflash/optimization/function_optimizer.py | 4 ++-- codeflash/optimization/optimizer.py | 2 +- codeflash/result/create_pr.py | 2 +- tests/test_add_needed_imports_from_module.py | 8 ++++---- tests/test_code_context_extractor.py | 6 +++--- tests/test_code_extractor_none_aliases_exact.py | 2 +- tests/test_code_replacement.py | 4 ++-- tests/test_get_code.py | 2 +- tests/test_is_numerical_code.py | 2 +- tests/test_languages/test_find_references.py | 2 +- tests/test_languages/test_js_code_replacer.py | 2 +- 16 files changed, 22 insertions(+), 22 deletions(-) rename codeflash/{code_utils => languages/python/static_analysis}/code_extractor.py (100%) rename codeflash/{code_utils => languages/python/static_analysis}/code_replacer.py (99%) diff --git a/codeflash/languages/python/context/code_context_extractor.py b/codeflash/languages/python/context/code_context_extractor.py index 0e42022f6..44ed6e4d8 100644 --- a/codeflash/languages/python/context/code_context_extractor.py +++ b/codeflash/languages/python/context/code_context_extractor.py @@ -10,7 +10,7 @@ import libcst as cst from codeflash.cli_cmds.console import logger -from codeflash.code_utils.code_extractor import add_needed_imports_from_module, find_preexisting_objects +from codeflash.languages.python.static_analysis.code_extractor import add_needed_imports_from_module, find_preexisting_objects from codeflash.code_utils.code_utils import encoded_tokens_len, get_qualified_name, path_belongs_to_site_packages from codeflash.code_utils.config_consts import OPTIMIZATION_CONTEXT_TOKEN_LIMIT, TESTGEN_CONTEXT_TOKEN_LIMIT from codeflash.discovery.functions_to_optimize import FunctionToOptimize # noqa: TC001 diff --git a/codeflash/languages/python/context/unused_definition_remover.py b/codeflash/languages/python/context/unused_definition_remover.py index 3cc7c173a..96bbd9781 100644 --- a/codeflash/languages/python/context/unused_definition_remover.py +++ b/codeflash/languages/python/context/unused_definition_remover.py @@ -10,7 +10,7 @@ import libcst as cst from codeflash.cli_cmds.console import logger -from codeflash.code_utils.code_replacer import replace_function_definitions_in_module +from codeflash.languages.python.static_analysis.code_replacer import replace_function_definitions_in_module from codeflash.languages import is_javascript from codeflash.models.models import CodeString, CodeStringsMarkdown diff --git a/codeflash/code_utils/code_extractor.py b/codeflash/languages/python/static_analysis/code_extractor.py similarity index 100% rename from codeflash/code_utils/code_extractor.py rename to codeflash/languages/python/static_analysis/code_extractor.py diff --git a/codeflash/code_utils/code_replacer.py b/codeflash/languages/python/static_analysis/code_replacer.py similarity index 99% rename from codeflash/code_utils/code_replacer.py rename to codeflash/languages/python/static_analysis/code_replacer.py index efc9e5798..9c4199278 100644 --- a/codeflash/code_utils/code_replacer.py +++ b/codeflash/languages/python/static_analysis/code_replacer.py @@ -10,7 +10,7 @@ from libcst.metadata import PositionProvider from codeflash.cli_cmds.console import logger -from codeflash.code_utils.code_extractor import ( +from codeflash.languages.python.static_analysis.code_extractor import ( add_global_assignments, add_needed_imports_from_module, find_insertion_index_after_imports, diff --git a/codeflash/languages/python/support.py b/codeflash/languages/python/support.py index b026e99e5..7eb52575b 100644 --- a/codeflash/languages/python/support.py +++ b/codeflash/languages/python/support.py @@ -379,7 +379,7 @@ def replace_function(self, source: str, function: FunctionToOptimize, new_source Modified source code with function replaced. """ - from codeflash.code_utils.code_replacer import replace_functions_in_file + from codeflash.languages.python.static_analysis.code_replacer import replace_functions_in_file try: # Determine the function names to replace diff --git a/codeflash/optimization/function_optimizer.py b/codeflash/optimization/function_optimizer.py index 64b6aa273..37ce0554c 100644 --- a/codeflash/optimization/function_optimizer.py +++ b/codeflash/optimization/function_optimizer.py @@ -26,8 +26,8 @@ from codeflash.benchmarking.utils import process_benchmark_data from codeflash.cli_cmds.console import code_print, console, logger, lsp_log, progress_bar from codeflash.code_utils import env_utils -from codeflash.code_utils.code_extractor import get_opt_review_metrics, is_numerical_code -from codeflash.code_utils.code_replacer import ( +from codeflash.languages.python.static_analysis.code_extractor import get_opt_review_metrics, is_numerical_code +from codeflash.languages.python.static_analysis.code_replacer import ( add_custom_marker_to_all_tests, modify_autouse_fixture, replace_function_definitions_in_module, diff --git a/codeflash/optimization/optimizer.py b/codeflash/optimization/optimizer.py index 6a57dd8db..a2b375bcc 100644 --- a/codeflash/optimization/optimizer.py +++ b/codeflash/optimization/optimizer.py @@ -293,7 +293,7 @@ def create_function_optimizer( def prepare_module_for_optimization( self, original_module_path: Path ) -> tuple[dict[Path, ValidCode], ast.Module | None] | None: - from codeflash.code_utils.code_replacer import normalize_code, normalize_node + from codeflash.languages.python.static_analysis.code_replacer import normalize_code, normalize_node from codeflash.languages.python.static_analysis.static_analysis import analyze_imported_modules logger.info(f"loading|Examining file {original_module_path!s}") diff --git a/codeflash/result/create_pr.py b/codeflash/result/create_pr.py index b276725f2..e466f1012 100644 --- a/codeflash/result/create_pr.py +++ b/codeflash/result/create_pr.py @@ -9,7 +9,7 @@ from codeflash.api import cfapi from codeflash.cli_cmds.console import console, logger from codeflash.code_utils import env_utils -from codeflash.code_utils.code_replacer import is_zero_diff +from codeflash.languages.python.static_analysis.code_replacer import is_zero_diff from codeflash.code_utils.git_utils import check_and_push_branch, get_current_branch, get_repo_owner_and_name from codeflash.code_utils.github_utils import github_pr_url from codeflash.code_utils.tabulate import tabulate diff --git a/tests/test_add_needed_imports_from_module.py b/tests/test_add_needed_imports_from_module.py index efb2a254c..03d62cdc8 100644 --- a/tests/test_add_needed_imports_from_module.py +++ b/tests/test_add_needed_imports_from_module.py @@ -3,13 +3,13 @@ import libcst as cst -from codeflash.code_utils.code_extractor import ( +from codeflash.languages.python.static_analysis.code_extractor import ( DottedImportCollector, add_needed_imports_from_module, find_preexisting_objects, resolve_star_import, ) -from codeflash.code_utils.code_replacer import replace_functions_and_add_imports +from codeflash.languages.python.static_analysis.code_replacer import replace_functions_and_add_imports from codeflash.models.models import FunctionParent @@ -22,7 +22,7 @@ def test_add_needed_imports_from_module0() -> None: import tiktoken from jedi.api.classes import Name from pydantic.dataclasses import dataclass -from codeflash.code_utils.code_extractor import get_code, get_code_no_skeleton +from codeflash.languages.python.static_analysis.code_extractor import get_code, get_code_no_skeleton from codeflash.code_utils.code_utils import path_belongs_to_site_packages from codeflash.discovery.functions_to_optimize import FunctionParent, FunctionToOptimize @@ -76,7 +76,7 @@ def test_add_needed_imports_from_module() -> None: from jedi.api.classes import Name from pydantic.dataclasses import dataclass -from codeflash.code_utils.code_extractor import get_code, get_code_no_skeleton +from codeflash.languages.python.static_analysis.code_extractor import get_code, get_code_no_skeleton from codeflash.code_utils.code_utils import path_belongs_to_site_packages from codeflash.discovery.functions_to_optimize import FunctionParent, FunctionToOptimize diff --git a/tests/test_code_context_extractor.py b/tests/test_code_context_extractor.py index 4dfddb4f7..2d87fbf24 100644 --- a/tests/test_code_context_extractor.py +++ b/tests/test_code_context_extractor.py @@ -8,8 +8,8 @@ import pytest -from codeflash.code_utils.code_extractor import GlobalAssignmentCollector, add_global_assignments -from codeflash.code_utils.code_replacer import replace_functions_and_add_imports +from codeflash.languages.python.static_analysis.code_extractor import GlobalAssignmentCollector, add_global_assignments +from codeflash.languages.python.static_analysis.code_replacer import replace_functions_and_add_imports from codeflash.discovery.functions_to_optimize import FunctionToOptimize from codeflash.languages.python.context.code_context_extractor import ( collect_names_from_annotation, @@ -2870,7 +2870,7 @@ def test_global_function_collector(): """Test GlobalFunctionCollector correctly collects module-level function definitions.""" import libcst as cst - from codeflash.code_utils.code_extractor import GlobalFunctionCollector + from codeflash.languages.python.static_analysis.code_extractor import GlobalFunctionCollector source_code = """ # Module-level functions diff --git a/tests/test_code_extractor_none_aliases_exact.py b/tests/test_code_extractor_none_aliases_exact.py index e212de857..464680bd2 100644 --- a/tests/test_code_extractor_none_aliases_exact.py +++ b/tests/test_code_extractor_none_aliases_exact.py @@ -1,7 +1,7 @@ import tempfile from pathlib import Path -from codeflash.code_utils.code_extractor import add_needed_imports_from_module +from codeflash.languages.python.static_analysis.code_extractor import add_needed_imports_from_module def test_add_needed_imports_with_none_aliases(): diff --git a/tests/test_code_replacement.py b/tests/test_code_replacement.py index fbca6d71e..77d9108ab 100644 --- a/tests/test_code_replacement.py +++ b/tests/test_code_replacement.py @@ -7,8 +7,8 @@ import libcst as cst -from codeflash.code_utils.code_extractor import delete___future___aliased_imports, find_preexisting_objects -from codeflash.code_utils.code_replacer import ( +from codeflash.languages.python.static_analysis.code_extractor import delete___future___aliased_imports, find_preexisting_objects +from codeflash.languages.python.static_analysis.code_replacer import ( AddRequestArgument, AutouseFixtureModifier, OptimFunctionCollector, diff --git a/tests/test_get_code.py b/tests/test_get_code.py index 50ac349cb..6f50ca44e 100644 --- a/tests/test_get_code.py +++ b/tests/test_get_code.py @@ -3,7 +3,7 @@ import pytest -from codeflash.code_utils.code_extractor import get_code +from codeflash.languages.python.static_analysis.code_extractor import get_code from codeflash.discovery.functions_to_optimize import FunctionToOptimize from codeflash.models.models import FunctionParent diff --git a/tests/test_is_numerical_code.py b/tests/test_is_numerical_code.py index 831d9c97e..3226bb77e 100644 --- a/tests/test_is_numerical_code.py +++ b/tests/test_is_numerical_code.py @@ -2,7 +2,7 @@ from unittest.mock import patch -from codeflash.code_utils.code_extractor import is_numerical_code +from codeflash.languages.python.static_analysis.code_extractor import is_numerical_code @patch("codeflash.code_utils.code_extractor.has_numba", True) diff --git a/tests/test_languages/test_find_references.py b/tests/test_languages/test_find_references.py index 537e3ef0b..88701d3d0 100644 --- a/tests/test_languages/test_find_references.py +++ b/tests/test_languages/test_find_references.py @@ -22,7 +22,7 @@ find_references, ) from codeflash.languages.base import Language, FunctionInfo, ReferenceInfo -from codeflash.code_utils.code_extractor import _format_references_as_markdown +from codeflash.languages.python.static_analysis.code_extractor import _format_references_as_markdown from codeflash.models.models import FunctionParent diff --git a/tests/test_languages/test_js_code_replacer.py b/tests/test_languages/test_js_code_replacer.py index 9e251804a..5700c4bfd 100644 --- a/tests/test_languages/test_js_code_replacer.py +++ b/tests/test_languages/test_js_code_replacer.py @@ -14,7 +14,7 @@ import pytest -from codeflash.code_utils.code_replacer import replace_function_definitions_for_language +from codeflash.languages.python.static_analysis.code_replacer import replace_function_definitions_for_language from codeflash.languages.base import Language from codeflash.languages.current import set_current_language from codeflash.languages.javascript.module_system import ( From 52a79bc0046cae8891b94feb9c469a2ffbc7e25c Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 03:22:48 -0500 Subject: [PATCH 083/100] chore: add static_analysis __init__.py and fix import sorting --- .../python/context/code_context_extractor.py | 5 +++- .../context/unused_definition_remover.py | 2 +- .../python/static_analysis/__init__.py | 0 .../python/static_analysis/code_replacer.py | 6 ++-- codeflash/optimization/function_optimizer.py | 30 +++++++++---------- codeflash/optimization/optimizer.py | 4 ++- codeflash/result/create_pr.py | 2 +- codeflash/verification/concolic_testing.py | 4 +-- codeflash/verification/test_runner.py | 2 +- 9 files changed, 30 insertions(+), 25 deletions(-) create mode 100644 codeflash/languages/python/static_analysis/__init__.py diff --git a/codeflash/languages/python/context/code_context_extractor.py b/codeflash/languages/python/context/code_context_extractor.py index 44ed6e4d8..0752f91b8 100644 --- a/codeflash/languages/python/context/code_context_extractor.py +++ b/codeflash/languages/python/context/code_context_extractor.py @@ -10,7 +10,6 @@ import libcst as cst from codeflash.cli_cmds.console import logger -from codeflash.languages.python.static_analysis.code_extractor import add_needed_imports_from_module, find_preexisting_objects from codeflash.code_utils.code_utils import encoded_tokens_len, get_qualified_name, path_belongs_to_site_packages from codeflash.code_utils.config_consts import OPTIMIZATION_CONTEXT_TOKEN_LIMIT, TESTGEN_CONTEXT_TOKEN_LIMIT from codeflash.discovery.functions_to_optimize import FunctionToOptimize # noqa: TC001 @@ -24,6 +23,10 @@ recurse_sections, remove_unused_definitions_by_function_names, ) +from codeflash.languages.python.static_analysis.code_extractor import ( + add_needed_imports_from_module, + find_preexisting_objects, +) from codeflash.models.models import ( CodeContextType, CodeOptimizationContext, diff --git a/codeflash/languages/python/context/unused_definition_remover.py b/codeflash/languages/python/context/unused_definition_remover.py index 96bbd9781..669f540bf 100644 --- a/codeflash/languages/python/context/unused_definition_remover.py +++ b/codeflash/languages/python/context/unused_definition_remover.py @@ -10,8 +10,8 @@ import libcst as cst from codeflash.cli_cmds.console import logger -from codeflash.languages.python.static_analysis.code_replacer import replace_function_definitions_in_module from codeflash.languages import is_javascript +from codeflash.languages.python.static_analysis.code_replacer import replace_function_definitions_in_module from codeflash.models.models import CodeString, CodeStringsMarkdown if TYPE_CHECKING: diff --git a/codeflash/languages/python/static_analysis/__init__.py b/codeflash/languages/python/static_analysis/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/codeflash/languages/python/static_analysis/code_replacer.py b/codeflash/languages/python/static_analysis/code_replacer.py index 9c4199278..2b96b9eba 100644 --- a/codeflash/languages/python/static_analysis/code_replacer.py +++ b/codeflash/languages/python/static_analysis/code_replacer.py @@ -10,15 +10,15 @@ from libcst.metadata import PositionProvider from codeflash.cli_cmds.console import logger +from codeflash.code_utils.config_parser import find_conftest_files +from codeflash.code_utils.formatter import sort_imports +from codeflash.languages import is_python from codeflash.languages.python.static_analysis.code_extractor import ( add_global_assignments, add_needed_imports_from_module, find_insertion_index_after_imports, ) -from codeflash.code_utils.config_parser import find_conftest_files -from codeflash.code_utils.formatter import sort_imports from codeflash.languages.python.static_analysis.line_profile_utils import ImportAdder -from codeflash.languages import is_python from codeflash.models.models import FunctionParent if TYPE_CHECKING: diff --git a/codeflash/optimization/function_optimizer.py b/codeflash/optimization/function_optimizer.py index 37ce0554c..0ba358c5b 100644 --- a/codeflash/optimization/function_optimizer.py +++ b/codeflash/optimization/function_optimizer.py @@ -26,12 +26,6 @@ from codeflash.benchmarking.utils import process_benchmark_data from codeflash.cli_cmds.console import code_print, console, logger, lsp_log, progress_bar from codeflash.code_utils import env_utils -from codeflash.languages.python.static_analysis.code_extractor import get_opt_review_metrics, is_numerical_code -from codeflash.languages.python.static_analysis.code_replacer import ( - add_custom_marker_to_all_tests, - modify_autouse_fixture, - replace_function_definitions_in_module, -) from codeflash.code_utils.code_utils import ( choose_weights, cleanup_paths, @@ -59,20 +53,11 @@ get_effort_value, ) from codeflash.code_utils.deduplicate_code import normalize_code -from codeflash.languages.python.static_analysis.edit_generated_tests import ( - add_runtime_comments_to_generated_tests, - disable_ts_check, - inject_test_globals, - normalize_generated_tests_imports, - remove_functions_from_generated_tests, -) from codeflash.code_utils.env_utils import get_pr_number from codeflash.code_utils.formatter import format_code, format_generated_code, sort_imports from codeflash.code_utils.git_utils import git_root_dir from codeflash.code_utils.instrument_existing_tests import inject_profiling_into_existing_test -from codeflash.languages.python.static_analysis.line_profile_utils import add_decorator_imports, contains_jit_decorator from codeflash.code_utils.shell_utils import make_env_with_project_root -from codeflash.languages.python.static_analysis.static_analysis import get_first_top_level_function_or_method_ast from codeflash.code_utils.time_utils import humanize_runtime from codeflash.discovery.functions_to_optimize import was_function_previously_optimized from codeflash.either import Failure, Success, is_successful @@ -86,6 +71,21 @@ detect_unused_helper_functions, revert_unused_helper_functions, ) +from codeflash.languages.python.static_analysis.code_extractor import get_opt_review_metrics, is_numerical_code +from codeflash.languages.python.static_analysis.code_replacer import ( + add_custom_marker_to_all_tests, + modify_autouse_fixture, + replace_function_definitions_in_module, +) +from codeflash.languages.python.static_analysis.edit_generated_tests import ( + add_runtime_comments_to_generated_tests, + disable_ts_check, + inject_test_globals, + normalize_generated_tests_imports, + remove_functions_from_generated_tests, +) +from codeflash.languages.python.static_analysis.line_profile_utils import add_decorator_imports, contains_jit_decorator +from codeflash.languages.python.static_analysis.static_analysis import get_first_top_level_function_or_method_ast from codeflash.lsp.helpers import is_LSP_enabled, report_to_markdown_table, tree_to_markdown from codeflash.lsp.lsp_message import LspCodeMessage, LspMarkdownMessage, LSPMessageId from codeflash.models.ExperimentMetadata import ExperimentMetadata diff --git a/codeflash/optimization/optimizer.py b/codeflash/optimization/optimizer.py index a2b375bcc..5527a0567 100644 --- a/codeflash/optimization/optimizer.py +++ b/codeflash/optimization/optimizer.py @@ -250,7 +250,9 @@ def create_function_optimizer( original_module_path: Path | None = None, call_graph: DependencyResolver | None = None, ) -> FunctionOptimizer | None: - from codeflash.languages.python.static_analysis.static_analysis import get_first_top_level_function_or_method_ast + from codeflash.languages.python.static_analysis.static_analysis import ( + get_first_top_level_function_or_method_ast, + ) from codeflash.optimization.function_optimizer import FunctionOptimizer if function_to_optimize_ast is None and original_module_ast is not None: diff --git a/codeflash/result/create_pr.py b/codeflash/result/create_pr.py index e466f1012..cbde5399a 100644 --- a/codeflash/result/create_pr.py +++ b/codeflash/result/create_pr.py @@ -9,12 +9,12 @@ from codeflash.api import cfapi from codeflash.cli_cmds.console import console, logger from codeflash.code_utils import env_utils -from codeflash.languages.python.static_analysis.code_replacer import is_zero_diff from codeflash.code_utils.git_utils import check_and_push_branch, get_current_branch, get_repo_owner_and_name from codeflash.code_utils.github_utils import github_pr_url from codeflash.code_utils.tabulate import tabulate from codeflash.code_utils.time_utils import format_perf, format_time from codeflash.github.PrComment import FileDiffContent, PrComment +from codeflash.languages.python.static_analysis.code_replacer import is_zero_diff from codeflash.result.critic import performance_gain if TYPE_CHECKING: diff --git a/codeflash/verification/concolic_testing.py b/codeflash/verification/concolic_testing.py index c648c5cf6..8fa43de7e 100644 --- a/codeflash/verification/concolic_testing.py +++ b/codeflash/verification/concolic_testing.py @@ -10,11 +10,11 @@ from codeflash.cli_cmds.console import console, logger from codeflash.code_utils.compat import SAFE_SYS_EXECUTABLE -from codeflash.languages.python.static_analysis.concolic_utils import clean_concolic_tests, is_valid_concolic_test from codeflash.code_utils.shell_utils import make_env_with_project_root -from codeflash.languages.python.static_analysis.static_analysis import has_typed_parameters from codeflash.discovery.discover_unit_tests import discover_unit_tests from codeflash.languages import is_python +from codeflash.languages.python.static_analysis.concolic_utils import clean_concolic_tests, is_valid_concolic_test +from codeflash.languages.python.static_analysis.static_analysis import has_typed_parameters from codeflash.lsp.helpers import is_LSP_enabled from codeflash.telemetry.posthog_cf import ph from codeflash.verification.verification_utils import TestConfig diff --git a/codeflash/verification/test_runner.py b/codeflash/verification/test_runner.py index 87cb9e48e..a64bdd8e1 100644 --- a/codeflash/verification/test_runner.py +++ b/codeflash/verification/test_runner.py @@ -13,9 +13,9 @@ from codeflash.code_utils.code_utils import custom_addopts, get_run_tmp_file from codeflash.code_utils.compat import IS_POSIX, SAFE_SYS_EXECUTABLE from codeflash.code_utils.config_consts import TOTAL_LOOPING_TIME_EFFECTIVE -from codeflash.languages.python.static_analysis.coverage_utils import prepare_coverage_files from codeflash.code_utils.shell_utils import get_cross_platform_subprocess_run_args from codeflash.languages import is_python +from codeflash.languages.python.static_analysis.coverage_utils import prepare_coverage_files from codeflash.languages.registry import get_language_support, get_language_support_by_framework from codeflash.models.models import TestFiles, TestType From 52c0e80db11d3d1e3010cd55b1dda9c50112d371 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 04:45:24 -0500 Subject: [PATCH 084/100] fix: update mypy_allowlist.txt paths for moved static analysis modules --- mypy_allowlist.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mypy_allowlist.txt b/mypy_allowlist.txt index e08b14e22..378d89675 100644 --- a/mypy_allowlist.txt +++ b/mypy_allowlist.txt @@ -28,8 +28,8 @@ codeflash/code_utils/__init__.py codeflash/code_utils/time_utils.py codeflash/code_utils/env_utils.py codeflash/code_utils/config_consts.py -codeflash/code_utils/static_analysis.py -codeflash/code_utils/edit_generated_tests.py +codeflash/languages/python/static_analysis/static_analysis.py +codeflash/languages/python/static_analysis/edit_generated_tests.py codeflash/cli_cmds/console_constants.py codeflash/cli_cmds/logging_config.py codeflash/cli_cmds/__init__.py From b3d77dd93b9a7110401a5571b263a54a13150058 Mon Sep 17 00:00:00 2001 From: "codeflash-ai[bot]" <148906541+codeflash-ai[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 09:51:44 +0000 Subject: [PATCH 085/100] Optimize PythonSupport.replace_function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The optimization achieves a **523% speedup** (from 2.29s to 367ms) by eliminating expensive libcst metadata operations and replacing the visitor/transformer pattern with direct AST manipulation. ## Key Performance Improvements **1. Removed MetadataWrapper (~430ms saved, ~9% of total time)** - Original: `cst.metadata.MetadataWrapper(cst.parse_module(optimized_code))` then `optimized_module.visit(visitor)` took 5.45s combined - Optimized: Direct `cst.parse_module(optimized_code)` takes only 183ms - The metadata infrastructure was unnecessary for this use case since we only need to identify and extract function definitions, not track parent-child relationships **2. Replaced Visitor Pattern with Direct Iteration (~5.3s saved, ~78% of total time)** - Original: Used `OptimFunctionCollector` visitor class with metadata dependencies, requiring full tree traversal and metadata resolution - Optimized: Simple for-loop over `optimized_module.body` to collect functions and classes - Direct iteration avoids the overhead of visitor callback infrastructure and metadata lookups **3. Eliminated Transformer Pattern (~87ms saved, ~1.6% of total time)** - Original: Used `OptimFunctionReplacer` transformer to traverse and rebuild the entire AST - Optimized: Manual list building with targeted `with_changes()` calls only where needed - Reduces redundant tree traversals and object creation **4. Improved Memory Efficiency** - Pre-allocated data structures instead of using visitor state - Single-pass collection instead of multiple tree traversals - Direct list manipulation instead of transformer's recursive rebuilding ## Test Performance Pattern The optimization excels across all test cases: - **Simple functions**: 587-696% faster (e.g., `test_replace_simple_function`: 2.62ms → 459μs) - **Class methods**: 509-549% faster (e.g., `test_replace_function_in_class`: 2.24ms → 367μs) - **Large files**: Still shows gains even with parsing overhead (e.g., `test_replace_function_in_large_file`: 9.37ms → 7.32ms, 28% faster) - **Batch operations**: Dramatic improvement in loops (e.g., 1000 iterations: 1.91s → 201ms, 850% faster) ## Impact on Workloads Based on `function_references`, this optimization benefits: - **Test suites** that perform multiple function replacements during test execution - **Code refactoring tools** that need to replace functions while preserving surrounding code - **Language parity testing** where consistent performance across language support implementations matters The optimization is particularly valuable for batch processing scenarios (as shown by the 850% improvement in the loop test), making it highly effective for CI/CD pipelines and automated code transformation workflows. --- .../python/static_analysis/code_replacer.py | 109 +++++++++++++++--- 1 file changed, 95 insertions(+), 14 deletions(-) diff --git a/codeflash/languages/python/static_analysis/code_replacer.py b/codeflash/languages/python/static_analysis/code_replacer.py index 2b96b9eba..8051c0766 100644 --- a/codeflash/languages/python/static_analysis/code_replacer.py +++ b/codeflash/languages/python/static_analysis/code_replacer.py @@ -401,23 +401,104 @@ def replace_functions_in_file( return source_code parsed_function_names.append((class_name, function_name)) - # Collect functions we want to modify from the optimized code - optimized_module = cst.metadata.MetadataWrapper(cst.parse_module(optimized_code)) + # Collect functions from optimized code without using MetadataWrapper + optimized_module = cst.parse_module(optimized_code) + modified_functions: dict[tuple[str | None, str], cst.FunctionDef] = {} + new_functions: list[cst.FunctionDef] = [] + new_class_functions: dict[str, list[cst.FunctionDef]] = defaultdict(list) + new_classes: list[cst.ClassDef] = [] + modified_init_functions: dict[str, cst.FunctionDef] = {} + + function_names_set = set(parsed_function_names) + + for node in optimized_module.body: + if isinstance(node, cst.FunctionDef): + key = (None, node.name.value) + if key in function_names_set: + modified_functions[key] = node + elif preexisting_objects and (node.name.value, ()) not in preexisting_objects: + new_functions.append(node) + + elif isinstance(node, cst.ClassDef): + class_name = node.name.value + parents = (FunctionParent(name=class_name, type="ClassDef"),) + + if (class_name, ()) not in preexisting_objects: + new_classes.append(node) + + for child in node.body.body: + if isinstance(child, cst.FunctionDef): + method_key = (class_name, child.name.value) + if method_key in function_names_set: + modified_functions[method_key] = child + elif child.name.value == "__init__" and preexisting_objects: + modified_init_functions[class_name] = child + elif preexisting_objects and (child.name.value, parents) not in preexisting_objects: + new_class_functions[class_name].append(child) + original_module = cst.parse_module(source_code) - visitor = OptimFunctionCollector(preexisting_objects, set(parsed_function_names)) - optimized_module.visit(visitor) + max_function_index = None + max_class_index = None + for index, _node in enumerate(original_module.body): + if isinstance(_node, cst.FunctionDef): + max_function_index = index + if isinstance(_node, cst.ClassDef): + max_class_index = index + + new_body: list[cst.CSTNode] = [] + existing_class_names = set() + + for node in original_module.body: + if isinstance(node, cst.FunctionDef): + key = (None, node.name.value) + if key in modified_functions: + modified_func = modified_functions[key] + new_body.append(node.with_changes(body=modified_func.body, decorators=modified_func.decorators)) + else: + new_body.append(node) + + elif isinstance(node, cst.ClassDef): + class_name = node.name.value + existing_class_names.add(class_name) + + new_members: list[cst.CSTNode] = [] + for child in node.body.body: + if isinstance(child, cst.FunctionDef): + key = (class_name, child.name.value) + if key in modified_functions: + modified_func = modified_functions[key] + new_members.append(child.with_changes(body=modified_func.body, decorators=modified_func.decorators)) + elif child.name.value == "__init__" and class_name in modified_init_functions: + new_members.append(modified_init_functions[class_name]) + else: + new_members.append(child) + else: + new_members.append(child) + + if class_name in new_class_functions: + new_members.extend(new_class_functions[class_name]) + + new_body.append(node.with_changes(body=node.body.with_changes(body=new_members))) + else: + new_body.append(node) + + if new_classes: + unique_classes = [nc for nc in new_classes if nc.name.value not in existing_class_names] + if unique_classes: + new_classes_insertion_idx = max_class_index if max_class_index is not None else find_insertion_index_after_imports(original_module) + new_body = list(chain(new_body[:new_classes_insertion_idx], unique_classes, new_body[new_classes_insertion_idx:])) - # Replace these functions in the original code - transformer = OptimFunctionReplacer( - modified_functions=visitor.modified_functions, - new_classes=visitor.new_classes, - new_functions=visitor.new_functions, - new_class_functions=visitor.new_class_functions, - modified_init_functions=visitor.modified_init_functions, - ) - modified_tree = original_module.visit(transformer) - return modified_tree.code + if new_functions: + if max_function_index is not None: + new_body = [*new_body[:max_function_index + 1], *new_functions, *new_body[max_function_index + 1:]] + elif max_class_index is not None: + new_body = [*new_body[:max_class_index + 1], *new_functions, *new_body[max_class_index + 1:]] + else: + new_body = [*new_functions, *new_body] + + updated_module = original_module.with_changes(body=new_body) + return updated_module.code def replace_functions_and_add_imports( From 7fdf5752a7ffd811a469c45934559c0ab2adbc73 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 09:54:06 +0000 Subject: [PATCH 086/100] style: auto-fix linting issues --- .../python/static_analysis/code_replacer.py | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/codeflash/languages/python/static_analysis/code_replacer.py b/codeflash/languages/python/static_analysis/code_replacer.py index 8051c0766..ebd66c8d5 100644 --- a/codeflash/languages/python/static_analysis/code_replacer.py +++ b/codeflash/languages/python/static_analysis/code_replacer.py @@ -448,7 +448,7 @@ def replace_functions_in_file( new_body: list[cst.CSTNode] = [] existing_class_names = set() - + for node in original_module.body: if isinstance(node, cst.FunctionDef): key = (None, node.name.value) @@ -461,24 +461,26 @@ def replace_functions_in_file( elif isinstance(node, cst.ClassDef): class_name = node.name.value existing_class_names.add(class_name) - + new_members: list[cst.CSTNode] = [] for child in node.body.body: if isinstance(child, cst.FunctionDef): key = (class_name, child.name.value) if key in modified_functions: modified_func = modified_functions[key] - new_members.append(child.with_changes(body=modified_func.body, decorators=modified_func.decorators)) + new_members.append( + child.with_changes(body=modified_func.body, decorators=modified_func.decorators) + ) elif child.name.value == "__init__" and class_name in modified_init_functions: new_members.append(modified_init_functions[class_name]) else: new_members.append(child) else: new_members.append(child) - + if class_name in new_class_functions: new_members.extend(new_class_functions[class_name]) - + new_body.append(node.with_changes(body=node.body.with_changes(body=new_members))) else: new_body.append(node) @@ -486,14 +488,18 @@ def replace_functions_in_file( if new_classes: unique_classes = [nc for nc in new_classes if nc.name.value not in existing_class_names] if unique_classes: - new_classes_insertion_idx = max_class_index if max_class_index is not None else find_insertion_index_after_imports(original_module) - new_body = list(chain(new_body[:new_classes_insertion_idx], unique_classes, new_body[new_classes_insertion_idx:])) + new_classes_insertion_idx = ( + max_class_index if max_class_index is not None else find_insertion_index_after_imports(original_module) + ) + new_body = list( + chain(new_body[:new_classes_insertion_idx], unique_classes, new_body[new_classes_insertion_idx:]) + ) if new_functions: if max_function_index is not None: - new_body = [*new_body[:max_function_index + 1], *new_functions, *new_body[max_function_index + 1:]] + new_body = [*new_body[: max_function_index + 1], *new_functions, *new_body[max_function_index + 1 :]] elif max_class_index is not None: - new_body = [*new_body[:max_class_index + 1], *new_functions, *new_body[max_class_index + 1:]] + new_body = [*new_body[: max_class_index + 1], *new_functions, *new_body[max_class_index + 1 :]] else: new_body = [*new_functions, *new_body] From 09a0a33aa8bc92c9a8efc43de4d45a5dd9f7a801 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 05:00:38 -0500 Subject: [PATCH 087/100] fix: update stale @patch paths in test_is_numerical_code.py --- tests/test_is_numerical_code.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/test_is_numerical_code.py b/tests/test_is_numerical_code.py index 3226bb77e..a13a627ac 100644 --- a/tests/test_is_numerical_code.py +++ b/tests/test_is_numerical_code.py @@ -5,7 +5,7 @@ from codeflash.languages.python.static_analysis.code_extractor import is_numerical_code -@patch("codeflash.code_utils.code_extractor.has_numba", True) +@patch("codeflash.languages.python.static_analysis.code_extractor.has_numba", True) class TestBasicNumpyUsage: """Test basic numpy library detection (with numba available).""" @@ -50,7 +50,7 @@ def func(x): assert is_numerical_code(code, "func") is True -@patch("codeflash.code_utils.code_extractor.has_numba", True) +@patch("codeflash.languages.python.static_analysis.code_extractor.has_numba", True) class TestNumpySubmodules: """Test numpy submodule imports (with numba available).""" @@ -265,7 +265,7 @@ def func(x): assert is_numerical_code(code, "func") is True -@patch("codeflash.code_utils.code_extractor.has_numba", True) +@patch("codeflash.languages.python.static_analysis.code_extractor.has_numba", True) class TestScipyUsage: """Test SciPy library detection (with numba available).""" @@ -302,7 +302,7 @@ def func(f, x0): assert is_numerical_code(code, "func") is True -@patch("codeflash.code_utils.code_extractor.has_numba", True) +@patch("codeflash.languages.python.static_analysis.code_extractor.has_numba", True) class TestMathUsage: """Test math standard library detection (with numba available).""" @@ -331,7 +331,7 @@ def calculate(x): assert is_numerical_code(code, "calculate") is True -@patch("codeflash.code_utils.code_extractor.has_numba", True) +@patch("codeflash.languages.python.static_analysis.code_extractor.has_numba", True) class TestClassMethods: """Test detection in class methods, staticmethods, and classmethods (with numba available).""" @@ -472,7 +472,7 @@ def func(): assert is_numerical_code(code, "func") is False -@patch("codeflash.code_utils.code_extractor.has_numba", True) +@patch("codeflash.languages.python.static_analysis.code_extractor.has_numba", True) class TestEdgeCases: """Test edge cases and special scenarios (with numba available).""" @@ -535,7 +535,7 @@ async def async_process(x): assert is_numerical_code(code, "async_process") is False -@patch("codeflash.code_utils.code_extractor.has_numba", True) +@patch("codeflash.languages.python.static_analysis.code_extractor.has_numba", True) class TestStarImports: """Test handling of star imports (with numba available). @@ -575,7 +575,7 @@ def func(x): assert is_numerical_code(code, "func") is False -@patch("codeflash.code_utils.code_extractor.has_numba", True) +@patch("codeflash.languages.python.static_analysis.code_extractor.has_numba", True) class TestNestedUsage: """Test nested numerical library usage patterns (with numba available).""" @@ -618,7 +618,7 @@ def func(x): assert is_numerical_code(code, "func") is True -@patch("codeflash.code_utils.code_extractor.has_numba", True) +@patch("codeflash.languages.python.static_analysis.code_extractor.has_numba", True) class TestMultipleLibraries: """Test code using multiple numerical libraries (with numba available).""" @@ -643,7 +643,7 @@ def analyze(data): assert is_numerical_code(code, "analyze") is True -@patch("codeflash.code_utils.code_extractor.has_numba", True) +@patch("codeflash.languages.python.static_analysis.code_extractor.has_numba", True) class TestQualifiedNames: """Test various qualified name patterns (with numba available).""" @@ -689,7 +689,7 @@ def method(self): assert is_numerical_code(code, "ClassB.method") is False -@patch("codeflash.code_utils.code_extractor.has_numba", True) +@patch("codeflash.languages.python.static_analysis.code_extractor.has_numba", True) class TestEmptyFunctionName: """Test behavior when function_name is empty/None. @@ -807,7 +807,7 @@ def broken( assert is_numerical_code(code, "") is False -@patch("codeflash.code_utils.code_extractor.has_numba", False) +@patch("codeflash.languages.python.static_analysis.code_extractor.has_numba", False) class TestEmptyFunctionNameWithoutNumba: """Test empty function_name behavior when numba is NOT available. @@ -886,7 +886,7 @@ def test_empty_string_math_and_scipy_returns_false_without_numba(self): assert is_numerical_code(code, "") is False -@patch("codeflash.code_utils.code_extractor.has_numba", False) +@patch("codeflash.languages.python.static_analysis.code_extractor.has_numba", False) class TestNumbaNotAvailable: """Test behavior when numba is NOT available in the environment. From 1fcdb4cf8dc3015d4cea6a96705843af1ce9b02a Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 05:42:34 -0500 Subject: [PATCH 088/100] Move JS test-edit helpers into javascript module --- codeflash/languages/javascript/edit_tests.py | 162 ++++++++++++++++++ .../static_analysis/edit_generated_tests.py | 157 +---------------- codeflash/optimization/function_optimizer.py | 8 +- 3 files changed, 172 insertions(+), 155 deletions(-) diff --git a/codeflash/languages/javascript/edit_tests.py b/codeflash/languages/javascript/edit_tests.py index a4523e83b..00ba04f9c 100644 --- a/codeflash/languages/javascript/edit_tests.py +++ b/codeflash/languages/javascript/edit_tests.py @@ -6,10 +6,13 @@ from __future__ import annotations +import os import re +from pathlib import Path from codeflash.cli_cmds.console import logger from codeflash.code_utils.time_utils import format_perf, format_time +from codeflash.models.models import GeneratedTests, GeneratedTestsList from codeflash.result.critic import performance_gain @@ -130,6 +133,165 @@ def find_matching_test(test_description: str) -> str | None: return "\n".join(modified_lines) +JS_TEST_EXTENSIONS = ( + ".test.ts", + ".test.js", + ".test.tsx", + ".test.jsx", + ".spec.ts", + ".spec.js", + ".spec.tsx", + ".spec.jsx", + ".ts", + ".js", + ".tsx", + ".jsx", + ".mjs", + ".mts", +) + + +# TODO:{self} Needs cleanup for jest logic in else block +# Author: Sarthak Agarwal +def is_js_test_module_path(test_module_path: str) -> bool: + """Return True when the module path looks like a JS/TS test path.""" + return any(test_module_path.endswith(ext) for ext in JS_TEST_EXTENSIONS) + + +# Author: Sarthak Agarwal +def resolve_js_test_module_path(test_module_path: str, tests_project_rootdir: Path) -> Path: + """Resolve a JS/TS test module path to a concrete file path.""" + if "/" in test_module_path or "\\" in test_module_path: + return tests_project_rootdir / Path(test_module_path) + + matched_ext = None + for ext in JS_TEST_EXTENSIONS: + if test_module_path.endswith(ext): + matched_ext = ext + break + + if matched_ext: + base_path = test_module_path[: -len(matched_ext)] + file_path = base_path.replace(".", os.sep) + matched_ext + tests_dir_name = tests_project_rootdir.name + if file_path.startswith((tests_dir_name + os.sep, tests_dir_name + "/")): + return tests_project_rootdir.parent / Path(file_path) + return tests_project_rootdir / Path(file_path) + + return tests_project_rootdir / Path(test_module_path) + + +# Patterns for normalizing codeflash imports (legacy -> npm package) +# Author: Sarthak Agarwal +_CODEFLASH_REQUIRE_PATTERN = re.compile( + r"(const|let|var)\s+(\w+)\s*=\s*require\s*\(\s*['\"]\.?/?codeflash-jest-helper['\"]\s*\)" +) +_CODEFLASH_IMPORT_PATTERN = re.compile(r"import\s+(?:\*\s+as\s+)?(\w+)\s+from\s+['\"]\.?/?codeflash-jest-helper['\"]") + + +# Author: Sarthak Agarwal +def normalize_codeflash_imports(source: str) -> str: + """Normalize codeflash imports to use the npm package. + + Replaces legacy local file imports: + const codeflash = require('./codeflash-jest-helper') + import codeflash from './codeflash-jest-helper' + + With npm package imports: + const codeflash = require('codeflash') + + Args: + source: JavaScript/TypeScript source code. + + Returns: + Source code with normalized imports. + + """ + # Replace CommonJS require + source = _CODEFLASH_REQUIRE_PATTERN.sub(r"\1 \2 = require('codeflash')", source) + # Replace ES module import + return _CODEFLASH_IMPORT_PATTERN.sub(r"import \1 from 'codeflash'", source) + + +# Author: ali +def inject_test_globals(generated_tests: GeneratedTestsList, test_framework: str = "jest") -> GeneratedTestsList: + # TODO: inside the prompt tell the llm if it should import jest functions or it's already injected in the global window + """Inject test globals into all generated tests. + + Args: + generated_tests: List of generated tests. + test_framework: The test framework being used ("jest", "vitest", or "mocha"). + + Returns: + Generated tests with test globals injected. + + """ + # we only inject test globals for esm modules + # Use vitest imports for vitest projects, jest imports for jest projects + if test_framework == "vitest": + global_import = "import { vi, describe, it, expect, beforeEach, afterEach, beforeAll, test } from 'vitest'\n" + else: + # Default to jest imports for jest and other frameworks + global_import = ( + "import { jest, describe, it, expect, beforeEach, afterEach, beforeAll, test } from '@jest/globals'\n" + ) + + for test in generated_tests.generated_tests: + test.generated_original_test_source = global_import + test.generated_original_test_source + test.instrumented_behavior_test_source = global_import + test.instrumented_behavior_test_source + test.instrumented_perf_test_source = global_import + test.instrumented_perf_test_source + return generated_tests + + +# Author: ali +def disable_ts_check(generated_tests: GeneratedTestsList) -> GeneratedTestsList: + """Disable TypeScript type checking in all generated tests. + + Args: + generated_tests: List of generated tests. + + Returns: + Generated tests with TypeScript type checking disabled. + + """ + # we only inject test globals for esm modules + ts_nocheck = "// @ts-nocheck\n" + + for test in generated_tests.generated_tests: + test.generated_original_test_source = ts_nocheck + test.generated_original_test_source + test.instrumented_behavior_test_source = ts_nocheck + test.instrumented_behavior_test_source + test.instrumented_perf_test_source = ts_nocheck + test.instrumented_perf_test_source + return generated_tests + + +# Author: Sarthak Agarwal +def normalize_generated_tests_imports(generated_tests: GeneratedTestsList) -> GeneratedTestsList: + """Normalize codeflash imports in all generated tests. + + Args: + generated_tests: List of generated tests. + + Returns: + Generated tests with normalized imports. + + """ + normalized_tests = [] + for test in generated_tests.generated_tests: + # Only normalize JS/TS files + if test.behavior_file_path.suffix in (".js", ".ts", ".jsx", ".tsx", ".mjs", ".mts"): + normalized_test = GeneratedTests( + generated_original_test_source=normalize_codeflash_imports(test.generated_original_test_source), + instrumented_behavior_test_source=normalize_codeflash_imports(test.instrumented_behavior_test_source), + instrumented_perf_test_source=normalize_codeflash_imports(test.instrumented_perf_test_source), + behavior_file_path=test.behavior_file_path, + perf_file_path=test.perf_file_path, + ) + normalized_tests.append(normalized_test) + else: + normalized_tests.append(test) + return GeneratedTestsList(generated_tests=normalized_tests) + + def remove_test_functions(source: str, functions_to_remove: list[str]) -> str: """Remove specific test functions from JavaScript test source code. diff --git a/codeflash/languages/python/static_analysis/edit_generated_tests.py b/codeflash/languages/python/static_analysis/edit_generated_tests.py index 7ec303b7a..b5c3b5454 100644 --- a/codeflash/languages/python/static_analysis/edit_generated_tests.py +++ b/codeflash/languages/python/static_analysis/edit_generated_tests.py @@ -1,7 +1,6 @@ from __future__ import annotations import ast -import os import re from pathlib import Path from typing import TYPE_CHECKING, Optional @@ -12,6 +11,7 @@ from codeflash.cli_cmds.console import logger from codeflash.code_utils.time_utils import format_perf, format_time +from codeflash.languages.javascript.edit_tests import is_js_test_module_path, resolve_js_test_module_path from codeflash.languages.registry import get_language_support from codeflash.models.models import GeneratedTests, GeneratedTestsList from codeflash.result.critic import performance_gain @@ -155,7 +155,6 @@ def _is_python_file(file_path: Path) -> bool: return file_path.suffix == ".py" -# TODO:{self} Needs cleanup for jest logic in else block def unique_inv_id(inv_id_runtimes: dict[InvocationId, list[int]], tests_project_rootdir: Path) -> dict[str, int]: unique_inv_ids: dict[str, int] = {} logger.debug(f"[unique_inv_id] Processing {len(inv_id_runtimes)} invocation IDs") @@ -166,53 +165,13 @@ def unique_inv_id(inv_id_runtimes: dict[InvocationId, list[int]], tests_project_ else inv_id.test_function_name ) - # Detect if test_module_path is a file path (like in js tests) or a Python module name - # File paths contain slashes, module names use dots test_module_path = inv_id.test_module_path - if "/" in test_module_path or "\\" in test_module_path: - # Already a file path - use directly + if is_js_test_module_path(test_module_path): + abs_path = resolve_js_test_module_path(test_module_path, tests_project_rootdir) + elif "/" in test_module_path or "\\" in test_module_path: abs_path = tests_project_rootdir / Path(test_module_path) else: - # Check for Jest test file extensions (e.g., tests.fibonacci.test.ts) - # These need special handling to avoid converting .test.ts -> /test/ts - jest_test_extensions = ( - ".test.ts", - ".test.js", - ".test.tsx", - ".test.jsx", - ".spec.ts", - ".spec.js", - ".spec.tsx", - ".spec.jsx", - ".ts", - ".js", - ".tsx", - ".jsx", - ".mjs", - ".mts", - ) - matched_ext = None - for ext in jest_test_extensions: - if test_module_path.endswith(ext): - matched_ext = ext - break - - if matched_ext: - # JavaScript/TypeScript: convert module-style path to file path - # "tests.fibonacci__perfonlyinstrumented.test.ts" -> "tests/fibonacci__perfonlyinstrumented.test.ts" - base_path = test_module_path[: -len(matched_ext)] - file_path = base_path.replace(".", os.sep) + matched_ext - # Check if the module path includes the tests directory name - tests_dir_name = tests_project_rootdir.name - if file_path.startswith((tests_dir_name + os.sep, tests_dir_name + "/")): - # Module path includes "tests." - use parent directory - abs_path = tests_project_rootdir.parent / Path(file_path) - else: - # Module path doesn't include tests dir - use tests root directly - abs_path = tests_project_rootdir / Path(file_path) - else: - # Python module name - convert dots to path separators and add .py - abs_path = tests_project_rootdir / Path(test_module_path.replace(".", os.sep)).with_suffix(".py") + abs_path = tests_project_rootdir / Path(test_module_path.replace(".", os.sep)).with_suffix(".py") abs_path_str = str(abs_path.resolve().with_suffix("")) # Include both unit test and perf test paths for runtime annotations @@ -329,109 +288,3 @@ def _compile_function_patterns(test_functions_to_remove: list[str]) -> list[re.P ) for func in test_functions_to_remove ] - - -# Patterns for normalizing codeflash imports (legacy -> npm package) -_CODEFLASH_REQUIRE_PATTERN = re.compile( - r"(const|let|var)\s+(\w+)\s*=\s*require\s*\(\s*['\"]\.?/?codeflash-jest-helper['\"]\s*\)" -) -_CODEFLASH_IMPORT_PATTERN = re.compile(r"import\s+(?:\*\s+as\s+)?(\w+)\s+from\s+['\"]\.?/?codeflash-jest-helper['\"]") - - -def normalize_codeflash_imports(source: str) -> str: - """Normalize codeflash imports to use the npm package. - - Replaces legacy local file imports: - const codeflash = require('./codeflash-jest-helper') - import codeflash from './codeflash-jest-helper' - - With npm package imports: - const codeflash = require('codeflash') - - Args: - source: JavaScript/TypeScript source code. - - Returns: - Source code with normalized imports. - - """ - # Replace CommonJS require - source = _CODEFLASH_REQUIRE_PATTERN.sub(r"\1 \2 = require('codeflash')", source) - # Replace ES module import - return _CODEFLASH_IMPORT_PATTERN.sub(r"import \1 from 'codeflash'", source) - - -def inject_test_globals(generated_tests: GeneratedTestsList, test_framework: str = "jest") -> GeneratedTestsList: - # TODO: inside the prompt tell the llm if it should import jest functions or it's already injected in the global window - """Inject test globals into all generated tests. - - Args: - generated_tests: List of generated tests. - test_framework: The test framework being used ("jest", "vitest", or "mocha"). - - Returns: - Generated tests with test globals injected. - - """ - # we only inject test globals for esm modules - # Use vitest imports for vitest projects, jest imports for jest projects - if test_framework == "vitest": - global_import = "import { vi, describe, it, expect, beforeEach, afterEach, beforeAll, test } from 'vitest'\n" - else: - # Default to jest imports for jest and other frameworks - global_import = ( - "import { jest, describe, it, expect, beforeEach, afterEach, beforeAll, test } from '@jest/globals'\n" - ) - - for test in generated_tests.generated_tests: - test.generated_original_test_source = global_import + test.generated_original_test_source - test.instrumented_behavior_test_source = global_import + test.instrumented_behavior_test_source - test.instrumented_perf_test_source = global_import + test.instrumented_perf_test_source - return generated_tests - - -def disable_ts_check(generated_tests: GeneratedTestsList) -> GeneratedTestsList: - """Disable TypeScript type checking in all generated tests. - - Args: - generated_tests: List of generated tests. - - Returns: - Generated tests with TypeScript type checking disabled. - - """ - # we only inject test globals for esm modules - ts_nocheck = "// @ts-nocheck\n" - - for test in generated_tests.generated_tests: - test.generated_original_test_source = ts_nocheck + test.generated_original_test_source - test.instrumented_behavior_test_source = ts_nocheck + test.instrumented_behavior_test_source - test.instrumented_perf_test_source = ts_nocheck + test.instrumented_perf_test_source - return generated_tests - - -def normalize_generated_tests_imports(generated_tests: GeneratedTestsList) -> GeneratedTestsList: - """Normalize codeflash imports in all generated tests. - - Args: - generated_tests: List of generated tests. - - Returns: - Generated tests with normalized imports. - - """ - normalized_tests = [] - for test in generated_tests.generated_tests: - # Only normalize JS/TS files - if test.behavior_file_path.suffix in (".js", ".ts", ".jsx", ".tsx", ".mjs", ".mts"): - normalized_test = GeneratedTests( - generated_original_test_source=normalize_codeflash_imports(test.generated_original_test_source), - instrumented_behavior_test_source=normalize_codeflash_imports(test.instrumented_behavior_test_source), - instrumented_perf_test_source=normalize_codeflash_imports(test.instrumented_perf_test_source), - behavior_file_path=test.behavior_file_path, - perf_file_path=test.perf_file_path, - ) - normalized_tests.append(normalized_test) - else: - normalized_tests.append(test) - return GeneratedTestsList(generated_tests=normalized_tests) diff --git a/codeflash/optimization/function_optimizer.py b/codeflash/optimization/function_optimizer.py index 0ba358c5b..cc6fa7781 100644 --- a/codeflash/optimization/function_optimizer.py +++ b/codeflash/optimization/function_optimizer.py @@ -64,6 +64,11 @@ from codeflash.languages import is_python from codeflash.languages.base import Language from codeflash.languages.current import current_language_support, is_typescript +from codeflash.languages.javascript.edit_tests import ( + disable_ts_check, + inject_test_globals, + normalize_generated_tests_imports, +) from codeflash.languages.javascript.module_system import detect_module_system from codeflash.languages.javascript.test_runner import clear_created_config_files, get_created_config_files from codeflash.languages.python.context import code_context_extractor @@ -79,9 +84,6 @@ ) from codeflash.languages.python.static_analysis.edit_generated_tests import ( add_runtime_comments_to_generated_tests, - disable_ts_check, - inject_test_globals, - normalize_generated_tests_imports, remove_functions_from_generated_tests, ) from codeflash.languages.python.static_analysis.line_profile_utils import add_decorator_imports, contains_jit_decorator From 1ceadcae108f640e545f1c222dd871cd53b4b169 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 05:49:29 -0500 Subject: [PATCH 089/100] Move JS code extraction/replacement helpers --- .../languages/javascript/code_replacer.py | 217 ++++++++++++++++++ codeflash/languages/javascript/treesitter.py | 36 +++ .../context/unused_definition_remover.py | 6 +- .../python/static_analysis/code_extractor.py | 41 +--- .../python/static_analysis/code_replacer.py | 167 +------------- 5 files changed, 264 insertions(+), 203 deletions(-) create mode 100644 codeflash/languages/javascript/code_replacer.py diff --git a/codeflash/languages/javascript/code_replacer.py b/codeflash/languages/javascript/code_replacer.py new file mode 100644 index 000000000..409e86c58 --- /dev/null +++ b/codeflash/languages/javascript/code_replacer.py @@ -0,0 +1,217 @@ +"""JavaScript/TypeScript code replacement helpers.""" + +from __future__ import annotations + +from pathlib import Path +from typing import TYPE_CHECKING + +from codeflash.cli_cmds.console import logger +from codeflash.languages.javascript.treesitter import get_analyzer_for_file + +if TYPE_CHECKING: + from codeflash.languages.base import Language + from codeflash.languages.javascript.treesitter import TreeSitterAnalyzer + + +# Author: ali +def _add_global_declarations_for_language( + optimized_code: str, original_source: str, module_abspath: Path, language: Language +) -> str: + """Add new global declarations from optimized code to original source. + + Finds module-level declarations (const, let, var, class, type, interface, enum) + in the optimized code that don't exist in the original source and adds them. + + New declarations are inserted after any existing declarations they depend on. + For example, if optimized code has `const _has = FOO.bar.bind(FOO)`, and `FOO` + is already declared in the original source, `_has` will be inserted after `FOO`. + + Args: + optimized_code: The optimized code that may contain new declarations. + original_source: The original source code. + module_abspath: Path to the module file (for parser selection). + language: The language of the code. + + Returns: + Original source with new declarations added in dependency order. + + """ + from codeflash.languages.base import Language + + if language not in (Language.JAVASCRIPT, Language.TYPESCRIPT): + return original_source + + try: + from codeflash.languages.javascript.treesitter import get_analyzer_for_file + + analyzer = get_analyzer_for_file(module_abspath) + + original_declarations = analyzer.find_module_level_declarations(original_source) + optimized_declarations = analyzer.find_module_level_declarations(optimized_code) + + if not optimized_declarations: + return original_source + + existing_names = _get_existing_names(original_declarations, analyzer, original_source) + new_declarations = _filter_new_declarations(optimized_declarations, existing_names) + + if not new_declarations: + return original_source + + # Build a map of existing declaration names to their end lines (1-indexed) + existing_decl_end_lines = {decl.name: decl.end_line for decl in original_declarations} + + # Insert each new declaration after its dependencies + result = original_source + for decl in new_declarations: + result = _insert_declaration_after_dependencies( + result, decl, existing_decl_end_lines, analyzer, module_abspath + ) + # Update the map with the newly inserted declaration for subsequent insertions + # Re-parse to get accurate line numbers after insertion + updated_declarations = analyzer.find_module_level_declarations(result) + existing_decl_end_lines = {d.name: d.end_line for d in updated_declarations} + + return result + + except Exception as e: + logger.debug(f"Error adding global declarations: {e}") + return original_source + + +# Author: ali +def _get_existing_names(original_declarations: list, analyzer: TreeSitterAnalyzer, original_source: str) -> set[str]: + """Get all names that already exist in the original source (declarations + imports).""" + existing_names = {decl.name for decl in original_declarations} + + original_imports = analyzer.find_imports(original_source) + for imp in original_imports: + if imp.default_import: + existing_names.add(imp.default_import) + for name, alias in imp.named_imports: + existing_names.add(alias if alias else name) + if imp.namespace_import: + existing_names.add(imp.namespace_import) + + return existing_names + + +# Author: ali +def _filter_new_declarations(optimized_declarations: list, existing_names: set[str]) -> list: + """Filter declarations to only those that don't exist in the original source.""" + new_declarations = [] + seen_sources: set[str] = set() + + # Sort by line number to maintain order from optimized code + sorted_declarations = sorted(optimized_declarations, key=lambda d: d.start_line) + + for decl in sorted_declarations: + if decl.name not in existing_names and decl.source_code not in seen_sources: + new_declarations.append(decl) + seen_sources.add(decl.source_code) + + return new_declarations + + +# Author: ali +def _insert_declaration_after_dependencies( + source: str, + declaration, + existing_decl_end_lines: dict[str, int], + analyzer: TreeSitterAnalyzer, + module_abspath: Path, +) -> str: + """Insert a declaration after the last existing declaration it depends on. + + Args: + source: Current source code. + declaration: The declaration to insert. + existing_decl_end_lines: Map of existing declaration names to their end lines. + analyzer: TreeSitter analyzer. + module_abspath: Path to the module file. + + Returns: + Source code with the declaration inserted at the correct position. + + """ + # Find identifiers referenced in this declaration + referenced_names = analyzer.find_referenced_identifiers(declaration.source_code) + + # Find the latest end line among all referenced declarations + insertion_line = _find_insertion_line_for_declaration(source, referenced_names, existing_decl_end_lines, analyzer) + + lines = source.splitlines(keepends=True) + + # Ensure proper spacing + decl_code = declaration.source_code + if not decl_code.endswith("\n"): + decl_code += "\n" + + # Add blank line before if inserting after content + if insertion_line > 0 and lines[insertion_line - 1].strip(): + decl_code = "\n" + decl_code + + before = lines[:insertion_line] + after = lines[insertion_line:] + + return "".join([*before, decl_code, *after]) + + +# Author: ali +def _find_insertion_line_for_declaration( + source: str, referenced_names: set[str], existing_decl_end_lines: dict[str, int], analyzer: TreeSitterAnalyzer +) -> int: + """Find the line where a declaration should be inserted based on its dependencies. + + Args: + source: Source code. + referenced_names: Names referenced by the declaration. + existing_decl_end_lines: Map of declaration names to their end lines (1-indexed). + analyzer: TreeSitter analyzer. + + Returns: + Line index (0-based) where the declaration should be inserted. + + """ + # Find the maximum end line among referenced declarations + max_dependency_line = 0 + for name in referenced_names: + if name in existing_decl_end_lines: + max_dependency_line = max(max_dependency_line, existing_decl_end_lines[name]) + + if max_dependency_line > 0: + # Insert after the last dependency (end_line is 1-indexed, we need 0-indexed) + return max_dependency_line + + # No dependencies found - insert after imports + lines = source.splitlines(keepends=True) + return _find_line_after_imports(lines, analyzer, source) + + +# Author: ali +def _find_line_after_imports(lines: list[str], analyzer: TreeSitterAnalyzer, source: str) -> int: + """Find the line index after all imports. + + Args: + lines: Source lines. + analyzer: TreeSitter analyzer. + source: Full source code. + + Returns: + Line index (0-based) for insertion after imports. + + """ + try: + imports = analyzer.find_imports(source) + if imports: + return max(imp.end_line for imp in imports) + except Exception as exc: + logger.debug(f"Exception in _find_line_after_imports: {exc}") + + # Default: insert at beginning (after shebang/directive comments) + for i, line in enumerate(lines): + stripped = line.strip() + if stripped and not stripped.startswith("//") and not stripped.startswith("#!"): + return i + + return 0 diff --git a/codeflash/languages/javascript/treesitter.py b/codeflash/languages/javascript/treesitter.py index 32d2431ac..c00cb228e 100644 --- a/codeflash/languages/javascript/treesitter.py +++ b/codeflash/languages/javascript/treesitter.py @@ -1788,3 +1788,39 @@ def get_analyzer_for_file(file_path: Path) -> TreeSitterAnalyzer: return TreeSitterAnalyzer(TreeSitterLanguage.TSX) # Default to JavaScript for .js, .jsx, .mjs, .cjs return TreeSitterAnalyzer(TreeSitterLanguage.JAVASCRIPT) + + +# Author: Saurabh Misra +def extract_calling_function_source(source_code: str, function_name: str, ref_line: int) -> str | None: + """Extract the source code of a calling function in JavaScript/TypeScript. + + Args: + source_code: Full source code of the file. + function_name: Name of the function to extract. + ref_line: Line number where the reference is (helps identify the right function). + + Returns: + Source code of the function, or None if not found. + + """ + try: + from codeflash.languages.javascript.treesitter import TreeSitterAnalyzer, TreeSitterLanguage + + # Try TypeScript first, fall back to JavaScript + for lang in [TreeSitterLanguage.TYPESCRIPT, TreeSitterLanguage.TSX, TreeSitterLanguage.JAVASCRIPT]: + try: + analyzer = TreeSitterAnalyzer(lang) + functions = analyzer.find_functions(source_code, include_methods=True) + + for func in functions: + if func.name == function_name: + # Check if the reference line is within this function + if func.start_line <= ref_line <= func.end_line: + return func.source_text + break + except Exception: + continue + + return None + except Exception: + return None diff --git a/codeflash/languages/python/context/unused_definition_remover.py b/codeflash/languages/python/context/unused_definition_remover.py index 669f540bf..e70dcad29 100644 --- a/codeflash/languages/python/context/unused_definition_remover.py +++ b/codeflash/languages/python/context/unused_definition_remover.py @@ -10,7 +10,7 @@ import libcst as cst from codeflash.cli_cmds.console import logger -from codeflash.languages import is_javascript +from codeflash.languages import is_python from codeflash.languages.python.static_analysis.code_replacer import replace_function_definitions_in_module from codeflash.models.models import CodeString, CodeStringsMarkdown @@ -747,8 +747,8 @@ def detect_unused_helper_functions( """ # Skip this analysis for non-Python languages since we use Python's ast module - if is_javascript(): - logger.debug("Skipping unused helper function detection for JavaScript/TypeScript") + if not is_python(): + logger.debug("Skipping unused helper function detection for non-Python languages") return [] if isinstance(optimized_code, CodeStringsMarkdown) and len(optimized_code.code_strings) > 0: diff --git a/codeflash/languages/python/static_analysis/code_extractor.py b/codeflash/languages/python/static_analysis/code_extractor.py index c4434c3ae..d7c2eed0f 100644 --- a/codeflash/languages/python/static_analysis/code_extractor.py +++ b/codeflash/languages/python/static_analysis/code_extractor.py @@ -1735,7 +1735,12 @@ def _extract_calling_function(source_code: str, function_name: str, ref_line: in """ if language == Language.PYTHON: return _extract_calling_function_python(source_code, function_name, ref_line) - return _extract_calling_function_js(source_code, function_name, ref_line) + try: + from codeflash.languages.javascript.treesitter import extract_calling_function_source + + return extract_calling_function_source(source_code, function_name, ref_line) + except Exception: + return None def _extract_calling_function_python(source_code: str, function_name: str, ref_line: int) -> str | None: @@ -1758,37 +1763,3 @@ def _extract_calling_function_python(source_code: str, function_name: str, ref_l except Exception: return None - -def _extract_calling_function_js(source_code: str, function_name: str, ref_line: int) -> str | None: - """Extract the source code of a calling function in JavaScript/TypeScript. - - Args: - source_code: Full source code of the file. - function_name: Name of the function to extract. - ref_line: Line number where the reference is (helps identify the right function). - - Returns: - Source code of the function, or None if not found. - - """ - try: - from codeflash.languages.javascript.treesitter import TreeSitterAnalyzer, TreeSitterLanguage - - # Try TypeScript first, fall back to JavaScript - for lang in [TreeSitterLanguage.TYPESCRIPT, TreeSitterLanguage.TSX, TreeSitterLanguage.JAVASCRIPT]: - try: - analyzer = TreeSitterAnalyzer(lang) - functions = analyzer.find_functions(source_code, include_methods=True) - - for func in functions: - if func.name == function_name: - # Check if the reference line is within this function - if func.start_line <= ref_line <= func.end_line: - return func.source_text - break - except Exception: - continue - - return None - except Exception: - return None diff --git a/codeflash/languages/python/static_analysis/code_replacer.py b/codeflash/languages/python/static_analysis/code_replacer.py index ebd66c8d5..209d20ec4 100644 --- a/codeflash/languages/python/static_analysis/code_replacer.py +++ b/codeflash/languages/python/static_analysis/code_replacer.py @@ -26,7 +26,6 @@ from codeflash.discovery.functions_to_optimize import FunctionToOptimize from codeflash.languages.base import Language, LanguageSupport - from codeflash.languages.javascript.treesitter import TreeSitterAnalyzer from codeflash.models.models import CodeOptimizationContext, CodeStringsMarkdown, OptimizedCandidate, ValidCode ASTNodeT = TypeVar("ASTNodeT", bound=ast.AST) @@ -727,176 +726,14 @@ def _add_global_declarations_for_language( return original_source try: - from codeflash.languages.javascript.treesitter import get_analyzer_for_file - - analyzer = get_analyzer_for_file(module_abspath) - - original_declarations = analyzer.find_module_level_declarations(original_source) - optimized_declarations = analyzer.find_module_level_declarations(optimized_code) - - if not optimized_declarations: - return original_source - - existing_names = _get_existing_names(original_declarations, analyzer, original_source) - new_declarations = _filter_new_declarations(optimized_declarations, existing_names) - - if not new_declarations: - return original_source - - # Build a map of existing declaration names to their end lines (1-indexed) - existing_decl_end_lines = {decl.name: decl.end_line for decl in original_declarations} - - # Insert each new declaration after its dependencies - result = original_source - for decl in new_declarations: - result = _insert_declaration_after_dependencies( - result, decl, existing_decl_end_lines, analyzer, module_abspath - ) - # Update the map with the newly inserted declaration for subsequent insertions - # Re-parse to get accurate line numbers after insertion - updated_declarations = analyzer.find_module_level_declarations(result) - existing_decl_end_lines = {d.name: d.end_line for d in updated_declarations} - - return result + from codeflash.languages.javascript.code_replacer import _add_global_declarations_for_language + return _add_global_declarations_for_language(optimized_code, original_source, module_abspath, language) except Exception as e: logger.debug(f"Error adding global declarations: {e}") return original_source -def _get_existing_names(original_declarations: list, analyzer: TreeSitterAnalyzer, original_source: str) -> set[str]: - """Get all names that already exist in the original source (declarations + imports).""" - existing_names = {decl.name for decl in original_declarations} - - original_imports = analyzer.find_imports(original_source) - for imp in original_imports: - if imp.default_import: - existing_names.add(imp.default_import) - for name, alias in imp.named_imports: - existing_names.add(alias if alias else name) - if imp.namespace_import: - existing_names.add(imp.namespace_import) - - return existing_names - - -def _filter_new_declarations(optimized_declarations: list, existing_names: set[str]) -> list: - """Filter declarations to only those that don't exist in the original source.""" - new_declarations = [] - seen_sources: set[str] = set() - - # Sort by line number to maintain order from optimized code - sorted_declarations = sorted(optimized_declarations, key=lambda d: d.start_line) - - for decl in sorted_declarations: - if decl.name not in existing_names and decl.source_code not in seen_sources: - new_declarations.append(decl) - seen_sources.add(decl.source_code) - - return new_declarations - - -def _insert_declaration_after_dependencies( - source: str, - declaration, - existing_decl_end_lines: dict[str, int], - analyzer: TreeSitterAnalyzer, - module_abspath: Path, -) -> str: - """Insert a declaration after the last existing declaration it depends on. - - Args: - source: Current source code. - declaration: The declaration to insert. - existing_decl_end_lines: Map of existing declaration names to their end lines. - analyzer: TreeSitter analyzer. - module_abspath: Path to the module file. - - Returns: - Source code with the declaration inserted at the correct position. - - """ - # Find identifiers referenced in this declaration - referenced_names = analyzer.find_referenced_identifiers(declaration.source_code) - - # Find the latest end line among all referenced declarations - insertion_line = _find_insertion_line_for_declaration(source, referenced_names, existing_decl_end_lines, analyzer) - - lines = source.splitlines(keepends=True) - - # Ensure proper spacing - decl_code = declaration.source_code - if not decl_code.endswith("\n"): - decl_code += "\n" - - # Add blank line before if inserting after content - if insertion_line > 0 and lines[insertion_line - 1].strip(): - decl_code = "\n" + decl_code - - before = lines[:insertion_line] - after = lines[insertion_line:] - - return "".join([*before, decl_code, *after]) - - -def _find_insertion_line_for_declaration( - source: str, referenced_names: set[str], existing_decl_end_lines: dict[str, int], analyzer: TreeSitterAnalyzer -) -> int: - """Find the line where a declaration should be inserted based on its dependencies. - - Args: - source: Source code. - referenced_names: Names referenced by the declaration. - existing_decl_end_lines: Map of declaration names to their end lines (1-indexed). - analyzer: TreeSitter analyzer. - - Returns: - Line index (0-based) where the declaration should be inserted. - - """ - # Find the maximum end line among referenced declarations - max_dependency_line = 0 - for name in referenced_names: - if name in existing_decl_end_lines: - max_dependency_line = max(max_dependency_line, existing_decl_end_lines[name]) - - if max_dependency_line > 0: - # Insert after the last dependency (end_line is 1-indexed, we need 0-indexed) - return max_dependency_line - - # No dependencies found - insert after imports - lines = source.splitlines(keepends=True) - return _find_line_after_imports(lines, analyzer, source) - - -def _find_line_after_imports(lines: list[str], analyzer: TreeSitterAnalyzer, source: str) -> int: - """Find the line index after all imports. - - Args: - lines: Source lines. - analyzer: TreeSitter analyzer. - source: Full source code. - - Returns: - Line index (0-based) for insertion after imports. - - """ - try: - imports = analyzer.find_imports(source) - if imports: - return max(imp.end_line for imp in imports) - except Exception as exc: - logger.debug(f"Exception in _find_line_after_imports: {exc}") - - # Default: insert at beginning (after shebang/directive comments) - for i, line in enumerate(lines): - stripped = line.strip() - if stripped and not stripped.startswith("//") and not stripped.startswith("#!"): - return i - - return 0 - - def get_optimized_code_for_module(relative_path: Path, optimized_code: CodeStringsMarkdown) -> str: file_to_code_context = optimized_code.file_to_path() module_optimized_code = file_to_code_context.get(str(relative_path)) From 4fbe5a1d9215d161dd8fb6ac617835760dea33b3 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 10:53:49 +0000 Subject: [PATCH 090/100] style: auto-fix linting issues --- codeflash/languages/javascript/code_replacer.py | 4 ++-- .../languages/python/static_analysis/edit_generated_tests.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/codeflash/languages/javascript/code_replacer.py b/codeflash/languages/javascript/code_replacer.py index 409e86c58..83c96ec6a 100644 --- a/codeflash/languages/javascript/code_replacer.py +++ b/codeflash/languages/javascript/code_replacer.py @@ -2,13 +2,13 @@ from __future__ import annotations -from pathlib import Path from typing import TYPE_CHECKING from codeflash.cli_cmds.console import logger -from codeflash.languages.javascript.treesitter import get_analyzer_for_file if TYPE_CHECKING: + from pathlib import Path + from codeflash.languages.base import Language from codeflash.languages.javascript.treesitter import TreeSitterAnalyzer diff --git a/codeflash/languages/python/static_analysis/edit_generated_tests.py b/codeflash/languages/python/static_analysis/edit_generated_tests.py index b5c3b5454..9a1efe2cd 100644 --- a/codeflash/languages/python/static_analysis/edit_generated_tests.py +++ b/codeflash/languages/python/static_analysis/edit_generated_tests.py @@ -1,6 +1,7 @@ from __future__ import annotations import ast +import os import re from pathlib import Path from typing import TYPE_CHECKING, Optional From 4dde695f756c5bb20b1d96165717cad72f88ba2b Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 10:54:16 +0000 Subject: [PATCH 091/100] style: fix trailing newline formatting --- codeflash/languages/python/static_analysis/code_extractor.py | 1 - 1 file changed, 1 deletion(-) diff --git a/codeflash/languages/python/static_analysis/code_extractor.py b/codeflash/languages/python/static_analysis/code_extractor.py index d7c2eed0f..69ec38353 100644 --- a/codeflash/languages/python/static_analysis/code_extractor.py +++ b/codeflash/languages/python/static_analysis/code_extractor.py @@ -1762,4 +1762,3 @@ def _extract_calling_function_python(source_code: str, function_name: str, ref_l return None except Exception: return None - From 936ed7e82c3b76b231b676580ef6c7b17363e7e4 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 06:28:47 -0500 Subject: [PATCH 092/100] Fix init replacement when class not preexisting --- codeflash/languages/python/static_analysis/code_replacer.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/codeflash/languages/python/static_analysis/code_replacer.py b/codeflash/languages/python/static_analysis/code_replacer.py index 209d20ec4..8e86ccbc4 100644 --- a/codeflash/languages/python/static_analysis/code_replacer.py +++ b/codeflash/languages/python/static_analysis/code_replacer.py @@ -430,7 +430,11 @@ def replace_functions_in_file( method_key = (class_name, child.name.value) if method_key in function_names_set: modified_functions[method_key] = child - elif child.name.value == "__init__" and preexisting_objects: + elif ( + child.name.value == "__init__" + and preexisting_objects + and (class_name, ()) in preexisting_objects + ): modified_init_functions[class_name] = child elif preexisting_objects and (child.name.value, parents) not in preexisting_objects: new_class_functions[class_name].append(child) From f4b904066c684f94adaf769e3484f0f9f7bead70 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 07:12:02 -0500 Subject: [PATCH 093/100] Add language support hooks for test postprocessing --- codeflash/languages/base.py | 86 ++++++++++++++++ codeflash/languages/javascript/support.py | 113 ++++++++++++++++++++++ codeflash/languages/python/support.py | 55 ++++++++++- 3 files changed, 253 insertions(+), 1 deletion(-) diff --git a/codeflash/languages/base.py b/codeflash/languages/base.py index 8542547a4..e1612d62d 100644 --- a/codeflash/languages/base.py +++ b/codeflash/languages/base.py @@ -15,6 +15,7 @@ from pathlib import Path from codeflash.discovery.functions_to_optimize import FunctionToOptimize + from codeflash.models.models import GeneratedTestsList, InvocationId from codeflash.models.models import FunctionSource from codeflash.languages.language_enum import Language @@ -538,6 +539,91 @@ def remove_test_functions(self, test_source: str, functions_to_remove: list[str] """ ... + def postprocess_generated_tests( + self, + generated_tests: GeneratedTestsList, + test_framework: str, + project_root: Path, + source_file_path: Path, + ) -> GeneratedTestsList: + """Apply language-specific postprocessing to generated tests. + + Args: + generated_tests: Generated tests to update. + test_framework: Test framework used for the project. + project_root: Project root directory. + source_file_path: Path to the source file under optimization. + + Returns: + Updated generated tests. + + """ + ... + + def remove_test_functions_from_generated_tests( + self, generated_tests: GeneratedTestsList, functions_to_remove: list[str] + ) -> GeneratedTestsList: + """Remove specific test functions from generated tests. + + Args: + generated_tests: Generated tests to update. + functions_to_remove: List of function names to remove. + + Returns: + Updated generated tests. + + """ + ... + + def add_runtime_comments_to_generated_tests( + self, + generated_tests: GeneratedTestsList, + original_runtimes: dict[InvocationId, list[int]], + optimized_runtimes: dict[InvocationId, list[int]], + tests_project_rootdir: Path | None = None, + ) -> GeneratedTestsList: + """Add runtime comments to generated tests. + + Args: + generated_tests: Generated tests to update. + original_runtimes: Mapping of invocation IDs to original runtimes. + optimized_runtimes: Mapping of invocation IDs to optimized runtimes. + tests_project_rootdir: Root directory for tests (if applicable). + + Returns: + Updated generated tests. + + """ + ... + + def add_global_declarations(self, optimized_code: str, original_source: str, module_abspath: Path) -> str: + """Add new global declarations from optimized code to original source. + + Args: + optimized_code: The optimized code that may contain new declarations. + original_source: The original source code. + module_abspath: Path to the module file (for parser selection). + + Returns: + Original source with new declarations added. + + """ + ... + + def extract_calling_function_source(self, source_code: str, function_name: str, ref_line: int) -> str | None: + """Extract the source code of a calling function. + + Args: + source_code: Full source code of the file. + function_name: Name of the function to extract. + ref_line: Line number where the reference is. + + Returns: + Source code of the function, or None if not found. + + """ + ... + # === Test Result Comparison === def compare_test_results( diff --git a/codeflash/languages/javascript/support.py b/codeflash/languages/javascript/support.py index cde098cab..e7f40025d 100644 --- a/codeflash/languages/javascript/support.py +++ b/codeflash/languages/javascript/support.py @@ -23,6 +23,7 @@ from codeflash.languages.base import ReferenceInfo from codeflash.languages.javascript.treesitter import TypeDefinition + from codeflash.models.models import GeneratedTestsList, InvocationId logger = logging.getLogger(__name__) @@ -1778,6 +1779,118 @@ def remove_test_functions(self, test_source: str, functions_to_remove: list[str] return remove_test_functions(test_source, functions_to_remove) + def postprocess_generated_tests( + self, + generated_tests: GeneratedTestsList, + test_framework: str, + project_root: Path, + source_file_path: Path, + ) -> GeneratedTestsList: + """Apply language-specific postprocessing to generated tests.""" + from codeflash.languages.javascript.edit_tests import ( + disable_ts_check, + inject_test_globals, + normalize_generated_tests_imports, + ) + from codeflash.languages.javascript.module_system import detect_module_system + + module_system = detect_module_system(project_root, source_file_path) + if module_system == "esm": + generated_tests = inject_test_globals(generated_tests, test_framework) + if self.language == Language.TYPESCRIPT: + generated_tests = disable_ts_check(generated_tests) + return normalize_generated_tests_imports(generated_tests) + + def remove_test_functions_from_generated_tests( + self, generated_tests: GeneratedTestsList, functions_to_remove: list[str] + ) -> GeneratedTestsList: + """Remove specific test functions from generated tests.""" + from codeflash.models.models import GeneratedTests, GeneratedTestsList + + updated_tests: list[GeneratedTests] = [] + for test in generated_tests.generated_tests: + updated_tests.append( + GeneratedTests( + generated_original_test_source=self.remove_test_functions( + test.generated_original_test_source, functions_to_remove + ), + instrumented_behavior_test_source=test.instrumented_behavior_test_source, + instrumented_perf_test_source=test.instrumented_perf_test_source, + behavior_file_path=test.behavior_file_path, + perf_file_path=test.perf_file_path, + ) + ) + return GeneratedTestsList(generated_tests=updated_tests) + + def add_runtime_comments_to_generated_tests( + self, + generated_tests: GeneratedTestsList, + original_runtimes: dict[InvocationId, list[int]], + optimized_runtimes: dict[InvocationId, list[int]], + tests_project_rootdir: Path | None = None, + ) -> GeneratedTestsList: + """Add runtime comments to generated tests.""" + from codeflash.models.models import GeneratedTests, GeneratedTestsList + + tests_root = tests_project_rootdir or Path() + original_runtimes_dict = self._build_runtime_map(original_runtimes, tests_root) + optimized_runtimes_dict = self._build_runtime_map(optimized_runtimes, tests_root) + + modified_tests: list[GeneratedTests] = [] + for test in generated_tests.generated_tests: + modified_source = self.add_runtime_comments( + test.generated_original_test_source, original_runtimes_dict, optimized_runtimes_dict + ) + modified_tests.append( + GeneratedTests( + generated_original_test_source=modified_source, + instrumented_behavior_test_source=test.instrumented_behavior_test_source, + instrumented_perf_test_source=test.instrumented_perf_test_source, + behavior_file_path=test.behavior_file_path, + perf_file_path=test.perf_file_path, + ) + ) + return GeneratedTestsList(generated_tests=modified_tests) + + def add_global_declarations(self, optimized_code: str, original_source: str, module_abspath: Path) -> str: + from codeflash.languages.javascript.code_replacer import _add_global_declarations_for_language + + return _add_global_declarations_for_language(optimized_code, original_source, module_abspath, self.language) + + def extract_calling_function_source(self, source_code: str, function_name: str, ref_line: int) -> str | None: + from codeflash.languages.javascript.treesitter import extract_calling_function_source + + return extract_calling_function_source(source_code, function_name, ref_line) + + def _build_runtime_map( + self, inv_id_runtimes: dict[InvocationId, list[int]], tests_project_rootdir: Path + ) -> dict[str, int]: + from codeflash.languages.javascript.edit_tests import resolve_js_test_module_path + + unique_inv_ids: dict[str, int] = {} + for inv_id, runtimes in inv_id_runtimes.items(): + test_qualified_name = ( + inv_id.test_class_name + "." + inv_id.test_function_name # type: ignore[operator] + if inv_id.test_class_name + else inv_id.test_function_name + ) + if not test_qualified_name: + continue + abs_path = resolve_js_test_module_path(inv_id.test_module_path, tests_project_rootdir) + + abs_path_str = str(abs_path.resolve().with_suffix("")) + if "__unit_test_" not in abs_path_str and "__perf_test_" not in abs_path_str: + continue + + key = test_qualified_name + "#" + abs_path_str + parts = inv_id.iteration_id.split("_").__len__() # type: ignore[union-attr] + cur_invid = inv_id.iteration_id.split("_")[0] if parts < 3 else "_".join(inv_id.iteration_id.split("_")[:-1]) # type: ignore[union-attr] + match_key = key + "#" + cur_invid + if match_key not in unique_inv_ids: + unique_inv_ids[match_key] = 0 + unique_inv_ids[match_key] += min(runtimes) + return unique_inv_ids + # === Test Result Comparison === def compare_test_results( diff --git a/codeflash/languages/python/support.py b/codeflash/languages/python/support.py index 7eb52575b..61ec5f46e 100644 --- a/codeflash/languages/python/support.py +++ b/codeflash/languages/python/support.py @@ -22,7 +22,7 @@ from collections.abc import Sequence from codeflash.languages.base import DependencyResolver - from codeflash.models.models import FunctionSource + from codeflash.models.models import FunctionSource, GeneratedTestsList, InvocationId logger = logging.getLogger(__name__) @@ -657,6 +657,59 @@ def leave_FunctionDef( except Exception: return test_source + def postprocess_generated_tests( + self, + generated_tests: GeneratedTestsList, + test_framework: str, + project_root: Path, + source_file_path: Path, + ) -> GeneratedTestsList: + """Apply language-specific postprocessing to generated tests.""" + _ = test_framework, project_root, source_file_path + return generated_tests + + def remove_test_functions_from_generated_tests( + self, generated_tests: GeneratedTestsList, functions_to_remove: list[str] + ) -> GeneratedTestsList: + """Remove specific test functions from generated tests.""" + from codeflash.languages.python.static_analysis.edit_generated_tests import remove_functions_from_generated_tests + + return remove_functions_from_generated_tests(generated_tests, functions_to_remove) + + def add_runtime_comments_to_generated_tests( + self, + generated_tests: GeneratedTestsList, + original_runtimes: dict[InvocationId, list[int]], + optimized_runtimes: dict[InvocationId, list[int]], + tests_project_rootdir: Path | None = None, + ) -> GeneratedTestsList: + """Add runtime comments to generated tests.""" + from codeflash.languages.python.static_analysis.edit_generated_tests import add_runtime_comments_to_generated_tests + + return add_runtime_comments_to_generated_tests( + generated_tests, original_runtimes, optimized_runtimes, tests_project_rootdir + ) + + def add_global_declarations(self, optimized_code: str, original_source: str, module_abspath: Path) -> str: + _ = optimized_code, module_abspath + return original_source + + def extract_calling_function_source(self, source_code: str, function_name: str, ref_line: int) -> str | None: + """Extract the source code of a calling function in Python.""" + try: + import ast + + lines = source_code.splitlines() + tree = ast.parse(source_code) + for node in ast.walk(tree): + if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)) and node.name == function_name: + end_line = node.end_lineno or node.lineno + if node.lineno <= ref_line <= end_line: + return "\n".join(lines[node.lineno - 1 : end_line]) + except Exception: + return None + return None + # === Test Result Comparison === def compare_test_results( From 0bbf220e0dcac37fc510dc3761212c6984331b0f Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 07:13:33 -0500 Subject: [PATCH 094/100] Route generated test handling through language support --- codeflash/optimization/function_optimizer.py | 40 ++++++++------------ 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/codeflash/optimization/function_optimizer.py b/codeflash/optimization/function_optimizer.py index cc6fa7781..eece4795d 100644 --- a/codeflash/optimization/function_optimizer.py +++ b/codeflash/optimization/function_optimizer.py @@ -63,13 +63,7 @@ from codeflash.either import Failure, Success, is_successful from codeflash.languages import is_python from codeflash.languages.base import Language -from codeflash.languages.current import current_language_support, is_typescript -from codeflash.languages.javascript.edit_tests import ( - disable_ts_check, - inject_test_globals, - normalize_generated_tests_imports, -) -from codeflash.languages.javascript.module_system import detect_module_system +from codeflash.languages.current import current_language_support from codeflash.languages.javascript.test_runner import clear_created_config_files, get_created_config_files from codeflash.languages.python.context import code_context_extractor from codeflash.languages.python.context.unused_definition_remover import ( @@ -82,10 +76,6 @@ modify_autouse_fixture, replace_function_definitions_in_module, ) -from codeflash.languages.python.static_analysis.edit_generated_tests import ( - add_runtime_comments_to_generated_tests, - remove_functions_from_generated_tests, -) from codeflash.languages.python.static_analysis.line_profile_utils import add_decorator_imports, contains_jit_decorator from codeflash.languages.python.static_analysis.static_analysis import get_first_top_level_function_or_method_ast from codeflash.lsp.helpers import is_LSP_enabled, report_to_markdown_table, tree_to_markdown @@ -598,16 +588,13 @@ def generate_and_instrument_tests( count_tests, generated_tests, function_to_concolic_tests, concolic_test_str = test_results.unwrap() - # Normalize codeflash imports in JS/TS tests to use npm package - if not is_python(): - module_system = detect_module_system(self.project_root, self.function_to_optimize.file_path) - if module_system == "esm": - generated_tests = inject_test_globals(generated_tests, self.test_cfg.test_framework) - if is_typescript(): - # disable ts check for typescript tests - generated_tests = disable_ts_check(generated_tests) - - generated_tests = normalize_generated_tests_imports(generated_tests) + # Language-specific postprocessing for generated tests + generated_tests = self.language_support.postprocess_generated_tests( + generated_tests, + test_framework=self.test_cfg.test_framework, + project_root=self.project_root, + source_file_path=self.function_to_optimize.file_path, + ) logger.debug(f"[PIPELINE] Processing {count_tests} generated tests") for i, generated_test in enumerate(generated_tests.generated_tests): @@ -2069,8 +2056,8 @@ def process_review( else "Coverage data not available" ) - generated_tests = remove_functions_from_generated_tests( - generated_tests=generated_tests, test_functions_to_remove=test_functions_to_remove + generated_tests = self.language_support.remove_test_functions_from_generated_tests( + generated_tests, test_functions_to_remove ) map_gen_test_file_to_no_of_tests = original_code_baseline.behavior_test_results.file_to_no_of_tests( test_functions_to_remove @@ -2081,8 +2068,11 @@ def process_review( best_optimization.winning_benchmarking_test_results.usable_runtime_data_by_test_case() ) - generated_tests = add_runtime_comments_to_generated_tests( - generated_tests, original_runtime_by_test, optimized_runtime_by_test, self.test_cfg.tests_project_rootdir + generated_tests = self.language_support.add_runtime_comments_to_generated_tests( + generated_tests, + original_runtime_by_test, + optimized_runtime_by_test, + self.test_cfg.tests_project_rootdir, ) generated_tests_str = "" From 77304360ba550517604dff9956b1b2f815f8f77f Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 07:14:23 -0500 Subject: [PATCH 095/100] Use language support to extract calling function context --- .../python/static_analysis/code_extractor.py | 56 ++++--------------- 1 file changed, 12 insertions(+), 44 deletions(-) diff --git a/codeflash/languages/python/static_analysis/code_extractor.py b/codeflash/languages/python/static_analysis/code_extractor.py index 69ec38353..eb6de3a4e 100644 --- a/codeflash/languages/python/static_analysis/code_extractor.py +++ b/codeflash/languages/python/static_analysis/code_extractor.py @@ -1659,6 +1659,13 @@ def _format_references_as_markdown(references: list, file_path: Path, project_ro refs_by_file[ref.file_path] = [] refs_by_file[ref.file_path].append(ref) + from codeflash.languages.registry import get_language_support + + try: + lang_support = get_language_support(language) + except Exception: + lang_support = None + fn_call_context = "" context_len = 0 @@ -1700,7 +1707,11 @@ def _format_references_as_markdown(references: list, file_path: Path, project_ro # Extract context around the reference if ref.caller_function: # Try to extract the full calling function - func_code = _extract_calling_function(file_content, ref.caller_function, ref.line, language) + func_code = None + if lang_support is not None: + func_code = lang_support.extract_calling_function_source( + file_content, ref.caller_function, ref.line + ) if func_code: caller_contexts.append(func_code) context_len += len(func_code) @@ -1719,46 +1730,3 @@ def _format_references_as_markdown(references: list, file_path: Path, project_ro return fn_call_context - -def _extract_calling_function(source_code: str, function_name: str, ref_line: int, language: Language) -> str | None: - """Extract the source code of a calling function. - - Args: - source_code: Full source code of the file. - function_name: Name of the function to extract. - ref_line: Line number where the reference is. - language: The programming language. - - Returns: - Source code of the function, or None if not found. - - """ - if language == Language.PYTHON: - return _extract_calling_function_python(source_code, function_name, ref_line) - try: - from codeflash.languages.javascript.treesitter import extract_calling_function_source - - return extract_calling_function_source(source_code, function_name, ref_line) - except Exception: - return None - - -def _extract_calling_function_python(source_code: str, function_name: str, ref_line: int) -> str | None: - """Extract the source code of a calling function in Python.""" - try: - import ast - - tree = ast.parse(source_code) - lines = source_code.splitlines() - - for node in ast.walk(tree): - if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)): - if node.name == function_name: - # Check if the reference line is within this function - start_line = node.lineno - end_line = node.end_lineno or start_line - if start_line <= ref_line <= end_line: - return "\n".join(lines[start_line - 1 : end_line]) - return None - except Exception: - return None From 919b2b2281395bffda19fc9f8d3a028ab2889149 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 07:15:00 -0500 Subject: [PATCH 096/100] Delegate global declaration insertion to language support --- .../python/static_analysis/code_replacer.py | 39 +------------------ 1 file changed, 1 insertion(+), 38 deletions(-) diff --git a/codeflash/languages/python/static_analysis/code_replacer.py b/codeflash/languages/python/static_analysis/code_replacer.py index 8e86ccbc4..d4d26e6dd 100644 --- a/codeflash/languages/python/static_analysis/code_replacer.py +++ b/codeflash/languages/python/static_analysis/code_replacer.py @@ -599,11 +599,10 @@ def replace_function_definitions_for_language( lang_support = get_language_support(language) # Add any new global declarations from the optimized code to the original source - original_source_code = _add_global_declarations_for_language( + original_source_code = lang_support.add_global_declarations( optimized_code=code_to_apply, original_source=original_source_code, module_abspath=module_abspath, - language=language, ) # If we have function_to_optimize with line info and this is the main file, use it for precise replacement @@ -702,42 +701,6 @@ def _extract_function_from_code( return None -def _add_global_declarations_for_language( - optimized_code: str, original_source: str, module_abspath: Path, language: Language -) -> str: - """Add new global declarations from optimized code to original source. - - Finds module-level declarations (const, let, var, class, type, interface, enum) - in the optimized code that don't exist in the original source and adds them. - - New declarations are inserted after any existing declarations they depend on. - For example, if optimized code has `const _has = FOO.bar.bind(FOO)`, and `FOO` - is already declared in the original source, `_has` will be inserted after `FOO`. - - Args: - optimized_code: The optimized code that may contain new declarations. - original_source: The original source code. - module_abspath: Path to the module file (for parser selection). - language: The language of the code. - - Returns: - Original source with new declarations added in dependency order. - - """ - from codeflash.languages.base import Language - - if language not in (Language.JAVASCRIPT, Language.TYPESCRIPT): - return original_source - - try: - from codeflash.languages.javascript.code_replacer import _add_global_declarations_for_language - - return _add_global_declarations_for_language(optimized_code, original_source, module_abspath, language) - except Exception as e: - logger.debug(f"Error adding global declarations: {e}") - return original_source - - def get_optimized_code_for_module(relative_path: Path, optimized_code: CodeStringsMarkdown) -> str: file_to_code_context = optimized_code.file_to_path() module_optimized_code = file_to_code_context.get(str(relative_path)) From 95d4f10b954ea85c5f26f32d5312977022882fb5 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 07:15:40 -0500 Subject: [PATCH 097/100] Keep Python generated test editing Python-only --- .../static_analysis/edit_generated_tests.py | 23 ++----------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/codeflash/languages/python/static_analysis/edit_generated_tests.py b/codeflash/languages/python/static_analysis/edit_generated_tests.py index 9a1efe2cd..c4aed07de 100644 --- a/codeflash/languages/python/static_analysis/edit_generated_tests.py +++ b/codeflash/languages/python/static_analysis/edit_generated_tests.py @@ -12,8 +12,6 @@ from codeflash.cli_cmds.console import logger from codeflash.code_utils.time_utils import format_perf, format_time -from codeflash.languages.javascript.edit_tests import is_js_test_module_path, resolve_js_test_module_path -from codeflash.languages.registry import get_language_support from codeflash.models.models import GeneratedTests, GeneratedTestsList from codeflash.result.critic import performance_gain @@ -167,9 +165,7 @@ def unique_inv_id(inv_id_runtimes: dict[InvocationId, list[int]], tests_project_ ) test_module_path = inv_id.test_module_path - if is_js_test_module_path(test_module_path): - abs_path = resolve_js_test_module_path(test_module_path, tests_project_rootdir) - elif "/" in test_module_path or "\\" in test_module_path: + if "/" in test_module_path or "\\" in test_module_path: abs_path = tests_project_rootdir / Path(test_module_path) else: abs_path = tests_project_rootdir / Path(test_module_path.replace(".", os.sep)).with_suffix(".py") @@ -228,22 +224,7 @@ def add_runtime_comments_to_generated_tests( logger.debug(f"Failed to add runtime comments to test: {e}") modified_tests.append(test) else: - try: - language_support = get_language_support(test.behavior_file_path) - modified_source = language_support.add_runtime_comments( - test.generated_original_test_source, original_runtimes_dict, optimized_runtimes_dict - ) - modified_test = GeneratedTests( - generated_original_test_source=modified_source, - instrumented_behavior_test_source=test.instrumented_behavior_test_source, - instrumented_perf_test_source=test.instrumented_perf_test_source, - behavior_file_path=test.behavior_file_path, - perf_file_path=test.perf_file_path, - ) - modified_tests.append(modified_test) - except Exception as e: - logger.debug(f"Failed to add runtime comments to test: {e}") - modified_tests.append(test) + modified_tests.append(test) return GeneratedTestsList(generated_tests=modified_tests) From 48c30f5ffe87a659635f055389d8de9d6628430f Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 19 Feb 2026 12:18:56 +0000 Subject: [PATCH 098/100] style: auto-fix linting issues --- codeflash/languages/base.py | 9 ++------- codeflash/languages/javascript/support.py | 10 ++++------ .../python/static_analysis/code_extractor.py | 1 - .../python/static_analysis/code_replacer.py | 6 ++---- codeflash/languages/python/support.py | 14 +++++++------- codeflash/optimization/function_optimizer.py | 5 +---- 6 files changed, 16 insertions(+), 29 deletions(-) diff --git a/codeflash/languages/base.py b/codeflash/languages/base.py index e1612d62d..3e10da319 100644 --- a/codeflash/languages/base.py +++ b/codeflash/languages/base.py @@ -15,8 +15,7 @@ from pathlib import Path from codeflash.discovery.functions_to_optimize import FunctionToOptimize - from codeflash.models.models import GeneratedTestsList, InvocationId - from codeflash.models.models import FunctionSource + from codeflash.models.models import FunctionSource, GeneratedTestsList, InvocationId from codeflash.languages.language_enum import Language from codeflash.models.function_types import FunctionParent @@ -540,11 +539,7 @@ def remove_test_functions(self, test_source: str, functions_to_remove: list[str] ... def postprocess_generated_tests( - self, - generated_tests: GeneratedTestsList, - test_framework: str, - project_root: Path, - source_file_path: Path, + self, generated_tests: GeneratedTestsList, test_framework: str, project_root: Path, source_file_path: Path ) -> GeneratedTestsList: """Apply language-specific postprocessing to generated tests. diff --git a/codeflash/languages/javascript/support.py b/codeflash/languages/javascript/support.py index e7f40025d..e0111c634 100644 --- a/codeflash/languages/javascript/support.py +++ b/codeflash/languages/javascript/support.py @@ -1780,11 +1780,7 @@ def remove_test_functions(self, test_source: str, functions_to_remove: list[str] return remove_test_functions(test_source, functions_to_remove) def postprocess_generated_tests( - self, - generated_tests: GeneratedTestsList, - test_framework: str, - project_root: Path, - source_file_path: Path, + self, generated_tests: GeneratedTestsList, test_framework: str, project_root: Path, source_file_path: Path ) -> GeneratedTestsList: """Apply language-specific postprocessing to generated tests.""" from codeflash.languages.javascript.edit_tests import ( @@ -1884,7 +1880,9 @@ def _build_runtime_map( key = test_qualified_name + "#" + abs_path_str parts = inv_id.iteration_id.split("_").__len__() # type: ignore[union-attr] - cur_invid = inv_id.iteration_id.split("_")[0] if parts < 3 else "_".join(inv_id.iteration_id.split("_")[:-1]) # type: ignore[union-attr] + cur_invid = ( + inv_id.iteration_id.split("_")[0] if parts < 3 else "_".join(inv_id.iteration_id.split("_")[:-1]) + ) # type: ignore[union-attr] match_key = key + "#" + cur_invid if match_key not in unique_inv_ids: unique_inv_ids[match_key] = 0 diff --git a/codeflash/languages/python/static_analysis/code_extractor.py b/codeflash/languages/python/static_analysis/code_extractor.py index eb6de3a4e..704f9e3db 100644 --- a/codeflash/languages/python/static_analysis/code_extractor.py +++ b/codeflash/languages/python/static_analysis/code_extractor.py @@ -1729,4 +1729,3 @@ def _format_references_as_markdown(references: list, file_path: Path, project_ro fn_call_context += "\n```\n" return fn_call_context - diff --git a/codeflash/languages/python/static_analysis/code_replacer.py b/codeflash/languages/python/static_analysis/code_replacer.py index d4d26e6dd..4e100a230 100644 --- a/codeflash/languages/python/static_analysis/code_replacer.py +++ b/codeflash/languages/python/static_analysis/code_replacer.py @@ -25,7 +25,7 @@ from pathlib import Path from codeflash.discovery.functions_to_optimize import FunctionToOptimize - from codeflash.languages.base import Language, LanguageSupport + from codeflash.languages.base import LanguageSupport from codeflash.models.models import CodeOptimizationContext, CodeStringsMarkdown, OptimizedCandidate, ValidCode ASTNodeT = TypeVar("ASTNodeT", bound=ast.AST) @@ -600,9 +600,7 @@ def replace_function_definitions_for_language( # Add any new global declarations from the optimized code to the original source original_source_code = lang_support.add_global_declarations( - optimized_code=code_to_apply, - original_source=original_source_code, - module_abspath=module_abspath, + optimized_code=code_to_apply, original_source=original_source_code, module_abspath=module_abspath ) # If we have function_to_optimize with line info and this is the main file, use it for precise replacement diff --git a/codeflash/languages/python/support.py b/codeflash/languages/python/support.py index 61ec5f46e..cf55e6f61 100644 --- a/codeflash/languages/python/support.py +++ b/codeflash/languages/python/support.py @@ -658,11 +658,7 @@ def leave_FunctionDef( return test_source def postprocess_generated_tests( - self, - generated_tests: GeneratedTestsList, - test_framework: str, - project_root: Path, - source_file_path: Path, + self, generated_tests: GeneratedTestsList, test_framework: str, project_root: Path, source_file_path: Path ) -> GeneratedTestsList: """Apply language-specific postprocessing to generated tests.""" _ = test_framework, project_root, source_file_path @@ -672,7 +668,9 @@ def remove_test_functions_from_generated_tests( self, generated_tests: GeneratedTestsList, functions_to_remove: list[str] ) -> GeneratedTestsList: """Remove specific test functions from generated tests.""" - from codeflash.languages.python.static_analysis.edit_generated_tests import remove_functions_from_generated_tests + from codeflash.languages.python.static_analysis.edit_generated_tests import ( + remove_functions_from_generated_tests, + ) return remove_functions_from_generated_tests(generated_tests, functions_to_remove) @@ -684,7 +682,9 @@ def add_runtime_comments_to_generated_tests( tests_project_rootdir: Path | None = None, ) -> GeneratedTestsList: """Add runtime comments to generated tests.""" - from codeflash.languages.python.static_analysis.edit_generated_tests import add_runtime_comments_to_generated_tests + from codeflash.languages.python.static_analysis.edit_generated_tests import ( + add_runtime_comments_to_generated_tests, + ) return add_runtime_comments_to_generated_tests( generated_tests, original_runtimes, optimized_runtimes, tests_project_rootdir diff --git a/codeflash/optimization/function_optimizer.py b/codeflash/optimization/function_optimizer.py index eece4795d..dd8e41dd8 100644 --- a/codeflash/optimization/function_optimizer.py +++ b/codeflash/optimization/function_optimizer.py @@ -2069,10 +2069,7 @@ def process_review( ) generated_tests = self.language_support.add_runtime_comments_to_generated_tests( - generated_tests, - original_runtime_by_test, - optimized_runtime_by_test, - self.test_cfg.tests_project_rootdir, + generated_tests, original_runtime_by_test, optimized_runtime_by_test, self.test_cfg.tests_project_rootdir ) generated_tests_str = "" From 506017970de31a8082900d618a54f5e075e72f93 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 19 Feb 2026 21:43:17 -0500 Subject: [PATCH 099/100] fix: remove leftover codeflash_capture instrumentation from test fixture bubble_sort_method.py was accidentally committed with a @codeflash_capture decorator and hardcoded temp path from a local test run, breaking tests in other environments. --- code_to_optimize/bubble_sort_method.py | 16 ++--- .../test_classmethod_behavior_results_temp.py | 58 ------------------- 2 files changed, 6 insertions(+), 68 deletions(-) delete mode 100644 code_to_optimize/tests/pytest/test_classmethod_behavior_results_temp.py diff --git a/code_to_optimize/bubble_sort_method.py b/code_to_optimize/bubble_sort_method.py index 7b399effd..9c4531bec 100644 --- a/code_to_optimize/bubble_sort_method.py +++ b/code_to_optimize/bubble_sort_method.py @@ -1,45 +1,41 @@ import sys -from codeflash.verification.codeflash_capture import codeflash_capture - class BubbleSorter: - - @codeflash_capture(function_name='BubbleSorter.__init__', tmp_dir_path='/var/folders/mg/k_c0twcj37q_gph3cfy3zlt80000gn/T/codeflash_ec8xrcji/test_return_values', tests_root='/Users/krrt7/Desktop/work/cf_org/codeflash/code_to_optimize/tests/pytest', is_fto=True) def __init__(self, x=0): self.x = x def sorter(self, arr): - print('codeflash stdout : BubbleSorter.sorter() called') + print("codeflash stdout : BubbleSorter.sorter() called") for i in range(len(arr)): for j in range(len(arr) - 1): if arr[j] > arr[j + 1]: temp = arr[j] arr[j] = arr[j + 1] arr[j + 1] = temp - print('stderr test', file=sys.stderr) + print("stderr test", file=sys.stderr) return arr @classmethod def sorter_classmethod(cls, arr): - print('codeflash stdout : BubbleSorter.sorter_classmethod() called') + print("codeflash stdout : BubbleSorter.sorter_classmethod() called") for i in range(len(arr)): for j in range(len(arr) - 1): if arr[j] > arr[j + 1]: temp = arr[j] arr[j] = arr[j + 1] arr[j + 1] = temp - print('stderr test classmethod', file=sys.stderr) + print("stderr test classmethod", file=sys.stderr) return arr @staticmethod def sorter_staticmethod(arr): - print('codeflash stdout : BubbleSorter.sorter_staticmethod() called') + print("codeflash stdout : BubbleSorter.sorter_staticmethod() called") for i in range(len(arr)): for j in range(len(arr) - 1): if arr[j] > arr[j + 1]: temp = arr[j] arr[j] = arr[j + 1] arr[j + 1] = temp - print('stderr test staticmethod', file=sys.stderr) + print("stderr test staticmethod", file=sys.stderr) return arr diff --git a/code_to_optimize/tests/pytest/test_classmethod_behavior_results_temp.py b/code_to_optimize/tests/pytest/test_classmethod_behavior_results_temp.py deleted file mode 100644 index ac9cdcfac..000000000 --- a/code_to_optimize/tests/pytest/test_classmethod_behavior_results_temp.py +++ /dev/null @@ -1,58 +0,0 @@ -import gc -import inspect -import os -import sqlite3 -import time - -import dill as pickle - -from code_to_optimize.bubble_sort_method import BubbleSorter - - -def codeflash_wrap(codeflash_wrapped, codeflash_test_module_name, codeflash_test_class_name, codeflash_test_name, codeflash_function_name, codeflash_line_id, codeflash_loop_index, codeflash_cur, codeflash_con, *args, **kwargs): - test_id = f'{codeflash_test_module_name}:{codeflash_test_class_name}:{codeflash_test_name}:{codeflash_line_id}:{codeflash_loop_index}' - if not hasattr(codeflash_wrap, 'index'): - codeflash_wrap.index = {} - if test_id in codeflash_wrap.index: - codeflash_wrap.index[test_id] += 1 - else: - codeflash_wrap.index[test_id] = 0 - codeflash_test_index = codeflash_wrap.index[test_id] - invocation_id = f'{codeflash_line_id}_{codeflash_test_index}' - test_stdout_tag = f"{codeflash_test_module_name}:{(codeflash_test_class_name + '.' if codeflash_test_class_name else '')}{codeflash_test_name}:{codeflash_function_name}:{codeflash_loop_index}:{invocation_id}" - print(f"!$######{test_stdout_tag}######$!") - exception = None - gc.disable() - try: - counter = time.perf_counter_ns() - return_value = codeflash_wrapped(*args, **kwargs) - codeflash_duration = time.perf_counter_ns() - counter - except Exception as e: - codeflash_duration = time.perf_counter_ns() - counter - exception = e - gc.enable() - print(f"!######{test_stdout_tag}######!") - pickled_return_value = pickle.dumps(exception) if exception else pickle.dumps(return_value) - codeflash_cur.execute('INSERT INTO test_results VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)', (codeflash_test_module_name, codeflash_test_class_name, codeflash_test_name, codeflash_function_name, codeflash_loop_index, invocation_id, codeflash_duration, pickled_return_value, 'function_call')) - codeflash_con.commit() - if exception: - raise exception - return return_value - -def test_sort(): - codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX']) - codeflash_iteration = os.environ['CODEFLASH_TEST_ITERATION'] - codeflash_con = sqlite3.connect(f'/var/folders/mg/k_c0twcj37q_gph3cfy3zlt80000gn/T/codeflash_ec8xrcji/test_return_values_{codeflash_iteration}.sqlite') - codeflash_cur = codeflash_con.cursor() - codeflash_cur.execute('CREATE TABLE IF NOT EXISTS test_results (test_module_path TEXT, test_class_name TEXT, test_function_name TEXT, function_getting_tested TEXT, loop_index INTEGER, iteration_id TEXT, runtime INTEGER, return_value BLOB, verification_type TEXT)') - input = [5, 4, 3, 2, 1, 0] - _call__bound__arguments = inspect.signature(BubbleSorter.sorter_classmethod).bind(input) - _call__bound__arguments.apply_defaults() - output = codeflash_wrap(BubbleSorter.sorter_classmethod, 'code_to_optimize.tests.pytest.test_classmethod_behavior_results_temp', None, 'test_sort', 'BubbleSorter.sorter_classmethod', '1', codeflash_loop_index, codeflash_cur, codeflash_con, *_call__bound__arguments.args, **_call__bound__arguments.kwargs) - assert output == [0, 1, 2, 3, 4, 5] - input = [5.0, 4.0, 3.0, 2.0, 1.0, 0.0] - _call__bound__arguments = inspect.signature(BubbleSorter.sorter_classmethod).bind(input) - _call__bound__arguments.apply_defaults() - output = codeflash_wrap(BubbleSorter.sorter_classmethod, 'code_to_optimize.tests.pytest.test_classmethod_behavior_results_temp', None, 'test_sort', 'BubbleSorter.sorter_classmethod', '4', codeflash_loop_index, codeflash_cur, codeflash_con, *_call__bound__arguments.args, **_call__bound__arguments.kwargs) - assert output == [0.0, 1.0, 2.0, 3.0, 4.0, 5.0] - codeflash_con.close() From d5783538b71d306003380a944033f2ae41064042 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Fri, 20 Feb 2026 02:45:16 +0000 Subject: [PATCH 100/100] style: auto-fix formatting issues Co-Authored-By: Claude Opus 4.6 --- codeflash/cli_cmds/console.py | 11 +++++++++- codeflash/cli_cmds/logging_config.py | 20 +++++++++++++++++-- codeflash/languages/java/context.py | 10 ++-------- codeflash/languages/java/instrumentation.py | 10 ++++++++-- codeflash/languages/java/replacement.py | 8 +------- .../parse_line_profile_test_output.py | 14 +++---------- 6 files changed, 42 insertions(+), 31 deletions(-) diff --git a/codeflash/cli_cmds/console.py b/codeflash/cli_cmds/console.py index 577f38f69..5ff215057 100644 --- a/codeflash/cli_cmds/console.py +++ b/codeflash/cli_cmds/console.py @@ -45,7 +45,16 @@ logging.basicConfig( level=logging.INFO, - handlers=[RichHandler(rich_tracebacks=True, markup=False, highlighter=NullHighlighter(), console=console, show_path=False, show_time=False)], + handlers=[ + RichHandler( + rich_tracebacks=True, + markup=False, + highlighter=NullHighlighter(), + console=console, + show_path=False, + show_time=False, + ) + ], format=BARE_LOGGING_FORMAT, ) diff --git a/codeflash/cli_cmds/logging_config.py b/codeflash/cli_cmds/logging_config.py index c2f339abd..dbb3663bd 100644 --- a/codeflash/cli_cmds/logging_config.py +++ b/codeflash/cli_cmds/logging_config.py @@ -14,7 +14,16 @@ def set_level(level: int, *, echo_setting: bool = True) -> None: logging.basicConfig( level=level, - handlers=[RichHandler(rich_tracebacks=True, markup=False, highlighter=NullHighlighter(), console=console, show_path=False, show_time=False)], + handlers=[ + RichHandler( + rich_tracebacks=True, + markup=False, + highlighter=NullHighlighter(), + console=console, + show_path=False, + show_time=False, + ) + ], format=BARE_LOGGING_FORMAT, ) logging.getLogger().setLevel(level) @@ -23,7 +32,14 @@ def set_level(level: int, *, echo_setting: bool = True) -> None: logging.basicConfig( format=VERBOSE_LOGGING_FORMAT, handlers=[ - RichHandler(rich_tracebacks=True, markup=False, highlighter=NullHighlighter(), console=console, show_path=False, show_time=False) + RichHandler( + rich_tracebacks=True, + markup=False, + highlighter=NullHighlighter(), + console=console, + show_path=False, + show_time=False, + ) ], force=True, ) diff --git a/codeflash/languages/java/context.py b/codeflash/languages/java/context.py index 29067f23f..d45c6ee5f 100644 --- a/codeflash/languages/java/context.py +++ b/codeflash/languages/java/context.py @@ -887,11 +887,7 @@ def collect_type_identifiers(node: Node) -> None: def get_java_imported_type_skeletons( - imports: list, - project_root: Path, - module_root: Path | None, - analyzer: JavaAnalyzer, - target_code: str = "", + imports: list, project_root: Path, module_root: Path | None, analyzer: JavaAnalyzer, target_code: str = "" ) -> str: """Extract type skeletons for project-internal imported types. @@ -1011,9 +1007,7 @@ def _extract_constructor_summaries(skeleton: TypeSkeleton) -> list[str]: return summaries -def _format_skeleton_for_context( - skeleton: TypeSkeleton, source: str, class_name: str, analyzer: JavaAnalyzer -) -> str: +def _format_skeleton_for_context(skeleton: TypeSkeleton, source: str, class_name: str, analyzer: JavaAnalyzer) -> str: """Format a TypeSkeleton into a context string with method signatures. Includes: type declaration, fields, constructors, and public method signatures diff --git a/codeflash/languages/java/instrumentation.py b/codeflash/languages/java/instrumentation.py index 7cad460dd..3dd17261d 100644 --- a/codeflash/languages/java/instrumentation.py +++ b/codeflash/languages/java/instrumentation.py @@ -731,8 +731,14 @@ def split_var_declaration(stmt_node, source_bytes_ref: bytes) -> tuple[str, str] # conditionally executed, so an uninitialized declaration would cause # "variable might not have been initialized" errors. _PRIMITIVE_DEFAULTS = { - "byte": "0", "short": "0", "int": "0", "long": "0L", - "float": "0.0f", "double": "0.0", "char": "'\\0'", "boolean": "false", + "byte": "0", + "short": "0", + "int": "0", + "long": "0L", + "float": "0.0f", + "double": "0.0", + "char": "'\\0'", + "boolean": "false", } default_val = _PRIMITIVE_DEFAULTS.get(type_text, "null") hoisted = f"{type_text} {name_text} = {default_val};" diff --git a/codeflash/languages/java/replacement.py b/codeflash/languages/java/replacement.py index 23e3c9232..a374043e5 100644 --- a/codeflash/languages/java/replacement.py +++ b/codeflash/languages/java/replacement.py @@ -374,13 +374,7 @@ def replace_function( class_name, ) source = _insert_class_members( - source, - class_name, - new_fields_to_add, - new_helpers_before, - new_helpers_after, - func_name, - analyzer, + source, class_name, new_fields_to_add, new_helpers_before, new_helpers_after, func_name, analyzer ) # Re-find the target method after modifications diff --git a/codeflash/verification/parse_line_profile_test_output.py b/codeflash/verification/parse_line_profile_test_output.py index 34b27bdb3..f1b4598eb 100644 --- a/codeflash/verification/parse_line_profile_test_output.py +++ b/codeflash/verification/parse_line_profile_test_output.py @@ -80,9 +80,7 @@ def show_text(stats: dict) -> str: return out_table -def show_text_non_python( - stats: dict, line_contents: dict[tuple[str, int], str] -) -> str: +def show_text_non_python(stats: dict, line_contents: dict[tuple[str, int], str]) -> str: """Show text for non-Python timings using profiler-provided line contents.""" out_table = "" out_table += "# Timer unit: {:g} s\n".format(stats["unit"]) @@ -115,11 +113,7 @@ def show_text_non_python( table_cols = ("Hits", "Time", "Per Hit", "% Time", "Line Contents") out_table += tabulate( - headers=table_cols, - tabular_data=table_rows, - tablefmt="pipe", - colglobalalign=None, - preserve_whitespace=True, + headers=table_cols, tabular_data=table_rows, tablefmt="pipe", colglobalalign=None, preserve_whitespace=True ) out_table += "\n" return out_table @@ -159,9 +153,7 @@ def parse_line_profile_results(line_profiler_output_file: Optional[Path]) -> dic line_num = int(line_str) line_num = int(line_num) - lines_by_file.setdefault(file_path, []).append( - (line_num, int(stats.get("hits", 0)), int(stats.get("time", 0))) - ) + lines_by_file.setdefault(file_path, []).append((line_num, int(stats.get("hits", 0)), int(stats.get("time", 0)))) line_contents[(file_path, line_num)] = stats.get("content", "") for file_path, line_stats in lines_by_file.items():