Add skills for managing PyPI project update dates and syncing README.md

This commit is contained in:
Wilson Freitas
2026-03-22 09:43:18 -03:00
parent 9405b48526
commit fc206ea4f3
6 changed files with 566 additions and 0 deletions
+132
View File
@@ -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.)
+66
View File
@@ -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