readmerator 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- readmerator-0.1.0/LICENSE +21 -0
- readmerator-0.1.0/MANIFEST.in +2 -0
- readmerator-0.1.0/PKG-INFO +161 -0
- readmerator-0.1.0/README.md +137 -0
- readmerator-0.1.0/pyproject.toml +36 -0
- readmerator-0.1.0/readmerator/__init__.py +3 -0
- readmerator-0.1.0/readmerator/__main__.py +6 -0
- readmerator-0.1.0/readmerator/cli.py +77 -0
- readmerator-0.1.0/readmerator/fetcher.py +126 -0
- readmerator-0.1.0/readmerator/parser.py +41 -0
- readmerator-0.1.0/readmerator.egg-info/PKG-INFO +161 -0
- readmerator-0.1.0/readmerator.egg-info/SOURCES.txt +16 -0
- readmerator-0.1.0/readmerator.egg-info/dependency_links.txt +1 -0
- readmerator-0.1.0/readmerator.egg-info/entry_points.txt +2 -0
- readmerator-0.1.0/readmerator.egg-info/requires.txt +1 -0
- readmerator-0.1.0/readmerator.egg-info/top_level.txt +1 -0
- readmerator-0.1.0/setup.cfg +4 -0
- readmerator-0.1.0/tests/test_parser.py +31 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Arved Klöhn
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: readmerator
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Fetch and cache README files for Python dependencies to use with AI assistants
|
|
5
|
+
Author: Arved Klöhn
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Redundando/readmerator
|
|
8
|
+
Project-URL: Repository, https://github.com/Redundando/readmerator
|
|
9
|
+
Keywords: ai,documentation,readme,pypi,github,context,assistant
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Requires-Python: >=3.8
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: aiohttp>=3.8.0
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
|
|
25
|
+
# readmerator
|
|
26
|
+
|
|
27
|
+
> Supercharge your AI coding assistant with instant access to all your dependency documentation.
|
|
28
|
+
|
|
29
|
+
Fetch and cache README files for Python dependencies, making them instantly available to AI assistants like Amazon Q, GitHub Copilot, and Cursor.
|
|
30
|
+
|
|
31
|
+
## Why?
|
|
32
|
+
|
|
33
|
+
AI coding assistants are powerful, but they don't automatically know about the packages you're using. You end up:
|
|
34
|
+
- Manually looking up documentation
|
|
35
|
+
- Copy-pasting docs into context
|
|
36
|
+
- Getting generic answers instead of package-specific help
|
|
37
|
+
|
|
38
|
+
**readmerator** solves this by automatically fetching all your dependency READMEs into a local folder that your AI can reference.
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install readmerator
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Quick Start
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# In your project directory
|
|
50
|
+
readmerator
|
|
51
|
+
|
|
52
|
+
# Then in your AI assistant
|
|
53
|
+
@folder .ai-docs
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
That's it! Your AI now has full context on all your dependencies.
|
|
57
|
+
|
|
58
|
+
## How It Works
|
|
59
|
+
|
|
60
|
+
1. **Finds** your `requirements.txt`
|
|
61
|
+
2. **Fetches** README files from PyPI and GitHub for each package
|
|
62
|
+
3. **Saves** them to `.ai-docs/` with metadata headers
|
|
63
|
+
4. **You reference** the folder in your AI assistant
|
|
64
|
+
|
|
65
|
+
## Usage
|
|
66
|
+
|
|
67
|
+
### Basic
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
readmerator
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### With Options
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Custom output directory
|
|
77
|
+
readmerator --output-dir docs/packages
|
|
78
|
+
|
|
79
|
+
# Specify requirements file
|
|
80
|
+
readmerator --source requirements.txt
|
|
81
|
+
|
|
82
|
+
# Verbose output (shows source: PyPI vs GitHub)
|
|
83
|
+
readmerator --verbose
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Example Output
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
$ readmerator --verbose
|
|
90
|
+
Found 16 packages in requirements.txt
|
|
91
|
+
Fetching READMEs to .ai-docs/
|
|
92
|
+
|
|
93
|
+
Fetching flask...
|
|
94
|
+
✓ flask: Saved (12453 bytes) from PyPI
|
|
95
|
+
Fetching fastapi...
|
|
96
|
+
✓ fastapi: Saved (23891 bytes) from GitHub
|
|
97
|
+
...
|
|
98
|
+
|
|
99
|
+
✓ Successfully fetched: 15
|
|
100
|
+
✗ Failed: 1
|
|
101
|
+
Failed packages: private-internal-package
|
|
102
|
+
|
|
103
|
+
READMEs saved to .ai-docs/
|
|
104
|
+
Use '@folder .ai-docs' in your AI assistant to include documentation
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Output Format
|
|
108
|
+
|
|
109
|
+
Each package gets a markdown file with metadata:
|
|
110
|
+
|
|
111
|
+
```markdown
|
|
112
|
+
---
|
|
113
|
+
Package: requests
|
|
114
|
+
Version: 2.32.5
|
|
115
|
+
Source: https://github.com/psf/requests
|
|
116
|
+
Fetched: 2024-01-15 10:30:00
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
# Requests
|
|
120
|
+
|
|
121
|
+
**Requests** is a simple, yet elegant, HTTP library.
|
|
122
|
+
...
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Features
|
|
126
|
+
|
|
127
|
+
- **Smart Fetching**: Tries PyPI first, falls back to GitHub
|
|
128
|
+
- **Fast**: Async/concurrent fetching
|
|
129
|
+
- **Reliable**: Graceful error handling for missing packages
|
|
130
|
+
- **Informative**: Progress indicators and detailed verbose mode
|
|
131
|
+
- **Lightweight**: Minimal dependencies (just aiohttp)
|
|
132
|
+
|
|
133
|
+
## AI Assistant Integration
|
|
134
|
+
|
|
135
|
+
### Amazon Q
|
|
136
|
+
```
|
|
137
|
+
@folder .ai-docs
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### GitHub Copilot
|
|
141
|
+
```
|
|
142
|
+
#file:.ai-docs/*
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Cursor
|
|
146
|
+
```
|
|
147
|
+
@Docs .ai-docs
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Requirements
|
|
151
|
+
|
|
152
|
+
- Python 3.8+
|
|
153
|
+
- aiohttp
|
|
154
|
+
|
|
155
|
+
## Contributing
|
|
156
|
+
|
|
157
|
+
Contributions welcome! Feel free to open issues or PRs on [GitHub](https://github.com/Redundando/readmerator).
|
|
158
|
+
|
|
159
|
+
## License
|
|
160
|
+
|
|
161
|
+
MIT © Arved Klöhn
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# readmerator
|
|
2
|
+
|
|
3
|
+
> Supercharge your AI coding assistant with instant access to all your dependency documentation.
|
|
4
|
+
|
|
5
|
+
Fetch and cache README files for Python dependencies, making them instantly available to AI assistants like Amazon Q, GitHub Copilot, and Cursor.
|
|
6
|
+
|
|
7
|
+
## Why?
|
|
8
|
+
|
|
9
|
+
AI coding assistants are powerful, but they don't automatically know about the packages you're using. You end up:
|
|
10
|
+
- Manually looking up documentation
|
|
11
|
+
- Copy-pasting docs into context
|
|
12
|
+
- Getting generic answers instead of package-specific help
|
|
13
|
+
|
|
14
|
+
**readmerator** solves this by automatically fetching all your dependency READMEs into a local folder that your AI can reference.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install readmerator
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# In your project directory
|
|
26
|
+
readmerator
|
|
27
|
+
|
|
28
|
+
# Then in your AI assistant
|
|
29
|
+
@folder .ai-docs
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
That's it! Your AI now has full context on all your dependencies.
|
|
33
|
+
|
|
34
|
+
## How It Works
|
|
35
|
+
|
|
36
|
+
1. **Finds** your `requirements.txt`
|
|
37
|
+
2. **Fetches** README files from PyPI and GitHub for each package
|
|
38
|
+
3. **Saves** them to `.ai-docs/` with metadata headers
|
|
39
|
+
4. **You reference** the folder in your AI assistant
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
### Basic
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
readmerator
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### With Options
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Custom output directory
|
|
53
|
+
readmerator --output-dir docs/packages
|
|
54
|
+
|
|
55
|
+
# Specify requirements file
|
|
56
|
+
readmerator --source requirements.txt
|
|
57
|
+
|
|
58
|
+
# Verbose output (shows source: PyPI vs GitHub)
|
|
59
|
+
readmerator --verbose
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Example Output
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
$ readmerator --verbose
|
|
66
|
+
Found 16 packages in requirements.txt
|
|
67
|
+
Fetching READMEs to .ai-docs/
|
|
68
|
+
|
|
69
|
+
Fetching flask...
|
|
70
|
+
✓ flask: Saved (12453 bytes) from PyPI
|
|
71
|
+
Fetching fastapi...
|
|
72
|
+
✓ fastapi: Saved (23891 bytes) from GitHub
|
|
73
|
+
...
|
|
74
|
+
|
|
75
|
+
✓ Successfully fetched: 15
|
|
76
|
+
✗ Failed: 1
|
|
77
|
+
Failed packages: private-internal-package
|
|
78
|
+
|
|
79
|
+
READMEs saved to .ai-docs/
|
|
80
|
+
Use '@folder .ai-docs' in your AI assistant to include documentation
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Output Format
|
|
84
|
+
|
|
85
|
+
Each package gets a markdown file with metadata:
|
|
86
|
+
|
|
87
|
+
```markdown
|
|
88
|
+
---
|
|
89
|
+
Package: requests
|
|
90
|
+
Version: 2.32.5
|
|
91
|
+
Source: https://github.com/psf/requests
|
|
92
|
+
Fetched: 2024-01-15 10:30:00
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
# Requests
|
|
96
|
+
|
|
97
|
+
**Requests** is a simple, yet elegant, HTTP library.
|
|
98
|
+
...
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Features
|
|
102
|
+
|
|
103
|
+
- **Smart Fetching**: Tries PyPI first, falls back to GitHub
|
|
104
|
+
- **Fast**: Async/concurrent fetching
|
|
105
|
+
- **Reliable**: Graceful error handling for missing packages
|
|
106
|
+
- **Informative**: Progress indicators and detailed verbose mode
|
|
107
|
+
- **Lightweight**: Minimal dependencies (just aiohttp)
|
|
108
|
+
|
|
109
|
+
## AI Assistant Integration
|
|
110
|
+
|
|
111
|
+
### Amazon Q
|
|
112
|
+
```
|
|
113
|
+
@folder .ai-docs
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### GitHub Copilot
|
|
117
|
+
```
|
|
118
|
+
#file:.ai-docs/*
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Cursor
|
|
122
|
+
```
|
|
123
|
+
@Docs .ai-docs
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Requirements
|
|
127
|
+
|
|
128
|
+
- Python 3.8+
|
|
129
|
+
- aiohttp
|
|
130
|
+
|
|
131
|
+
## Contributing
|
|
132
|
+
|
|
133
|
+
Contributions welcome! Feel free to open issues or PRs on [GitHub](https://github.com/Redundando/readmerator).
|
|
134
|
+
|
|
135
|
+
## License
|
|
136
|
+
|
|
137
|
+
MIT © Arved Klöhn
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "readmerator"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Fetch and cache README files for Python dependencies to use with AI assistants"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Arved Klöhn"}
|
|
14
|
+
]
|
|
15
|
+
keywords = ["ai", "documentation", "readme", "pypi", "github", "context", "assistant"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.8",
|
|
22
|
+
"Programming Language :: Python :: 3.9",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
]
|
|
27
|
+
dependencies = [
|
|
28
|
+
"aiohttp>=3.8.0",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
readmerator = "readmerator.cli:main"
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://github.com/Redundando/readmerator"
|
|
36
|
+
Repository = "https://github.com/Redundando/readmerator"
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Command-line interface for readmerator."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import argparse
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
from .parser import parse_requirements_txt, find_dependency_file
|
|
9
|
+
from .fetcher import fetch_all_readmes
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main():
|
|
13
|
+
"""Main CLI entry point."""
|
|
14
|
+
parser = argparse.ArgumentParser(
|
|
15
|
+
description="Fetch and cache README files for Python dependencies"
|
|
16
|
+
)
|
|
17
|
+
parser.add_argument(
|
|
18
|
+
"--output-dir",
|
|
19
|
+
type=Path,
|
|
20
|
+
default=Path(".ai-docs"),
|
|
21
|
+
help="Output directory for README files (default: .ai-docs)",
|
|
22
|
+
)
|
|
23
|
+
parser.add_argument(
|
|
24
|
+
"--source",
|
|
25
|
+
type=Path,
|
|
26
|
+
help="Path to requirements.txt (default: auto-detect)",
|
|
27
|
+
)
|
|
28
|
+
parser.add_argument(
|
|
29
|
+
"--verbose",
|
|
30
|
+
"-v",
|
|
31
|
+
action="store_true",
|
|
32
|
+
help="Show detailed progress",
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
args = parser.parse_args()
|
|
36
|
+
|
|
37
|
+
# Find dependency file
|
|
38
|
+
if args.source:
|
|
39
|
+
dep_file = args.source
|
|
40
|
+
if not dep_file.exists():
|
|
41
|
+
print(f"Error: {dep_file} not found", file=sys.stderr)
|
|
42
|
+
sys.exit(1)
|
|
43
|
+
else:
|
|
44
|
+
dep_file = find_dependency_file(Path.cwd())
|
|
45
|
+
if not dep_file:
|
|
46
|
+
print("Error: No requirements.txt found in current directory", file=sys.stderr)
|
|
47
|
+
sys.exit(1)
|
|
48
|
+
|
|
49
|
+
# Parse dependencies
|
|
50
|
+
packages = parse_requirements_txt(dep_file)
|
|
51
|
+
if not packages:
|
|
52
|
+
print(f"No packages found in {dep_file}")
|
|
53
|
+
sys.exit(0)
|
|
54
|
+
|
|
55
|
+
print(f"Found {len(packages)} packages in {dep_file}")
|
|
56
|
+
print(f"Fetching READMEs to {args.output_dir}/")
|
|
57
|
+
|
|
58
|
+
# Fetch READMEs
|
|
59
|
+
results = asyncio.run(fetch_all_readmes(packages, args.output_dir, args.verbose))
|
|
60
|
+
|
|
61
|
+
# Summary
|
|
62
|
+
success_count = sum(1 for v in results.values() if v)
|
|
63
|
+
fail_count = len(results) - success_count
|
|
64
|
+
|
|
65
|
+
print(f"\n✓ Successfully fetched: {success_count}")
|
|
66
|
+
if fail_count > 0:
|
|
67
|
+
print(f"✗ Failed: {fail_count}")
|
|
68
|
+
if not args.verbose:
|
|
69
|
+
failed = [pkg for pkg, success in results.items() if not success]
|
|
70
|
+
print(f" Failed packages: {', '.join(failed)}")
|
|
71
|
+
|
|
72
|
+
print(f"\nREADMEs saved to {args.output_dir}/")
|
|
73
|
+
print(f"Use '@folder {args.output_dir}' in your AI assistant to include documentation")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
if __name__ == "__main__":
|
|
77
|
+
main()
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""Core functionality for fetching package READMEs."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import re
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Optional, Dict, List
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
import aiohttp
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
async def fetch_pypi_metadata(session: aiohttp.ClientSession, package: str) -> Optional[Dict]:
|
|
12
|
+
"""Fetch package metadata from PyPI."""
|
|
13
|
+
url = f"https://pypi.org/pypi/{package}/json"
|
|
14
|
+
try:
|
|
15
|
+
async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as resp:
|
|
16
|
+
if resp.status == 200:
|
|
17
|
+
return await resp.json()
|
|
18
|
+
except Exception:
|
|
19
|
+
pass
|
|
20
|
+
return None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
async def fetch_github_readme(session: aiohttp.ClientSession, repo_url: str) -> Optional[str]:
|
|
24
|
+
"""Fetch README from GitHub repository."""
|
|
25
|
+
match = re.search(r"github\.com/([^/]+)/([^/]+)", repo_url)
|
|
26
|
+
if not match:
|
|
27
|
+
return None
|
|
28
|
+
|
|
29
|
+
owner, repo = match.groups()
|
|
30
|
+
repo = repo.rstrip("/").removesuffix(".git")
|
|
31
|
+
|
|
32
|
+
for branch in ["main", "master"]:
|
|
33
|
+
url = f"https://raw.githubusercontent.com/{owner}/{repo}/{branch}/README.md"
|
|
34
|
+
try:
|
|
35
|
+
async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as resp:
|
|
36
|
+
if resp.status == 200:
|
|
37
|
+
return await resp.text()
|
|
38
|
+
except Exception:
|
|
39
|
+
continue
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
async def fetch_package_readme(session: aiohttp.ClientSession, package: str) -> Optional[tuple[str, str, str, str]]:
|
|
44
|
+
"""Fetch README for a package. Returns (content, version, source_url, source_type)."""
|
|
45
|
+
metadata = await fetch_pypi_metadata(session, package)
|
|
46
|
+
if not metadata:
|
|
47
|
+
return None
|
|
48
|
+
|
|
49
|
+
info = metadata.get("info", {})
|
|
50
|
+
version = info.get("version", "unknown")
|
|
51
|
+
|
|
52
|
+
# Try PyPI long_description first
|
|
53
|
+
description = info.get("description", "")
|
|
54
|
+
if description and len(description) > 100:
|
|
55
|
+
pypi_url = f"https://pypi.org/project/{package}/"
|
|
56
|
+
return (description, version, pypi_url, "PyPI")
|
|
57
|
+
|
|
58
|
+
# Try GitHub README
|
|
59
|
+
project_urls = info.get("project_urls", {})
|
|
60
|
+
for key in ["Source", "Homepage", "Repository", "GitHub"]:
|
|
61
|
+
url = project_urls.get(key, "")
|
|
62
|
+
if "github.com" in url:
|
|
63
|
+
readme = await fetch_github_readme(session, url)
|
|
64
|
+
if readme:
|
|
65
|
+
return (readme, version, url, "GitHub")
|
|
66
|
+
|
|
67
|
+
# Fallback to short description
|
|
68
|
+
summary = info.get("summary", "")
|
|
69
|
+
if summary:
|
|
70
|
+
pypi_url = f"https://pypi.org/project/{package}/"
|
|
71
|
+
return (f"# {package}\n\n{summary}\n\nSee: {pypi_url}", version, pypi_url, "PyPI summary")
|
|
72
|
+
|
|
73
|
+
return None
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def create_readme_content(package: str, content: str, version: str, source_url: str) -> str:
|
|
77
|
+
"""Create formatted README with metadata header."""
|
|
78
|
+
header = f"""---
|
|
79
|
+
Package: {package}
|
|
80
|
+
Version: {version}
|
|
81
|
+
Source: {source_url}
|
|
82
|
+
Fetched: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
"""
|
|
86
|
+
return header + content
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
async def fetch_all_readmes(packages: List[str], output_dir: Path, verbose: bool = False) -> Dict[str, bool]:
|
|
90
|
+
"""Fetch READMEs for all packages. Returns dict of package: success."""
|
|
91
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
92
|
+
results = {}
|
|
93
|
+
|
|
94
|
+
async with aiohttp.ClientSession() as session:
|
|
95
|
+
tasks = []
|
|
96
|
+
for package in packages:
|
|
97
|
+
tasks.append(fetch_and_save(session, package, output_dir, verbose))
|
|
98
|
+
|
|
99
|
+
results_list = await asyncio.gather(*tasks)
|
|
100
|
+
for package, success in results_list:
|
|
101
|
+
results[package] = success
|
|
102
|
+
|
|
103
|
+
return results
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
async def fetch_and_save(session: aiohttp.ClientSession, package: str, output_dir: Path, verbose: bool) -> tuple[str, bool]:
|
|
107
|
+
"""Fetch and save README for a single package."""
|
|
108
|
+
if verbose:
|
|
109
|
+
print(f"Fetching {package}...")
|
|
110
|
+
|
|
111
|
+
result = await fetch_package_readme(session, package)
|
|
112
|
+
if not result:
|
|
113
|
+
if verbose:
|
|
114
|
+
print(f" ✗ {package}: Failed to fetch")
|
|
115
|
+
return (package, False)
|
|
116
|
+
|
|
117
|
+
content, version, source_url, source_type = result
|
|
118
|
+
readme_content = create_readme_content(package, content, version, source_url)
|
|
119
|
+
|
|
120
|
+
output_file = output_dir / f"{package}.md"
|
|
121
|
+
output_file.write_text(readme_content, encoding="utf-8")
|
|
122
|
+
|
|
123
|
+
if verbose:
|
|
124
|
+
print(f" ✓ {package}: Saved ({len(content)} bytes) from {source_type}")
|
|
125
|
+
|
|
126
|
+
return (package, True)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Parse Python dependency files."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import List, Set
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def parse_requirements_txt(file_path: Path) -> List[str]:
|
|
9
|
+
"""Parse requirements.txt and extract package names."""
|
|
10
|
+
packages: Set[str] = set()
|
|
11
|
+
|
|
12
|
+
if not file_path.exists():
|
|
13
|
+
return []
|
|
14
|
+
|
|
15
|
+
content = file_path.read_text(encoding="utf-8")
|
|
16
|
+
|
|
17
|
+
for line in content.splitlines():
|
|
18
|
+
line = line.strip()
|
|
19
|
+
|
|
20
|
+
# Skip comments and empty lines
|
|
21
|
+
if not line or line.startswith("#"):
|
|
22
|
+
continue
|
|
23
|
+
|
|
24
|
+
# Skip -r, -e, --hash, etc.
|
|
25
|
+
if line.startswith("-"):
|
|
26
|
+
continue
|
|
27
|
+
|
|
28
|
+
# Extract package name (before any version specifier)
|
|
29
|
+
match = re.match(r"^([a-zA-Z0-9_-]+)", line)
|
|
30
|
+
if match:
|
|
31
|
+
packages.add(match.group(1).lower())
|
|
32
|
+
|
|
33
|
+
return sorted(packages)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def find_dependency_file(directory: Path) -> Path | None:
|
|
37
|
+
"""Find requirements.txt in directory."""
|
|
38
|
+
req_file = directory / "requirements.txt"
|
|
39
|
+
if req_file.exists():
|
|
40
|
+
return req_file
|
|
41
|
+
return None
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: readmerator
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Fetch and cache README files for Python dependencies to use with AI assistants
|
|
5
|
+
Author: Arved Klöhn
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Redundando/readmerator
|
|
8
|
+
Project-URL: Repository, https://github.com/Redundando/readmerator
|
|
9
|
+
Keywords: ai,documentation,readme,pypi,github,context,assistant
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Requires-Python: >=3.8
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: aiohttp>=3.8.0
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
|
|
25
|
+
# readmerator
|
|
26
|
+
|
|
27
|
+
> Supercharge your AI coding assistant with instant access to all your dependency documentation.
|
|
28
|
+
|
|
29
|
+
Fetch and cache README files for Python dependencies, making them instantly available to AI assistants like Amazon Q, GitHub Copilot, and Cursor.
|
|
30
|
+
|
|
31
|
+
## Why?
|
|
32
|
+
|
|
33
|
+
AI coding assistants are powerful, but they don't automatically know about the packages you're using. You end up:
|
|
34
|
+
- Manually looking up documentation
|
|
35
|
+
- Copy-pasting docs into context
|
|
36
|
+
- Getting generic answers instead of package-specific help
|
|
37
|
+
|
|
38
|
+
**readmerator** solves this by automatically fetching all your dependency READMEs into a local folder that your AI can reference.
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install readmerator
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Quick Start
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# In your project directory
|
|
50
|
+
readmerator
|
|
51
|
+
|
|
52
|
+
# Then in your AI assistant
|
|
53
|
+
@folder .ai-docs
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
That's it! Your AI now has full context on all your dependencies.
|
|
57
|
+
|
|
58
|
+
## How It Works
|
|
59
|
+
|
|
60
|
+
1. **Finds** your `requirements.txt`
|
|
61
|
+
2. **Fetches** README files from PyPI and GitHub for each package
|
|
62
|
+
3. **Saves** them to `.ai-docs/` with metadata headers
|
|
63
|
+
4. **You reference** the folder in your AI assistant
|
|
64
|
+
|
|
65
|
+
## Usage
|
|
66
|
+
|
|
67
|
+
### Basic
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
readmerator
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### With Options
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Custom output directory
|
|
77
|
+
readmerator --output-dir docs/packages
|
|
78
|
+
|
|
79
|
+
# Specify requirements file
|
|
80
|
+
readmerator --source requirements.txt
|
|
81
|
+
|
|
82
|
+
# Verbose output (shows source: PyPI vs GitHub)
|
|
83
|
+
readmerator --verbose
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Example Output
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
$ readmerator --verbose
|
|
90
|
+
Found 16 packages in requirements.txt
|
|
91
|
+
Fetching READMEs to .ai-docs/
|
|
92
|
+
|
|
93
|
+
Fetching flask...
|
|
94
|
+
✓ flask: Saved (12453 bytes) from PyPI
|
|
95
|
+
Fetching fastapi...
|
|
96
|
+
✓ fastapi: Saved (23891 bytes) from GitHub
|
|
97
|
+
...
|
|
98
|
+
|
|
99
|
+
✓ Successfully fetched: 15
|
|
100
|
+
✗ Failed: 1
|
|
101
|
+
Failed packages: private-internal-package
|
|
102
|
+
|
|
103
|
+
READMEs saved to .ai-docs/
|
|
104
|
+
Use '@folder .ai-docs' in your AI assistant to include documentation
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Output Format
|
|
108
|
+
|
|
109
|
+
Each package gets a markdown file with metadata:
|
|
110
|
+
|
|
111
|
+
```markdown
|
|
112
|
+
---
|
|
113
|
+
Package: requests
|
|
114
|
+
Version: 2.32.5
|
|
115
|
+
Source: https://github.com/psf/requests
|
|
116
|
+
Fetched: 2024-01-15 10:30:00
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
# Requests
|
|
120
|
+
|
|
121
|
+
**Requests** is a simple, yet elegant, HTTP library.
|
|
122
|
+
...
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Features
|
|
126
|
+
|
|
127
|
+
- **Smart Fetching**: Tries PyPI first, falls back to GitHub
|
|
128
|
+
- **Fast**: Async/concurrent fetching
|
|
129
|
+
- **Reliable**: Graceful error handling for missing packages
|
|
130
|
+
- **Informative**: Progress indicators and detailed verbose mode
|
|
131
|
+
- **Lightweight**: Minimal dependencies (just aiohttp)
|
|
132
|
+
|
|
133
|
+
## AI Assistant Integration
|
|
134
|
+
|
|
135
|
+
### Amazon Q
|
|
136
|
+
```
|
|
137
|
+
@folder .ai-docs
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### GitHub Copilot
|
|
141
|
+
```
|
|
142
|
+
#file:.ai-docs/*
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Cursor
|
|
146
|
+
```
|
|
147
|
+
@Docs .ai-docs
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Requirements
|
|
151
|
+
|
|
152
|
+
- Python 3.8+
|
|
153
|
+
- aiohttp
|
|
154
|
+
|
|
155
|
+
## Contributing
|
|
156
|
+
|
|
157
|
+
Contributions welcome! Feel free to open issues or PRs on [GitHub](https://github.com/Redundando/readmerator).
|
|
158
|
+
|
|
159
|
+
## License
|
|
160
|
+
|
|
161
|
+
MIT © Arved Klöhn
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
readmerator/__init__.py
|
|
6
|
+
readmerator/__main__.py
|
|
7
|
+
readmerator/cli.py
|
|
8
|
+
readmerator/fetcher.py
|
|
9
|
+
readmerator/parser.py
|
|
10
|
+
readmerator.egg-info/PKG-INFO
|
|
11
|
+
readmerator.egg-info/SOURCES.txt
|
|
12
|
+
readmerator.egg-info/dependency_links.txt
|
|
13
|
+
readmerator.egg-info/entry_points.txt
|
|
14
|
+
readmerator.egg-info/requires.txt
|
|
15
|
+
readmerator.egg-info/top_level.txt
|
|
16
|
+
tests/test_parser.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
aiohttp>=3.8.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
readmerator
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Basic tests for readmerator."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from readmerator.parser import parse_requirements_txt
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_parse_requirements():
|
|
8
|
+
"""Test parsing a simple requirements file."""
|
|
9
|
+
test_file = Path("test_req.txt")
|
|
10
|
+
test_file.write_text("requests>=2.0.0\nclick==8.0.0\n# comment\naiohttp")
|
|
11
|
+
|
|
12
|
+
packages = parse_requirements_txt(test_file)
|
|
13
|
+
|
|
14
|
+
assert "requests" in packages
|
|
15
|
+
assert "click" in packages
|
|
16
|
+
assert "aiohttp" in packages
|
|
17
|
+
assert len(packages) == 3
|
|
18
|
+
|
|
19
|
+
test_file.unlink()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_parse_empty_file():
|
|
23
|
+
"""Test parsing empty requirements file."""
|
|
24
|
+
test_file = Path("empty_req.txt")
|
|
25
|
+
test_file.write_text("# only comments\n\n")
|
|
26
|
+
|
|
27
|
+
packages = parse_requirements_txt(test_file)
|
|
28
|
+
|
|
29
|
+
assert len(packages) == 0
|
|
30
|
+
|
|
31
|
+
test_file.unlink()
|