mirror of
https://github.com/wilsonfreitas/awesome-quant.git
synced 2026-08-18 14:28:06 +00:00
155 lines
4.8 KiB
Python
Executable File
155 lines
4.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Check PyPI projects for last updated dates and update README.md entries.
|
|
"""
|
|
|
|
import json
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
from typing import Dict, Optional, Tuple
|
|
from urllib.request import urlopen
|
|
|
|
# PyPI projects to track
|
|
PYPI_PROJECTS = {
|
|
"qfrm": "qfrm",
|
|
"chinesestockapi": "chinesestockapi",
|
|
"tushare": "tushare",
|
|
"metatrader5": "MetaTrader5",
|
|
}
|
|
|
|
README_PATH = Path(__file__).parent.parent.parent.parent.parent / "README.md"
|
|
|
|
|
|
def get_pypi_last_updated(package_name: str) -> Optional[str]:
|
|
"""
|
|
Fetch the last updated date for a PyPI package.
|
|
|
|
Returns: date string in format "YYYY-MM-DD" or None if not found
|
|
"""
|
|
try:
|
|
url = f"https://pypi.org/pypi/{package_name}/json"
|
|
with urlopen(url, timeout=5) as response:
|
|
data = json.loads(response.read().decode())
|
|
|
|
# Get releases (ordered dict, latest first after sorting)
|
|
releases = data.get("releases", {})
|
|
if not releases:
|
|
return None
|
|
|
|
# Find the latest release with upload time
|
|
for version in sorted(releases.keys(), reverse=True):
|
|
release_data = releases[version]
|
|
if release_data and len(release_data) > 0:
|
|
upload_time = release_data[0].get("upload_time_iso_8601")
|
|
if upload_time:
|
|
# Extract just the date part (YYYY-MM-DD)
|
|
return upload_time.split("T")[0]
|
|
|
|
return None
|
|
except Exception as e:
|
|
print(f" ❌ Error fetching {package_name}: {e}", file=sys.stderr)
|
|
return None
|
|
|
|
|
|
def find_readme_entry(readme_content: str, package_display_name: str) -> Tuple[Optional[int], Optional[str]]:
|
|
"""
|
|
Find a README entry for a package.
|
|
|
|
Returns: (line_number, match_text) or (None, None)
|
|
"""
|
|
# Pattern to match the entry - look for [package_name](pypi.org...)
|
|
pattern = rf"\- \[{re.escape(package_display_name)}\]\(https://pypi\.org/project/\w+/\)[^\n]*"
|
|
|
|
for line_num, line in enumerate(readme_content.split("\n"), 1):
|
|
if re.search(pattern, line):
|
|
return line_num, line.strip()
|
|
|
|
return None, None
|
|
|
|
|
|
def update_readme_entry(readme_content: str, package_display_name: str, new_date: str) -> Tuple[str, bool]:
|
|
"""
|
|
Update or add the last updated date to a README entry.
|
|
|
|
Returns: (updated_content, was_changed)
|
|
"""
|
|
lines = readme_content.split("\n")
|
|
line_num, entry_text = find_readme_entry(readme_content, package_display_name)
|
|
|
|
if line_num is None:
|
|
return readme_content, False
|
|
|
|
old_line = lines[line_num - 1]
|
|
|
|
# Check if entry already has a date
|
|
existing_date_pattern = r"\(Last updated: \d{4}-\d{2}-\d{2}\)"
|
|
existing_match = re.search(existing_date_pattern, old_line)
|
|
|
|
if existing_match:
|
|
old_date = existing_match.group(0)
|
|
new_date_str = f"(Last updated: {new_date})"
|
|
if old_date == new_date_str:
|
|
return readme_content, False # No change needed
|
|
new_line = old_line.replace(old_date, new_date_str)
|
|
else:
|
|
# Add date to the end of the entry (before period if present)
|
|
if old_line.endswith("."):
|
|
new_line = old_line[:-1] + f" (Last updated: {new_date})."
|
|
else:
|
|
new_line = old_line + f" (Last updated: {new_date})"
|
|
|
|
lines[line_num - 1] = new_line
|
|
return "\n".join(lines), True
|
|
|
|
|
|
def main():
|
|
"""Check PyPI projects and update README.md."""
|
|
if not README_PATH.exists():
|
|
print(f"❌ README.md not found at {README_PATH}")
|
|
sys.exit(1)
|
|
|
|
readme_content = README_PATH.read_text(encoding="utf-8")
|
|
updated_content = readme_content
|
|
changes_made = []
|
|
|
|
print("📦 Checking PyPI projects for last updated dates...\n")
|
|
|
|
for display_name, pypi_name in PYPI_PROJECTS.items():
|
|
print(f"Checking {display_name}...")
|
|
|
|
last_updated = get_pypi_last_updated(pypi_name)
|
|
if last_updated is None:
|
|
print(f" ⚠️ Could not find last updated date")
|
|
continue
|
|
|
|
updated_content, was_changed = update_readme_entry(
|
|
updated_content, display_name, last_updated
|
|
)
|
|
|
|
if was_changed:
|
|
print(f" ✅ Updated to {last_updated}")
|
|
changes_made.append((display_name, last_updated))
|
|
else:
|
|
print(f" ✓ {last_updated} (no change)")
|
|
|
|
print()
|
|
|
|
if changes_made:
|
|
print(f"📝 Found {len(changes_made)} update(s):")
|
|
for pkg_name, date in changes_made:
|
|
print(f" - {pkg_name}: {date}")
|
|
|
|
README_PATH.write_text(updated_content, encoding="utf-8")
|
|
print(f"\n✅ Updated {README_PATH.name}")
|
|
return 0
|
|
else:
|
|
print("✓ All packages up to date!")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|