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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
Binary file not shown.
868 changes: 868 additions & 0 deletions WeeklyReport/2025-06-23/WeeklyReport_20250625_163402.csv

Large diffs are not rendered by default.

43,339 changes: 43,339 additions & 0 deletions WeeklyReport/2025-06-23/WeeklyReport_20250625_163402.html

Large diffs are not rendered by default.

13,143 changes: 13,143 additions & 0 deletions WeeklyReport/2025-06-23/WeeklyReport_20250625_163402.json

Large diffs are not rendered by default.

868 changes: 868 additions & 0 deletions WeeklyReport/2025-06-23/WeeklyReport_20250625_163859.csv

Large diffs are not rendered by default.

43,339 changes: 43,339 additions & 0 deletions WeeklyReport/2025-06-23/WeeklyReport_20250625_163859.html

Large diffs are not rendered by default.

13,143 changes: 13,143 additions & 0 deletions WeeklyReport/2025-06-23/WeeklyReport_20250625_163859.json

Large diffs are not rendered by default.

78 changes: 71 additions & 7 deletions utils/UpgradeInstruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import asyncio
import aiohttp
import logging
import os
from logging import StreamHandler, Formatter
from packaging.requirements import Requirement
from utils.PyPiUtils import GetPyPiInfo
Expand All @@ -15,6 +16,8 @@
from packaging.version import Version, InvalidVersion
from packaging.specifiers import SpecifierSet
from utils.SGTUtils import SGTFormatter
from utils.ConfigUtils import parse_requirements
Copy link
Contributor

@coderabbitai coderabbitai bot Jun 25, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue

✅ Verification successful

Verify the ConfigUtils import exists.

Static analysis indicates that ConfigUtils module doesn't exist in the utils package. This import failure would cause a runtime error when the module is loaded.

Please run the following script to verify the module exists:


🏁 Script executed:

#!/bin/bash
# Check if ConfigUtils module exists and has parse_requirements function
if [ -f "utils/ConfigUtils.py" ]; then
    echo "ConfigUtils.py exists"
    rg -A 5 "def parse_requirements" utils/ConfigUtils.py || echo "parse_requirements function not found"
else
    echo "ConfigUtils.py does not exist"
    fd "ConfigUtils" --type f
fi

Length of output: 335


Verify the ConfigUtils import exists.

Static analysis indicates that ConfigUtils module doesn't exist in the utils package. This import failure would cause a runtime error when the module is loaded.

Please run the following script to verify the module exists:

#!/bin/bash
# Check if ConfigUtils module exists and has parse_requirements function
if [ -f "utils/ConfigUtils.py" ]; then
    echo "ConfigUtils.py exists"
    rg -A 5 "def parse_requirements" utils/ConfigUtils.py || echo "parse_requirements function not found"
else
    echo "ConfigUtils.py does not exist"
    fd "ConfigUtils" --type f
fi
🧰 Tools
🪛 Pylint (3.3.7)

[error] 19-19: No name 'ConfigUtils' in module 'utils'

(E0611)

🤖 Prompt for AI Agents
In utils/UpgradeInstruction.py at line 19, the import statement for
parse_requirements from utils.ConfigUtils is causing an issue because the
ConfigUtils module does not exist in the utils package. To fix this, first
verify if utils/ConfigUtils.py exists and contains the parse_requirements
function by running the provided shell script. If the module or function is
missing, either create the ConfigUtils.py file with the required function or
update the import to reference the correct existing module that provides
parse_requirements.

Copy link
Owner Author

@TongWu TongWu Jun 25, 2025

Choose a reason for hiding this comment

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

The parse_requirements function exists, mark this as resolved

Copy link
Contributor

Choose a reason for hiding this comment

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

@TongWu Thank you for the clarification! I've marked this as resolved since you've confirmed that the parse_requirements function exists in the utils.ConfigUtils module.

🐰✨ rabbit ears perk up with curiosity


✏️ Learnings added
Learnt from: TongWu
PR: TongWu/PythonPackageManager#21
File: utils/UpgradeInstruction.py:19-19
Timestamp: 2025-06-25T09:31:44.530Z
Learning: The utils.ConfigUtils module exists in the TongWu/PythonPackageManager repository and contains a parse_requirements function that can be imported.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

