Skip to content

Commit f94ab96

Browse files
authored
Merge pull request #18 from HLD/claude/review-project-74JID
2 parents 9bdc0fc + 2dba983 commit f94ab96

6 files changed

Lines changed: 606 additions & 93 deletions

File tree

PYTHON3_MIGRATION_GUIDE.md

Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
# Python 3 Migration Guide for GGRC-Core
2+
3+
This document outlines the migration strategy from Python 2.7 to Python 3.9+ for the GGRC-Core project.
4+
5+
## Migration Status
6+
7+
### ✅ Completed
8+
- [x] Compatibility assessment across codebase
9+
- [x] Updated requirements.txt for Python 3
10+
- [x] Updated requirements-dev.txt for Python 3
11+
- [x] Updated requirements-selenium.txt for Python 3
12+
- [x] Created automated migration script
13+
- [x] Migrated sample file (src/ggrc/converters/base_block.py)
14+
15+
### 🚧 In Progress
16+
- [ ] Run automated migration on all core modules
17+
- [ ] Fix Python 3 compatibility issues
18+
- [ ] Update test suite
19+
- [ ] Verify application functionality
20+
21+
## Compatibility Assessment Results
22+
23+
| Issue Type | Occurrences | Files Affected | Severity |
24+
|------------|-------------|----------------|----------|
25+
| Print statements | 48 | 15 files | Medium |
26+
| Dict iteration methods (.iteritems/.iterkeys/.itervalues) | 167 | 65 files | High |
27+
| xrange() usage | 19 | 14 files | Low |
28+
| unicode() calls | 85 | 25 files | High |
29+
| Old stdlib imports (urlparse, urllib2, ConfigParser) | 8 | 8 files | Medium |
30+
| basestring/long types | 40 | 25 files | Medium |
31+
| Missing __future__ imports | ~900 files | Most files | Critical |
32+
33+
**Total affected files: ~150-200 files requiring changes**
34+
35+
## Key Dependency Updates
36+
37+
### Core Dependencies
38+
| Package | Old Version | New Version | Notes |
39+
|---------|-------------|-------------|-------|
40+
| Python | 2.7 | 3.9+ | **Critical** |
41+
| Flask | 0.10.1 | 3.0.0 | Major API changes |
42+
| SQLAlchemy | 0.9.8 | 2.0.23 | Significant migration required |
43+
| Werkzeug | 0.12.2 | 3.0.1 | Bundled with Flask |
44+
| bleach | 1.2.2 | 6.1.0 | Security critical |
45+
| requests | 2.8.1 | 2.31.0 | Security updates |
46+
47+
### Testing Dependencies
48+
| Package | Old Version | New Version | Notes |
49+
|---------|-------------|-------------|-------|
50+
| pytest | 3.2.1 | 7.4.3 | nose → pytest migration |
51+
| selenium | 2.47.3 | 4.15.2 | WebDriver W3C protocol |
52+
| pylint | 1.7.1 | 3.0.3 | Updated linting rules |
53+
54+
### Removed Dependencies (Built into Python 3)
55+
- `enum34` - Built into Python 3.4+
56+
- `argparse` - Built into Python 3.2+
57+
- `mock` - Use `unittest.mock` from stdlib
58+
- `wsgiref` - Built into Python 3
59+
60+
## Migration Steps
61+
62+
### Step 1: Automated Migration
63+
Run the migration script to fix common Python 2/3 issues:
64+
65+
```bash
66+
python3 migrate_to_python3.py
67+
```
68+
69+
This script automatically fixes:
70+
- `.iteritems()``.items()`
71+
- `.iterkeys()``.keys()`
72+
- `.itervalues()``.values()`
73+
- `xrange()``range()`
74+
- `unicode()``str()`
75+
- `basestring``str`
76+
- `long()``int()`
77+
- Old imports (urlparse, urllib2, ConfigParser)
78+
79+
### Step 2: Manual Fixes
80+
81+
Some issues require manual intervention:
82+
83+
#### Print Statements
84+
```python
85+
# Python 2
86+
print "Hello, world!"
87+
88+
# Python 3
89+
print("Hello, world!")
90+
```
91+
92+
#### String/Bytes Handling
93+
```python
94+
# Python 2
95+
data = "hello".encode('utf-8')
96+
# data is str
97+
98+
# Python 3
99+
data = "hello".encode('utf-8')
100+
# data is bytes - handle accordingly
101+
```
102+
103+
#### Division
104+
```python
105+
# Python 2
106+
result = 5 / 2 # Returns 2
107+
108+
# Python 3
109+
result = 5 / 2 # Returns 2.5
110+
result = 5 // 2 # Returns 2 (floor division)
111+
```
112+
113+
#### Exception Handling
114+
```python
115+
# Python 2
116+
except ValueError, e:
117+
pass
118+
119+
# Python 3
120+
except ValueError as e:
121+
pass
122+
```
123+
124+
### Step 3: Flask 3.0 Migration
125+
126+
Flask 3.0 has breaking changes:
127+
128+
1. **Import changes:**
129+
```python
130+
# Old
131+
from flask.ext.sqlalchemy import SQLAlchemy
132+
133+
# New
134+
from flask_sqlalchemy import SQLAlchemy
135+
```
136+
137+
2. **Before/After request decorators:**
138+
```python
139+
# Old - returns modified response
140+
@app.after_request
141+
def after(response):
142+
response.headers['X-Custom'] = 'value'
143+
return response
144+
145+
# New - same, but stricter about return value
146+
```
147+
148+
3. **JSON handling:**
149+
```python
150+
# Old
151+
return jsonify(data), 200
152+
153+
# New - still works, but response.json is stricter
154+
```
155+
156+
### Step 4: SQLAlchemy 2.0 Migration
157+
158+
Major changes in SQLAlchemy 2.0:
159+
160+
1. **Query API changes:**
161+
```python
162+
# Old style (1.x)
163+
users = session.query(User).filter(User.name == 'john').all()
164+
165+
# New style (2.0)
166+
from sqlalchemy import select
167+
stmt = select(User).where(User.name == 'john')
168+
users = session.execute(stmt).scalars().all()
169+
```
170+
171+
2. **Declarative base:**
172+
```python
173+
# Old
174+
from flask_sqlalchemy import SQLAlchemy
175+
db = SQLAlchemy()
176+
177+
# New - compatible, but check deprecation warnings
178+
```
179+
180+
### Step 5: Update Docker Configuration
181+
182+
Update Dockerfile to use Python 3:
183+
184+
```dockerfile
185+
FROM python:3.11-slim
186+
187+
# Rest of Dockerfile...
188+
```
189+
190+
### Step 6: Testing
191+
192+
1. **Install dependencies:**
193+
```bash
194+
cd src
195+
pip install -r requirements.txt
196+
pip install -r requirements-dev.txt
197+
```
198+
199+
2. **Run tests:**
200+
```bash
201+
# Run pytest (replacing nose)
202+
pytest test/
203+
204+
# Run specific test files
205+
pytest test/integration/
206+
207+
# Run with coverage
208+
pytest --cov=ggrc --cov-report=html
209+
```
210+
211+
3. **Check for deprecation warnings:**
212+
```bash
213+
python3 -Wd -m pytest test/
214+
```
215+
216+
## Common Issues & Solutions
217+
218+
### Issue: Import errors after migration
219+
**Solution:** Check for renamed stdlib modules:
220+
- `urlparse``urllib.parse`
221+
- `urllib2``urllib.request`
222+
- `ConfigParser``configparser`
223+
- `Queue``queue`
224+
225+
### Issue: String encoding errors
226+
**Solution:** Be explicit about bytes vs strings:
227+
```python
228+
# When reading files
229+
with open('file.txt', 'r', encoding='utf-8') as f:
230+
content = f.read() # Returns str
231+
232+
with open('file.bin', 'rb') as f:
233+
content = f.read() # Returns bytes
234+
```
235+
236+
### Issue: Dictionary iteration errors
237+
**Solution:** In Python 3, `.keys()`, `.values()`, `.items()` return views, not lists:
238+
```python
239+
# If you need a list:
240+
keys_list = list(my_dict.keys())
241+
242+
# But usually views work fine:
243+
for key in my_dict.keys(): # Works in both Python 2 & 3
244+
pass
245+
```
246+
247+
### Issue: Integer division
248+
**Solution:** Use `//` for floor division, `/` for true division:
249+
```python
250+
# Ensure integer division
251+
result = total // count # Floor division
252+
253+
# Or use from __future__
254+
from __future__ import division
255+
```
256+
257+
## Testing Checklist
258+
259+
- [ ] All unit tests pass
260+
- [ ] All integration tests pass
261+
- [ ] All Selenium tests pass
262+
- [ ] Application starts without errors
263+
- [ ] Database migrations work
264+
- [ ] Import/export functionality works
265+
- [ ] Authentication works
266+
- [ ] API endpoints respond correctly
267+
- [ ] Frontend loads and renders
268+
- [ ] Workflows execute properly
269+
- [ ] Notifications send correctly
270+
271+
## Rollback Plan
272+
273+
If migration fails:
274+
275+
1. **Revert code changes:**
276+
```bash
277+
git reset --hard HEAD~1 # or specific commit
278+
```
279+
280+
2. **Restore old requirements:**
281+
```bash
282+
git checkout HEAD~1 -- src/requirements*.txt
283+
```
284+
285+
3. **Reinstall Python 2.7 environment**
286+
287+
## Timeline Estimate
288+
289+
- **Automated migration:** 1 day
290+
- **Manual fixes:** 3-5 days
291+
- **Flask/SQLAlchemy updates:** 5-7 days
292+
- **Testing and bug fixes:** 7-10 days
293+
- **Total:** 3-4 weeks
294+
295+
## Resources
296+
297+
- [Python 3 Porting Guide](https://docs.python.org/3/howto/pyporting.html)
298+
- [Flask 3.0 Changelog](https://flask.palletsprojects.com/en/3.0.x/changes/)
299+
- [SQLAlchemy 2.0 Migration Guide](https://docs.sqlalchemy.org/en/20/changelog/migration_20.html)
300+
- [Conservative Python 3 Porting Guide](https://portingguide.readthedocs.io/)
301+
302+
## Support
303+
304+
For migration issues:
305+
- Check existing GitHub issues
306+
- Review deprecation warnings
307+
- Consult Python 3 porting guide
308+
- Test incrementally
309+
310+
---
311+
312+
**Last Updated:** 2025-12-25
313+
**Migration Started:** 2025-12-25
314+
**Target Completion:** 2026-01-15

0 commit comments

Comments
 (0)