mirror of
https://github.com/wilsonfreitas/awesome-quant.git
synced 2026-07-27 20:07:50 +00:00
Add skills for managing PyPI project update dates and syncing README.md
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
# Update PyPI Dates Skill
|
||||
|
||||
Automatically check PyPI projects for their latest update dates and keep README.md entries current.
|
||||
|
||||
## Overview
|
||||
|
||||
This skill monitors Python packages listed in awesome-quant and updates their entries with the latest release dates from PyPI. This ensures that outdated project information is easily identifiable.
|
||||
|
||||
## Features
|
||||
|
||||
- ✅ Checks 4 PyPI projects: qfrm, chinesestockapi, tushare, metatrader5
|
||||
- ✅ Fetches latest release dates from PyPI API
|
||||
- ✅ Updates README.md entries with `(Last updated: YYYY-MM-DD)` format
|
||||
- ✅ Commits changes automatically when updates found
|
||||
- ✅ No dependencies beyond Python standard library
|
||||
|
||||
## Usage
|
||||
|
||||
### Invoke from Claude Code
|
||||
|
||||
```bash
|
||||
/update-pypi-dates
|
||||
```
|
||||
|
||||
Or call the script directly:
|
||||
|
||||
```bash
|
||||
./.claude/skills/update-pypi-dates/scripts/check_pypi_dates.py
|
||||
```
|
||||
|
||||
### Manual Python Execution
|
||||
|
||||
```bash
|
||||
python3 .claude/skills/update-pypi-dates/scripts/check_pypi_dates.py
|
||||
```
|
||||
|
||||
### Bash Wrapper
|
||||
|
||||
```bash
|
||||
./.claude/skills/update-pypi-dates/scripts/update_pypi_dates.sh
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
1. **Queries PyPI API** for each tracked package
|
||||
2. **Extracts last release date** from the releases data
|
||||
3. **Updates README.md** entries with format: `(Last updated: 2024-08-27)`
|
||||
4. **Commits changes** if any updates were found
|
||||
|
||||
## Adding New Packages
|
||||
|
||||
To track additional PyPI packages, edit the `PYPI_PROJECTS` dictionary in `scripts/check_pypi_dates.py`:
|
||||
|
||||
```python
|
||||
PYPI_PROJECTS = {
|
||||
"display_name": "pypi_package_name",
|
||||
# Add new entries here
|
||||
}
|
||||
```
|
||||
|
||||
Then update the skill description if needed.
|
||||
|
||||
## Output Examples
|
||||
|
||||
### No Changes
|
||||
```
|
||||
📦 Checking PyPI projects for last updated dates...
|
||||
|
||||
Checking qfrm...
|
||||
✓ 2015-12-12 (no change)
|
||||
|
||||
✓ All packages up to date!
|
||||
```
|
||||
|
||||
### With Updates
|
||||
```
|
||||
📦 Checking PyPI projects for last updated dates...
|
||||
|
||||
Checking tushare...
|
||||
✓ 2024-08-27 (no change)
|
||||
Checking metatrader5...
|
||||
✅ Updated to 2026-02-20
|
||||
|
||||
📝 Found 1 update(s):
|
||||
- metatrader5: 2026-02-20
|
||||
|
||||
✅ Updated README.md
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Periodic Execution
|
||||
|
||||
Set up a cron job to run weekly:
|
||||
|
||||
```bash
|
||||
# Add to crontab (runs Monday at 2 AM)
|
||||
0 2 * * 1 cd /path/to/awesome-quant && ./.claude/skills/update-pypi-dates/scripts/update_pypi_dates.sh
|
||||
```
|
||||
|
||||
Or use Claude Code's scheduling:
|
||||
|
||||
```bash
|
||||
/loop 1w /update-pypi-dates
|
||||
```
|
||||
|
||||
## Files
|
||||
|
||||
- `SKILL.md` - Skill definition and documentation
|
||||
- `scripts/check_pypi_dates.py` - Main Python script
|
||||
- `scripts/update_pypi_dates.sh` - Bash wrapper with git integration
|
||||
- `README.md` - This file
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python 3.6+
|
||||
- Network access to PyPI API
|
||||
- Git (for automatic commits)
|
||||
|
||||
## Error Handling
|
||||
|
||||
- Network timeouts: Gracefully skipped with warning
|
||||
- Package not found: Skipped with message
|
||||
- API errors: Logged and continued with other packages
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
- [ ] Support for more PyPI packages
|
||||
- [ ] GitHub Actions workflow integration
|
||||
- [ ] Email notifications on updates
|
||||
- [ ] Comparison with published versions in README
|
||||
- [ ] Support for other package registries (npm, Ruby Gems, etc.)
|
||||
@@ -0,0 +1,66 @@
|
||||
---
|
||||
name: update-pypi-dates
|
||||
description: Check PyPI projects for last updated dates and update README.md entries. Use this skill to keep PyPI project information current with latest release dates from PyPI. Run periodically to maintain up-to-date metadata on Python packages listed in awesome-quant.
|
||||
---
|
||||
|
||||
# Update PyPI Dates
|
||||
|
||||
Automatically check PyPI projects for their latest update dates and update corresponding README.md entries with the "(Last updated: YYYY-MM-DD)" information.
|
||||
|
||||
## How it works
|
||||
|
||||
The skill maintains a list of PyPI projects in awesome-quant and:
|
||||
1. Queries the PyPI JSON API for each package
|
||||
2. Extracts the last release date
|
||||
3. Updates README.md entries with the new date if changed
|
||||
4. Commits changes to git if updates were made
|
||||
|
||||
## PyPI Projects to Track
|
||||
|
||||
Current projects tracked:
|
||||
- qfrm
|
||||
- chinesestockapi
|
||||
- tushare
|
||||
- metatrader5
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Fetch PyPI data for each project
|
||||
|
||||
For each PyPI project, query: `https://pypi.org/pypi/{package_name}/json`
|
||||
|
||||
Extract the last release date from the releases data.
|
||||
|
||||
### 2. Update README.md entries
|
||||
|
||||
For each project with a new date:
|
||||
- Find the entry in README.md
|
||||
- Update or add the "(Last updated: YYYY-MM-DD)" note
|
||||
- Use the exact entry format: `(Last updated: 2024-08-27)`
|
||||
|
||||
### 3. Verify changes
|
||||
|
||||
Show the user:
|
||||
- Which packages were checked
|
||||
- Which packages have new update dates
|
||||
- The differences (old date → new date)
|
||||
|
||||
### 4. Commit if changes detected
|
||||
|
||||
If any updates were made:
|
||||
```bash
|
||||
git add README.md non-github-urls.md
|
||||
git commit -m "Update PyPI project last updated dates"
|
||||
git push origin master
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
The user can:
|
||||
- Run the skill directly: `/update-pypi-dates`
|
||||
- Schedule it to run weekly/monthly via cron
|
||||
- Include it in CI/CD pipelines to keep data fresh
|
||||
|
||||
## Script
|
||||
|
||||
Use `scripts/check_pypi_dates.sh` for the core update logic.
|
||||
@@ -0,0 +1,154 @@
|
||||
#!/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())
|
||||
@@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
# Wrapper script to check PyPI dates and update README.md
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../../../.." && pwd)"
|
||||
|
||||
cd "$PROJECT_ROOT" || exit 1
|
||||
|
||||
echo "🚀 Starting PyPI date update check..."
|
||||
python3 "$SCRIPT_DIR/check_pypi_dates.py"
|
||||
exit_code=$?
|
||||
|
||||
if [ $exit_code -eq 0 ]; then
|
||||
# Check if there are any changes to commit
|
||||
if git diff --quiet README.md; then
|
||||
echo "✓ No changes needed"
|
||||
else
|
||||
echo ""
|
||||
echo "📝 Changes detected, committing..."
|
||||
git add README.md
|
||||
git commit -m "Update PyPI project last updated dates"
|
||||
git push origin master
|
||||
echo "✅ Changes pushed to remote"
|
||||
fi
|
||||
fi
|
||||
|
||||
exit $exit_code
|
||||
Reference in New Issue
Block a user