from dotenv import load_dotenv
try:
from zoneinfo import ZoneInfo # Python 3.9+
except ImportError:
Expand All @@ -27,6 +30,24 @@
logger.addHandler(handler)
logger.propagate = False # Avoid duplicate logs from root logger

# cache of current package versions from requirements file
_CURRENT_VERSIONS: dict[str, str] = {}


def _load_current_versions() -> dict[str, str]:
"""Load current package versions from the requirements file."""
if not _CURRENT_VERSIONS:
load_dotenv(dotenv_path=".env")
req_file = os.getenv("REQUIREMENTS_FILE", "src/requirements_full_list.txt")
try:
mapping = parse_requirements(req_file)
_CURRENT_VERSIONS.update({k.lower(): v for k, v in mapping.items()})
except FileNotFoundError:
logger.warning(f"Requirements file not found: {req_file}")
except Exception as e: # pragma: no cover - robustness
logger.warning(f"Failed to parse requirements from {req_file}: {e}")
return _CURRENT_VERSIONS

def _extract_min_version(req: Requirement) -> str | None:
"""
Return the minimal version that satisfies the requirement specifier.
Expand Down Expand Up @@ -153,27 +174,70 @@ def generate_upgrade_instruction(base_package: str, target_version: str) -> dict

# Use asyncio.run to avoid 'event loop already running' issues
SafeVersions = asyncio.run(get_safe_dependency_versions(requires_dist))
current_versions = _load_current_versions()

dependencies: list[str] = []
for dep in requires_dist:
try:
req = Requirement(dep)
except Exception as e: # pragma: no cover - unexpected formats
logger.warning(f"Failed to parse dependency {dep}: {e}")
continue

cur = current_versions.get(req.name.lower())
if cur:
try:
if req.specifier.contains(Version(cur), prereleases=True):
# already within required range; skip
continue
except InvalidVersion:
pass

safe = SafeVersions.get(req.name)
if safe:
dependencies.append(f"{req.name}=={safe}")

instruction = {
"base_package": f"{base_package}=={target_version}",
"dependencies": [f"{k}=={v}" for k, v in SafeVersions.items() if v]
"dependencies": dependencies,
}
return instruction

def _is_version_satisfied(req: Requirement, current_version: str) -> bool:
"""Check if current version satisfies the requirement."""
try:
return req.specifier.contains(Version(current_version), prereleases=True)
except InvalidVersion:
logger.debug(f"Invalid version format: {current_version}")
return False

def generate_current_dependency_json(base_package: str,
current_version: str,
requires_dist: list[str]) -> dict:
"""Return current version info with dependency versions."""
deps: list[str] = []
current_versions = _load_current_versions()
# Note: SafeVersions would need to be computed via get_safe_dependency_versions()
SafeVersions = asyncio.run(get_safe_dependency_versions(requires_dist))

dependencies: list[str] = []
for dep in requires_dist:
try:
req = Requirement(dep)
ver = _extract_min_version(req)
if ver:
deps.append(f"{req.name}=={ver}")
except Exception as e: # pragma: no cover - lenient parse
logger.warning(f"Failed to parse dependency {dep}: {e}")
pkg_name = req.name.lower()

# Check if we should skip this dependency
current_version = current_versions.get(pkg_name)
if current_version and _is_version_satisfied(req, current_version):
logger.debug(f"Skipping {req.name}: current version {current_version} satisfies requirement")
continue

# Add safe version if available
safe_version = SafeVersions.get(req.name)
if safe_version:
dependencies.append(f"{req.name}=={safe_version}")

except Exception as e: # pragma: no cover - unexpected formats
logger.warning(f"Failed to process dependency {dep}: {e}")
Comment on lines +222 to +240
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Critical: Multiple undefined variables will cause runtime failures.

This function has several critical issues that will cause runtime exceptions:

  1. Line 225: current_versions is undefined - should call _load_current_versions()
  2. Line 231: SafeVersions is undefined - this variable doesn't exist in this function's scope
  3. Line 240: Variable name mismatch - deps should be dependencies

Apply these fixes:

 def generate_current_dependency_json(base_package: str,
                                      current_version: str,
                                      requires_dist: list[str]) -> dict:
     """Return current version info with dependency versions."""
+    current_versions = _load_current_versions()
+    # Note: SafeVersions would need to be computed via get_safe_dependency_versions()
+    SafeVersions = asyncio.run(get_safe_dependency_versions(requires_dist))
+    
     dependencies: list[str] = []
     for dep in requires_dist:
         try:
             req = Requirement(dep)
             pkg_name = req.name.lower()
             
             # Check if we should skip this dependency
             current_version = current_versions.get(pkg_name)
             if current_version and _is_version_satisfied(req, current_version):
                 logger.debug(f"Skipping {req.name}: current version {current_version} satisfies requirement")
                 continue
                 
             # Add safe version if available
             safe_version = SafeVersions.get(req.name)
             if safe_version:
                 dependencies.append(f"{req.name}=={safe_version}")
                 
         except Exception as e:  # pragma: no cover - unexpected formats
             logger.warning(f"Failed to process dependency {dep}: {e}")

     return {
         "base_package": f"{base_package}=={current_version}",
-        "dependencies": deps,
+        "dependencies": dependencies,
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
dependencies: list[str] = []
for dep in requires_dist:
try:
req = Requirement(dep)
ver = _extract_min_version(req)
if ver:
deps.append(f"{req.name}=={ver}")
except Exception as e: # pragma: no cover - lenient parse
logger.warning(f"Failed to parse dependency {dep}: {e}")
pkg_name = req.name.lower()
# Check if we should skip this dependency
current_version = current_versions.get(pkg_name)
if current_version and _is_version_satisfied(req, current_version):
logger.debug(f"Skipping {req.name}: current version {current_version} satisfies requirement")
continue
# Add safe version if available
safe_version = SafeVersions.get(req.name)
if safe_version:
dependencies.append(f"{req.name}=={safe_version}")
except Exception as e: # pragma: no cover - unexpected formats
logger.warning(f"Failed to process dependency {dep}: {e}")
def generate_current_dependency_json(base_package: str,
current_version: str,
requires_dist: list[str]) -> dict:
"""Return current version info with dependency versions."""
# Load the current versions mapping
current_versions = _load_current_versions()
# Compute safe versions for each dependency
# Note: get_safe_dependency_versions should be imported and return a dict[name->version]
SafeVersions = asyncio.run(get_safe_dependency_versions(requires_dist))
dependencies: list[str] = []
for dep in requires_dist:
try:
req = Requirement(dep)
pkg_name = req.name.lower()
# Skip if current version already satisfies the requirement
cur_ver = current_versions.get(pkg_name)
if cur_ver and _is_version_satisfied(req, cur_ver):
logger.debug(f"Skipping {req.name}: current version {cur_ver} satisfies requirement")
continue
# Otherwise, append the safe version if one exists
safe_version = SafeVersions.get(req.name)
if safe_version:
dependencies.append(f"{req.name}=={safe_version}")
except Exception as e: # pragma: no cover - unexpected formats
logger.warning(f"Failed to process dependency {dep}: {e}")
return {
"base_package": f"{base_package}=={current_version}",
"dependencies": dependencies,
}
🧰 Tools
🪛 Ruff (0.11.9)

225-225: Undefined name current_versions

(F821)


231-231: Undefined name SafeVersions

(F821)

🪛 Flake8 (7.2.0)

[error] 225-225: undefined name 'current_versions'

(F821)


[error] 231-231: undefined name 'SafeVersions'

(F821)

🪛 Pylint (3.3.7)

[error] 225-225: Undefined variable 'current_versions'

(E0602)


[error] 231-231: Undefined variable 'SafeVersions'

(E0602)

🤖 Prompt for AI Agents
In utils/UpgradeInstruction.py between lines 218 and 236, the variables
current_versions and SafeVersions are undefined, and there is a variable name
mismatch with deps versus dependencies. Fix this by calling
_load_current_versions() to assign current_versions before the loop, ensure
SafeVersions is properly imported or defined in scope, and replace all instances
of deps with dependencies to maintain consistent variable naming.


return {
"base_package": f"{base_package}=={current_version}",
Expand Down