codeshift 0.3.2__tar.gz → 0.3.4__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.
- {codeshift-0.3.2 → codeshift-0.3.4}/PKG-INFO +46 -4
- {codeshift-0.3.2 → codeshift-0.3.4}/README.md +45 -3
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/cli/commands/apply.py +24 -2
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/cli/commands/upgrade_all.py +4 -1
- codeshift-0.3.4/codeshift/cli/package_manager.py +102 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/knowledge/generator.py +11 -1
- codeshift-0.3.4/codeshift/knowledge_base/libraries/aiohttp.yaml +186 -0
- codeshift-0.3.4/codeshift/knowledge_base/libraries/attrs.yaml +181 -0
- codeshift-0.3.4/codeshift/knowledge_base/libraries/celery.yaml +244 -0
- codeshift-0.3.4/codeshift/knowledge_base/libraries/click.yaml +195 -0
- codeshift-0.3.4/codeshift/knowledge_base/libraries/django.yaml +355 -0
- codeshift-0.3.4/codeshift/knowledge_base/libraries/flask.yaml +270 -0
- codeshift-0.3.4/codeshift/knowledge_base/libraries/httpx.yaml +183 -0
- codeshift-0.3.4/codeshift/knowledge_base/libraries/marshmallow.yaml +238 -0
- codeshift-0.3.4/codeshift/knowledge_base/libraries/numpy.yaml +429 -0
- codeshift-0.3.4/codeshift/knowledge_base/libraries/pytest.yaml +192 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/knowledge_base/libraries/sqlalchemy.yaml +2 -1
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/migrator/engine.py +60 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/migrator/transforms/__init__.py +2 -0
- codeshift-0.3.4/codeshift/migrator/transforms/aiohttp_transformer.py +608 -0
- codeshift-0.3.4/codeshift/migrator/transforms/attrs_transformer.py +570 -0
- codeshift-0.3.4/codeshift/migrator/transforms/celery_transformer.py +546 -0
- codeshift-0.3.4/codeshift/migrator/transforms/click_transformer.py +526 -0
- codeshift-0.3.4/codeshift/migrator/transforms/django_transformer.py +852 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/migrator/transforms/fastapi_transformer.py +12 -7
- codeshift-0.3.4/codeshift/migrator/transforms/flask_transformer.py +505 -0
- codeshift-0.3.4/codeshift/migrator/transforms/httpx_transformer.py +419 -0
- codeshift-0.3.4/codeshift/migrator/transforms/marshmallow_transformer.py +515 -0
- codeshift-0.3.4/codeshift/migrator/transforms/numpy_transformer.py +413 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/migrator/transforms/pydantic_v1_to_v2.py +53 -8
- codeshift-0.3.4/codeshift/migrator/transforms/pytest_transformer.py +351 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/migrator/transforms/requests_transformer.py +74 -1
- codeshift-0.3.4/codeshift/migrator/transforms/sqlalchemy_transformer.py +828 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/scanner/dependency_parser.py +1 -1
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift.egg-info/PKG-INFO +46 -4
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift.egg-info/SOURCES.txt +31 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/pyproject.toml +1 -1
- codeshift-0.3.4/tests/test_aiohttp_transforms.py +197 -0
- codeshift-0.3.4/tests/test_attrs_transforms.py +296 -0
- codeshift-0.3.4/tests/test_celery_transforms.py +212 -0
- codeshift-0.3.4/tests/test_click_transforms.py +211 -0
- codeshift-0.3.4/tests/test_django_transforms.py +235 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/tests/test_fastapi_transforms.py +82 -8
- codeshift-0.3.4/tests/test_flask_transforms.py +206 -0
- codeshift-0.3.4/tests/test_httpx_transforms.py +207 -0
- codeshift-0.3.4/tests/test_marshmallow_transforms.py +487 -0
- codeshift-0.3.4/tests/test_numpy_transforms.py +421 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/tests/test_pydantic_transforms.py +93 -0
- codeshift-0.3.4/tests/test_pytest_transforms.py +439 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/tests/test_requests_transforms.py +36 -0
- codeshift-0.3.4/tests/test_sqlalchemy_transforms.py +588 -0
- codeshift-0.3.2/codeshift/migrator/transforms/sqlalchemy_transformer.py +0 -175
- codeshift-0.3.2/tests/test_sqlalchemy_transforms.py +0 -97
- {codeshift-0.3.2 → codeshift-0.3.4}/LICENSE +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/__init__.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/analyzer/__init__.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/analyzer/risk_assessor.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/api/__init__.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/api/auth.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/api/config.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/api/database.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/api/main.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/api/models/__init__.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/api/models/auth.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/api/models/billing.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/api/models/migrate.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/api/models/usage.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/api/routers/__init__.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/api/routers/auth.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/api/routers/billing.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/api/routers/migrate.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/api/routers/usage.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/api/routers/webhooks.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/cli/__init__.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/cli/commands/__init__.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/cli/commands/auth.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/cli/commands/diff.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/cli/commands/scan.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/cli/commands/upgrade.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/cli/main.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/cli/quota.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/knowledge/__init__.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/knowledge/cache.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/knowledge/models.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/knowledge/parser.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/knowledge/sources.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/knowledge_base/__init__.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/knowledge_base/libraries/fastapi.yaml +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/knowledge_base/libraries/pandas.yaml +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/knowledge_base/libraries/pydantic.yaml +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/knowledge_base/libraries/requests.yaml +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/knowledge_base/loader.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/knowledge_base/models.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/migrator/__init__.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/migrator/ast_transforms.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/migrator/llm_migrator.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/migrator/transforms/pandas_transformer.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/scanner/__init__.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/scanner/code_scanner.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/utils/__init__.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/utils/api_client.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/utils/cache.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/utils/config.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/utils/llm_client.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/validator/__init__.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/validator/syntax_checker.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift/validator/test_runner.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift.egg-info/dependency_links.txt +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift.egg-info/entry_points.txt +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift.egg-info/requires.txt +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/codeshift.egg-info/top_level.txt +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/setup.cfg +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/tests/test_code_scanner.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/tests/test_knowledge_base.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/tests/test_pandas_transforms.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/tests/test_risk_assessor.py +0 -0
- {codeshift-0.3.2 → codeshift-0.3.4}/tests/test_syntax_checker.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codeshift
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: AI-powered CLI tool that migrates Python code to handle breaking dependency changes
|
|
5
5
|
Author: PyResolve Team
|
|
6
6
|
License: MIT
|
|
@@ -84,6 +84,16 @@ PyResolve is an AI-powered CLI tool that migrates Python code to handle breaking
|
|
|
84
84
|
| SQLAlchemy | 1.4 → 2.0 | ✅ Supported |
|
|
85
85
|
| Pandas | 1.x → 2.x | ✅ Supported |
|
|
86
86
|
| Requests | Various | ✅ Supported |
|
|
87
|
+
| Django | 3.x → 4.x/5.x | ✅ Supported |
|
|
88
|
+
| Flask | 1.x → 2.x/3.x | ✅ Supported |
|
|
89
|
+
| NumPy | 1.x → 2.x | ✅ Supported |
|
|
90
|
+
| attrs | attr → attrs | ✅ Supported |
|
|
91
|
+
| Celery | 4.x → 5.x | ✅ Supported |
|
|
92
|
+
| Click | 7.x → 8.x | ✅ Supported |
|
|
93
|
+
| aiohttp | 2.x → 3.x | ✅ Supported |
|
|
94
|
+
| httpx | 0.x → 0.24+ | ✅ Supported |
|
|
95
|
+
| Marshmallow | 2.x → 3.x | ✅ Supported |
|
|
96
|
+
| pytest | 6.x → 7.x/8.x | ✅ Supported |
|
|
87
97
|
|
|
88
98
|
### Any Library (Auto-Generated Knowledge Base)
|
|
89
99
|
|
|
@@ -104,7 +114,10 @@ pyresolve scan
|
|
|
104
114
|
# Scan with detailed breaking change analysis
|
|
105
115
|
pyresolve scan --fetch-changes
|
|
106
116
|
|
|
107
|
-
#
|
|
117
|
+
# Upgrade all outdated packages at once
|
|
118
|
+
pyresolve upgrade-all
|
|
119
|
+
|
|
120
|
+
# Or analyze and propose changes for a specific library
|
|
108
121
|
pyresolve upgrade pydantic --target 2.5.0
|
|
109
122
|
|
|
110
123
|
# View detailed diff of proposed changes
|
|
@@ -231,6 +244,35 @@ pyresolve apply
|
|
|
231
244
|
# --file, -f Apply changes to specific file only
|
|
232
245
|
```
|
|
233
246
|
|
|
247
|
+
### Upgrade-All Command
|
|
248
|
+
|
|
249
|
+
Upgrade all outdated packages to their latest versions in one go:
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
pyresolve upgrade-all
|
|
253
|
+
|
|
254
|
+
# Options:
|
|
255
|
+
# --all, -a Include all outdated packages (not just Tier 1)
|
|
256
|
+
# --path, -p Path to analyze (default: current directory)
|
|
257
|
+
# --dry-run Show what would be changed without saving state
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Libraries Command
|
|
261
|
+
|
|
262
|
+
List all supported libraries and their migration paths:
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
pyresolve libraries
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Status Command
|
|
269
|
+
|
|
270
|
+
Show current migration status, pending changes, and quota information:
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
pyresolve status
|
|
274
|
+
```
|
|
275
|
+
|
|
234
276
|
## How It Works
|
|
235
277
|
|
|
236
278
|
```text
|
|
@@ -261,7 +303,7 @@ pyresolve apply
|
|
|
261
303
|
2. **Parse Changes**: Uses LLM to extract breaking changes with confidence levels (HIGH/MEDIUM/LOW)
|
|
262
304
|
3. **Scan Codebase**: Finds imports and usage of the target library
|
|
263
305
|
4. **Tiered Migration**:
|
|
264
|
-
- **Tier 1**: Deterministic AST transforms for
|
|
306
|
+
- **Tier 1**: Deterministic AST transforms for 15 supported libraries (Pydantic, FastAPI, SQLAlchemy, Django, Flask, NumPy, Pandas, Requests, attrs, Celery, Click, aiohttp, httpx, Marshmallow, pytest)
|
|
265
307
|
- **Tier 2**: Knowledge base guided migration with LLM assistance
|
|
266
308
|
- **Tier 3**: Pure LLM migration for unknown patterns
|
|
267
309
|
5. **Validate**: Runs syntax checks and optionally your test suite
|
|
@@ -303,7 +345,7 @@ PyResolve uses a tiered pricing model:
|
|
|
303
345
|
|
|
304
346
|
| Tier | Price | Features |
|
|
305
347
|
|------|-------|----------|
|
|
306
|
-
| **Free** | $0/month | Tier 1 deterministic transforms (Pydantic,
|
|
348
|
+
| **Free** | $0/month | Tier 1 deterministic transforms (15 libraries including Pydantic, Django, Flask, SQLAlchemy, and more) |
|
|
307
349
|
| **Pro** | $19/month | Tier 2 KB-guided LLM migrations for any library |
|
|
308
350
|
| **Unlimited** | $49/month | Tier 3 pure LLM migrations + priority support |
|
|
309
351
|
|
|
@@ -28,6 +28,16 @@ PyResolve is an AI-powered CLI tool that migrates Python code to handle breaking
|
|
|
28
28
|
| SQLAlchemy | 1.4 → 2.0 | ✅ Supported |
|
|
29
29
|
| Pandas | 1.x → 2.x | ✅ Supported |
|
|
30
30
|
| Requests | Various | ✅ Supported |
|
|
31
|
+
| Django | 3.x → 4.x/5.x | ✅ Supported |
|
|
32
|
+
| Flask | 1.x → 2.x/3.x | ✅ Supported |
|
|
33
|
+
| NumPy | 1.x → 2.x | ✅ Supported |
|
|
34
|
+
| attrs | attr → attrs | ✅ Supported |
|
|
35
|
+
| Celery | 4.x → 5.x | ✅ Supported |
|
|
36
|
+
| Click | 7.x → 8.x | ✅ Supported |
|
|
37
|
+
| aiohttp | 2.x → 3.x | ✅ Supported |
|
|
38
|
+
| httpx | 0.x → 0.24+ | ✅ Supported |
|
|
39
|
+
| Marshmallow | 2.x → 3.x | ✅ Supported |
|
|
40
|
+
| pytest | 6.x → 7.x/8.x | ✅ Supported |
|
|
31
41
|
|
|
32
42
|
### Any Library (Auto-Generated Knowledge Base)
|
|
33
43
|
|
|
@@ -48,7 +58,10 @@ pyresolve scan
|
|
|
48
58
|
# Scan with detailed breaking change analysis
|
|
49
59
|
pyresolve scan --fetch-changes
|
|
50
60
|
|
|
51
|
-
#
|
|
61
|
+
# Upgrade all outdated packages at once
|
|
62
|
+
pyresolve upgrade-all
|
|
63
|
+
|
|
64
|
+
# Or analyze and propose changes for a specific library
|
|
52
65
|
pyresolve upgrade pydantic --target 2.5.0
|
|
53
66
|
|
|
54
67
|
# View detailed diff of proposed changes
|
|
@@ -175,6 +188,35 @@ pyresolve apply
|
|
|
175
188
|
# --file, -f Apply changes to specific file only
|
|
176
189
|
```
|
|
177
190
|
|
|
191
|
+
### Upgrade-All Command
|
|
192
|
+
|
|
193
|
+
Upgrade all outdated packages to their latest versions in one go:
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
pyresolve upgrade-all
|
|
197
|
+
|
|
198
|
+
# Options:
|
|
199
|
+
# --all, -a Include all outdated packages (not just Tier 1)
|
|
200
|
+
# --path, -p Path to analyze (default: current directory)
|
|
201
|
+
# --dry-run Show what would be changed without saving state
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Libraries Command
|
|
205
|
+
|
|
206
|
+
List all supported libraries and their migration paths:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
pyresolve libraries
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Status Command
|
|
213
|
+
|
|
214
|
+
Show current migration status, pending changes, and quota information:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
pyresolve status
|
|
218
|
+
```
|
|
219
|
+
|
|
178
220
|
## How It Works
|
|
179
221
|
|
|
180
222
|
```text
|
|
@@ -205,7 +247,7 @@ pyresolve apply
|
|
|
205
247
|
2. **Parse Changes**: Uses LLM to extract breaking changes with confidence levels (HIGH/MEDIUM/LOW)
|
|
206
248
|
3. **Scan Codebase**: Finds imports and usage of the target library
|
|
207
249
|
4. **Tiered Migration**:
|
|
208
|
-
- **Tier 1**: Deterministic AST transforms for
|
|
250
|
+
- **Tier 1**: Deterministic AST transforms for 15 supported libraries (Pydantic, FastAPI, SQLAlchemy, Django, Flask, NumPy, Pandas, Requests, attrs, Celery, Click, aiohttp, httpx, Marshmallow, pytest)
|
|
209
251
|
- **Tier 2**: Knowledge base guided migration with LLM assistance
|
|
210
252
|
- **Tier 3**: Pure LLM migration for unknown patterns
|
|
211
253
|
5. **Validate**: Runs syntax checks and optionally your test suite
|
|
@@ -247,7 +289,7 @@ PyResolve uses a tiered pricing model:
|
|
|
247
289
|
|
|
248
290
|
| Tier | Price | Features |
|
|
249
291
|
|------|-------|----------|
|
|
250
|
-
| **Free** | $0/month | Tier 1 deterministic transforms (Pydantic,
|
|
292
|
+
| **Free** | $0/month | Tier 1 deterministic transforms (15 libraries including Pydantic, Django, Flask, SQLAlchemy, and more) |
|
|
251
293
|
| **Pro** | $19/month | Tier 2 KB-guided LLM migrations for any library |
|
|
252
294
|
| **Unlimited** | $49/month | Tier 3 pure LLM migrations + priority support |
|
|
253
295
|
|
|
@@ -10,6 +10,7 @@ from rich.panel import Panel
|
|
|
10
10
|
from rich.prompt import Confirm
|
|
11
11
|
|
|
12
12
|
from codeshift.cli.commands.upgrade import load_state, save_state
|
|
13
|
+
from codeshift.cli.package_manager import get_install_commands, get_sync_command
|
|
13
14
|
from codeshift.cli.quota import (
|
|
14
15
|
QuotaError,
|
|
15
16
|
check_quota,
|
|
@@ -226,11 +227,32 @@ def apply(
|
|
|
226
227
|
state_file.unlink()
|
|
227
228
|
console.print("\n[green]Migration complete![/]")
|
|
228
229
|
|
|
229
|
-
# Next steps
|
|
230
|
+
# Next steps - generate dynamic dependency sync command
|
|
230
231
|
console.print("\n[bold]Recommended next steps:[/]")
|
|
231
232
|
console.print(" 1. Review the changes in your editor")
|
|
232
233
|
console.print(" 2. Run your test suite: [cyan]pytest[/]")
|
|
233
|
-
|
|
234
|
+
|
|
235
|
+
# Generate dependency update commands based on library/libraries and package manager
|
|
236
|
+
sync_command = get_sync_command(project_path)
|
|
237
|
+
|
|
238
|
+
# Check if this is a multi-library migration (upgrade-all)
|
|
239
|
+
migrations = state.get("migrations", [])
|
|
240
|
+
if library == "multiple" and migrations:
|
|
241
|
+
# Multi-library case: show sync command and list all libraries
|
|
242
|
+
console.print(f" 3. Sync your dependencies: [cyan]{sync_command}[/]")
|
|
243
|
+
console.print("\n [dim]Upgraded libraries:[/]")
|
|
244
|
+
for migration in migrations:
|
|
245
|
+
lib_name = migration.get("library", "unknown")
|
|
246
|
+
to_version = migration.get("to_version", "unknown")
|
|
247
|
+
console.print(f" • {lib_name} → {to_version}")
|
|
248
|
+
else:
|
|
249
|
+
# Single library case: show sync command with specific library info
|
|
250
|
+
console.print(f" 3. Sync your dependencies: [cyan]{sync_command}[/]")
|
|
251
|
+
if library != "unknown" and target_version != "unknown":
|
|
252
|
+
libraries = [{"name": library, "version": target_version}]
|
|
253
|
+
install_commands = get_install_commands(project_path, libraries)
|
|
254
|
+
if install_commands:
|
|
255
|
+
console.print(f"\n [dim]Or install directly:[/] {install_commands[0]}")
|
|
234
256
|
|
|
235
257
|
|
|
236
258
|
@click.command()
|
|
@@ -257,6 +257,7 @@ def upgrade_all(
|
|
|
257
257
|
BarColumn(),
|
|
258
258
|
TaskProgressColumn(),
|
|
259
259
|
console=console,
|
|
260
|
+
transient=True,
|
|
260
261
|
) as progress:
|
|
261
262
|
task = progress.add_task("Checking for updates...", total=len(dependencies))
|
|
262
263
|
|
|
@@ -347,9 +348,10 @@ def upgrade_all(
|
|
|
347
348
|
table.add_row(str(pkg["name"]), str(pkg["current"]), str(pkg["latest"]), type_str, tier_str)
|
|
348
349
|
|
|
349
350
|
console.print(table)
|
|
351
|
+
console.print() # Ensure table is fully rendered before progress bar
|
|
350
352
|
|
|
351
353
|
# Run upgrades for each package
|
|
352
|
-
console.print("
|
|
354
|
+
console.print("[bold]Running migrations...[/]\n")
|
|
353
355
|
|
|
354
356
|
all_results: dict[str, list[dict]] = {}
|
|
355
357
|
migration_summary: list[dict] = []
|
|
@@ -360,6 +362,7 @@ def upgrade_all(
|
|
|
360
362
|
BarColumn(),
|
|
361
363
|
TaskProgressColumn(),
|
|
362
364
|
console=console,
|
|
365
|
+
transient=True,
|
|
363
366
|
) as progress:
|
|
364
367
|
task = progress.add_task("Upgrading packages...", total=len(upgradeable))
|
|
365
368
|
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""Package manager detection and sync command generation utilities."""
|
|
2
|
+
|
|
3
|
+
import shutil
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Literal
|
|
6
|
+
|
|
7
|
+
PackageManager = Literal["uv", "poetry", "pip"]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def detect_package_manager(project_path: Path) -> PackageManager:
|
|
11
|
+
"""Detect the package manager used in a project.
|
|
12
|
+
|
|
13
|
+
Detection order:
|
|
14
|
+
1. uv.lock file presence → uv
|
|
15
|
+
2. poetry.lock file presence → poetry
|
|
16
|
+
3. Default → pip
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
project_path: Path to the project root directory.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
The detected package manager name.
|
|
23
|
+
"""
|
|
24
|
+
# Check for uv (uv.lock file)
|
|
25
|
+
if (project_path / "uv.lock").exists():
|
|
26
|
+
return "uv"
|
|
27
|
+
|
|
28
|
+
# Check for poetry (poetry.lock file)
|
|
29
|
+
if (project_path / "poetry.lock").exists():
|
|
30
|
+
return "poetry"
|
|
31
|
+
|
|
32
|
+
# Default to pip
|
|
33
|
+
return "pip"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_sync_command(project_path: Path) -> str:
|
|
37
|
+
"""Get the appropriate dependency sync command for the project.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
project_path: Path to the project root directory.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
The shell command to sync/install dependencies.
|
|
44
|
+
"""
|
|
45
|
+
manager = detect_package_manager(project_path)
|
|
46
|
+
|
|
47
|
+
if manager == "uv":
|
|
48
|
+
return "uv sync"
|
|
49
|
+
elif manager == "poetry":
|
|
50
|
+
return "poetry install"
|
|
51
|
+
else:
|
|
52
|
+
# pip - check what kind of project it is
|
|
53
|
+
if (project_path / "pyproject.toml").exists():
|
|
54
|
+
return "pip install -e ."
|
|
55
|
+
elif (project_path / "requirements.txt").exists():
|
|
56
|
+
return "pip install -r requirements.txt"
|
|
57
|
+
else:
|
|
58
|
+
return "pip install -e ."
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def is_package_manager_available(manager: PackageManager) -> bool:
|
|
62
|
+
"""Check if a package manager is available in the system.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
manager: The package manager to check.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
True if the package manager is available, False otherwise.
|
|
69
|
+
"""
|
|
70
|
+
return shutil.which(manager) is not None
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def get_install_commands(
|
|
74
|
+
project_path: Path,
|
|
75
|
+
libraries: list[dict[str, str]],
|
|
76
|
+
) -> list[str]:
|
|
77
|
+
"""Generate install commands for the upgraded libraries.
|
|
78
|
+
|
|
79
|
+
This is a fallback for when users want to install specific packages
|
|
80
|
+
rather than sync the entire project.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
project_path: Path to the project root directory.
|
|
84
|
+
libraries: List of dicts with 'name' and 'version' keys.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
List of install commands for each library.
|
|
88
|
+
"""
|
|
89
|
+
manager = detect_package_manager(project_path)
|
|
90
|
+
|
|
91
|
+
commands = []
|
|
92
|
+
for lib in libraries:
|
|
93
|
+
name = lib["name"]
|
|
94
|
+
version = lib["version"]
|
|
95
|
+
if manager == "uv":
|
|
96
|
+
commands.append(f"uv add {name}>={version}")
|
|
97
|
+
elif manager == "poetry":
|
|
98
|
+
commands.append(f"poetry add {name}>={version}")
|
|
99
|
+
else:
|
|
100
|
+
commands.append(f"pip install {name}>={version}")
|
|
101
|
+
|
|
102
|
+
return commands
|
|
@@ -162,7 +162,17 @@ class KnowledgeGenerator:
|
|
|
162
162
|
|
|
163
163
|
|
|
164
164
|
# Tier 1 libraries with deterministic AST transforms
|
|
165
|
-
TIER_1_LIBRARIES = {
|
|
165
|
+
TIER_1_LIBRARIES = {
|
|
166
|
+
"pydantic",
|
|
167
|
+
"fastapi",
|
|
168
|
+
"sqlalchemy",
|
|
169
|
+
"pandas",
|
|
170
|
+
"requests",
|
|
171
|
+
"numpy",
|
|
172
|
+
"pytest",
|
|
173
|
+
"marshmallow",
|
|
174
|
+
"flask",
|
|
175
|
+
}
|
|
166
176
|
|
|
167
177
|
|
|
168
178
|
def is_tier_1_library(library: str) -> bool:
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# aiohttp Knowledge Base
|
|
2
|
+
# Breaking changes from v3.7 to v3.9+
|
|
3
|
+
|
|
4
|
+
name: aiohttp
|
|
5
|
+
display_name: aiohttp
|
|
6
|
+
description: Async HTTP client/server framework for asyncio
|
|
7
|
+
migration_guide_url: https://docs.aiohttp.org/en/stable/changes.html
|
|
8
|
+
|
|
9
|
+
supported_migrations:
|
|
10
|
+
- from: "3.7"
|
|
11
|
+
to: "3.9"
|
|
12
|
+
|
|
13
|
+
breaking_changes:
|
|
14
|
+
# Loop parameter removal - ClientSession
|
|
15
|
+
- symbol: "ClientSession(loop=...)"
|
|
16
|
+
change_type: removed
|
|
17
|
+
severity: high
|
|
18
|
+
from_version: "3.7"
|
|
19
|
+
to_version: "3.8"
|
|
20
|
+
description: "loop parameter removed from ClientSession constructor"
|
|
21
|
+
replacement: "ClientSession()"
|
|
22
|
+
has_deterministic_transform: true
|
|
23
|
+
transform_name: remove_loop_param_client_session
|
|
24
|
+
notes: "Event loop is now obtained automatically via asyncio.get_event_loop()"
|
|
25
|
+
|
|
26
|
+
# Loop parameter removal - TCPConnector
|
|
27
|
+
- symbol: "TCPConnector(loop=...)"
|
|
28
|
+
change_type: removed
|
|
29
|
+
severity: high
|
|
30
|
+
from_version: "3.7"
|
|
31
|
+
to_version: "3.8"
|
|
32
|
+
description: "loop parameter removed from TCPConnector constructor"
|
|
33
|
+
replacement: "TCPConnector()"
|
|
34
|
+
has_deterministic_transform: true
|
|
35
|
+
transform_name: remove_loop_param_tcp_connector
|
|
36
|
+
|
|
37
|
+
# Loop parameter removal - UnixConnector
|
|
38
|
+
- symbol: "UnixConnector(loop=...)"
|
|
39
|
+
change_type: removed
|
|
40
|
+
severity: medium
|
|
41
|
+
from_version: "3.7"
|
|
42
|
+
to_version: "3.8"
|
|
43
|
+
description: "loop parameter removed from UnixConnector constructor"
|
|
44
|
+
replacement: "UnixConnector()"
|
|
45
|
+
has_deterministic_transform: true
|
|
46
|
+
transform_name: remove_loop_param_unix_connector
|
|
47
|
+
|
|
48
|
+
# Loop parameter removal - web.Application
|
|
49
|
+
- symbol: "web.Application(loop=...)"
|
|
50
|
+
change_type: removed
|
|
51
|
+
severity: high
|
|
52
|
+
from_version: "3.7"
|
|
53
|
+
to_version: "3.8"
|
|
54
|
+
description: "loop parameter removed from web.Application constructor"
|
|
55
|
+
replacement: "web.Application()"
|
|
56
|
+
has_deterministic_transform: true
|
|
57
|
+
transform_name: remove_loop_param_web_application
|
|
58
|
+
|
|
59
|
+
# Loop parameter removal - ClientTimeout
|
|
60
|
+
- symbol: "ClientTimeout(loop=...)"
|
|
61
|
+
change_type: removed
|
|
62
|
+
severity: medium
|
|
63
|
+
from_version: "3.7"
|
|
64
|
+
to_version: "3.8"
|
|
65
|
+
description: "loop parameter removed from ClientTimeout constructor"
|
|
66
|
+
replacement: "ClientTimeout()"
|
|
67
|
+
has_deterministic_transform: true
|
|
68
|
+
transform_name: remove_loop_param_client_timeout
|
|
69
|
+
|
|
70
|
+
# connector_owner default change
|
|
71
|
+
- symbol: "ClientSession(connector=..., connector_owner=None)"
|
|
72
|
+
change_type: behavior_change
|
|
73
|
+
severity: medium
|
|
74
|
+
from_version: "3.7"
|
|
75
|
+
to_version: "3.9"
|
|
76
|
+
description: "connector_owner now defaults to True; explicitly set to False if connector is shared"
|
|
77
|
+
replacement: "ClientSession(connector=..., connector_owner=False)"
|
|
78
|
+
has_deterministic_transform: false
|
|
79
|
+
notes: "Manual review needed - depends on whether connector is shared across sessions"
|
|
80
|
+
|
|
81
|
+
# BasicAuth.encode() removal
|
|
82
|
+
- symbol: "BasicAuth.encode()"
|
|
83
|
+
change_type: removed
|
|
84
|
+
severity: medium
|
|
85
|
+
from_version: "3.7"
|
|
86
|
+
to_version: "3.9"
|
|
87
|
+
description: "BasicAuth.encode() method removed"
|
|
88
|
+
replacement: "str(BasicAuth(...))"
|
|
89
|
+
has_deterministic_transform: true
|
|
90
|
+
transform_name: basicauth_encode_to_str
|
|
91
|
+
|
|
92
|
+
# Deprecated timeout parameters
|
|
93
|
+
- symbol: "ClientSession(read_timeout=...)"
|
|
94
|
+
change_type: removed
|
|
95
|
+
severity: medium
|
|
96
|
+
from_version: "3.7"
|
|
97
|
+
to_version: "3.8"
|
|
98
|
+
description: "read_timeout parameter deprecated, use ClientTimeout instead"
|
|
99
|
+
replacement: "ClientSession(timeout=ClientTimeout(total=...))"
|
|
100
|
+
has_deterministic_transform: true
|
|
101
|
+
transform_name: read_timeout_to_client_timeout
|
|
102
|
+
|
|
103
|
+
- symbol: "ClientSession(conn_timeout=...)"
|
|
104
|
+
change_type: removed
|
|
105
|
+
severity: medium
|
|
106
|
+
from_version: "3.7"
|
|
107
|
+
to_version: "3.8"
|
|
108
|
+
description: "conn_timeout parameter deprecated, use ClientTimeout instead"
|
|
109
|
+
replacement: "ClientSession(timeout=ClientTimeout(connect=...))"
|
|
110
|
+
has_deterministic_transform: true
|
|
111
|
+
transform_name: conn_timeout_to_client_timeout
|
|
112
|
+
|
|
113
|
+
# app.loop, request.loop, client.loop deprecation
|
|
114
|
+
- symbol: "app.loop"
|
|
115
|
+
change_type: deprecated
|
|
116
|
+
severity: medium
|
|
117
|
+
from_version: "3.7"
|
|
118
|
+
to_version: "3.8"
|
|
119
|
+
description: "app.loop property deprecated"
|
|
120
|
+
replacement: "asyncio.get_event_loop()"
|
|
121
|
+
has_deterministic_transform: true
|
|
122
|
+
transform_name: app_loop_to_get_event_loop
|
|
123
|
+
|
|
124
|
+
- symbol: "request.app.loop"
|
|
125
|
+
change_type: deprecated
|
|
126
|
+
severity: medium
|
|
127
|
+
from_version: "3.7"
|
|
128
|
+
to_version: "3.8"
|
|
129
|
+
description: "request.app.loop property deprecated"
|
|
130
|
+
replacement: "asyncio.get_event_loop()"
|
|
131
|
+
has_deterministic_transform: true
|
|
132
|
+
transform_name: request_loop_to_get_event_loop
|
|
133
|
+
|
|
134
|
+
# Middleware signature changes (old-style to new-style)
|
|
135
|
+
- symbol: "@middleware"
|
|
136
|
+
change_type: signature_change
|
|
137
|
+
severity: high
|
|
138
|
+
from_version: "3.7"
|
|
139
|
+
to_version: "3.9"
|
|
140
|
+
description: "Old-style middleware decorator deprecated; use @web.middleware with async def(request, handler)"
|
|
141
|
+
replacement: "@web.middleware async def middleware(request, handler)"
|
|
142
|
+
has_deterministic_transform: false
|
|
143
|
+
notes: "Middleware function signature changed; manual review recommended"
|
|
144
|
+
|
|
145
|
+
# ws_connect timeout deprecation
|
|
146
|
+
- symbol: "ws_connect(timeout=...)"
|
|
147
|
+
change_type: deprecated
|
|
148
|
+
severity: low
|
|
149
|
+
from_version: "3.7"
|
|
150
|
+
to_version: "3.9"
|
|
151
|
+
description: "timeout parameter in ws_connect deprecated"
|
|
152
|
+
replacement: "ws_connect(receive_timeout=...)"
|
|
153
|
+
has_deterministic_transform: true
|
|
154
|
+
transform_name: ws_connect_timeout_rename
|
|
155
|
+
|
|
156
|
+
- symbol: "ws_connect(receive_timeout=...)"
|
|
157
|
+
change_type: behavior_change
|
|
158
|
+
severity: low
|
|
159
|
+
from_version: "3.7"
|
|
160
|
+
to_version: "3.9"
|
|
161
|
+
description: "Default websocket receive_timeout changed from None to 10.0 seconds"
|
|
162
|
+
replacement: "ws_connect(receive_timeout=None)"
|
|
163
|
+
has_deterministic_transform: false
|
|
164
|
+
notes: "Set receive_timeout=None explicitly if you want no timeout"
|
|
165
|
+
|
|
166
|
+
# Response URL attribute change
|
|
167
|
+
- symbol: "response.url_obj"
|
|
168
|
+
change_type: renamed
|
|
169
|
+
severity: low
|
|
170
|
+
from_version: "3.7"
|
|
171
|
+
to_version: "3.9"
|
|
172
|
+
description: "url_obj attribute renamed to url (now returns yarl.URL)"
|
|
173
|
+
replacement: "response.url"
|
|
174
|
+
has_deterministic_transform: true
|
|
175
|
+
transform_name: url_obj_to_url
|
|
176
|
+
|
|
177
|
+
# WebSocket protocol attribute rename
|
|
178
|
+
- symbol: "ws_response.protocol"
|
|
179
|
+
change_type: renamed
|
|
180
|
+
severity: low
|
|
181
|
+
from_version: "3.7"
|
|
182
|
+
to_version: "3.9"
|
|
183
|
+
description: "WebSocketResponse.protocol renamed to ws_protocol"
|
|
184
|
+
replacement: "ws_response.ws_protocol"
|
|
185
|
+
has_deterministic_transform: true
|
|
186
|
+
transform_name: ws_protocol_rename
|