Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions codeflash/code_utils/version_check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
"""Version checking utilities for codeflash."""

import sys
import time
from typing import Optional

import requests
from packaging import version

from codeflash.cli_cmds.console import console, logger
from codeflash.version import __version__

# Simple cache to avoid checking too frequently
_version_cache = {"version": None, "timestamp": 0}
_cache_duration = 3600 # 1 hour cache


def get_latest_version_from_pypi() -> Optional[str]:
"""Get the latest version of codeflash from PyPI.

Returns:
The latest version string from PyPI, or None if the request fails.
"""
global _version_cache

# Check cache first
current_time = time.time()
if (_version_cache["version"] is not None and
current_time - _version_cache["timestamp"] < _cache_duration):
return _version_cache["version"]

try:
response = requests.get("https://pypi.org/pypi/codeflash/json", timeout=10)
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: can have quick timeout here to make it non blocking if there is network issue.

if response.status_code == 200:
data = response.json()
latest_version = data["info"]["version"]

# Update cache
_version_cache["version"] = latest_version
_version_cache["timestamp"] = current_time

return latest_version
else:
logger.debug(f"Failed to fetch version from PyPI: {response.status_code}")
return None
except requests.RequestException as e:
logger.debug(f"Network error fetching version from PyPI: {e}")
return None
except (KeyError, ValueError) as e:
logger.debug(f"Invalid response format from PyPI: {e}")
return None
except Exception as e:
logger.debug(f"Unexpected error fetching version from PyPI: {e}")
return None


def check_for_newer_minor_version(*, disable_check: bool = False) -> None:
"""Check if a newer minor version is available on PyPI and notify the user.

This function compares the current version with the latest version on PyPI.
If a newer minor version is available, it prints an informational message
suggesting the user upgrade.

Args:
disable_check: If True, skip the version check entirely.
"""
if disable_check:
return

# Get current version dynamically to handle runtime changes
from codeflash.version import __version__ as current_version
Copy link
Contributor

Choose a reason for hiding this comment

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

we already have this as global import.

latest_version = get_latest_version_from_pypi()

if not latest_version:
return

try:
current_parsed = version.parse(current_version)
latest_parsed = version.parse(latest_version)

# Check if there's a newer minor version available
# We only notify for minor version updates, not patch updates
if (latest_parsed.major > current_parsed.major or
(latest_parsed.major == current_parsed.major and
latest_parsed.minor > current_parsed.minor)):

console.print(
f"[bold blue]ℹ️ A newer version of Codeflash is available![/bold blue]\n"
f"Current version: {current_version} | Latest version: {latest_version}\n"
f"Consider upgrading for better quality optimizations.",
style="blue"
)

except version.InvalidVersion as e:
logger.debug(f"Invalid version format: {e}")
return
12 changes: 12 additions & 0 deletions codeflash/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from codeflash.cli_cmds.console import paneled_text
from codeflash.code_utils.checkpoint import ask_should_use_checkpoint_get_functions
from codeflash.code_utils.config_parser import parse_config_file
from codeflash.code_utils.version_check import check_for_newer_minor_version
from codeflash.telemetry import posthog_cf
from codeflash.telemetry.sentry import init_sentry

Expand All @@ -21,6 +22,17 @@ def main() -> None:
CODEFLASH_LOGO, panel_args={"title": "https://codeflash.ai", "expand": False}, text_args={"style": "bold gold3"}
)
args = parse_args()

# Check for newer version (skip for version command to avoid confusion)
if not args.version:
Copy link
Contributor

Choose a reason for hiding this comment

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

With version check 'codeflash --version' we can also show the status if its outdated.

# Check if version check is disabled in config
disable_version_check = False
Copy link
Contributor

Choose a reason for hiding this comment

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

I am not sure we are going to add this in the configs or existing configs with customers.
We can just have a direct non blocking check.

if args.config_file and Path.exists(args.config_file):
pyproject_config, _ = parse_config_file(args.config_file)
disable_version_check = pyproject_config.get("disable_version_check", False)

check_for_newer_minor_version(disable_check=disable_version_check)

if args.command:
if args.config_file and Path.exists(args.config_file):
pyproject_config, _ = parse_config_file(args.config_file)
Expand Down
4 changes: 4 additions & 0 deletions codeflash/version.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
# These version placeholders will be replaced by uv-dynamic-versioning during build.
<<<<<<< HEAD
Copy link
Contributor

Choose a reason for hiding this comment

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

we can remove this file from local version testing.

Copy link
Contributor

Choose a reason for hiding this comment

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

@mihikap01 we can remove this file from the scope of this PR.

__version__ = "0.15.6.post8.dev0+52083c4b"
=======
__version__ = "0.16.1"
>>>>>>> 3171bb87187f35c9bd6dbcd3326b09939903898e