Skip to content

Commit 7c52cba

Browse files
authored
FreezeGun to TimeMachine Migration Guide (#11)
* FreezeGun to TimeMachine Migration Guide * update * folder rename * updated codemod * final version --------- Co-authored-by: KopekC <[email protected]>
1 parent b5c9dcf commit 7c52cba

File tree

2 files changed

+177
-0
lines changed

2 files changed

+177
-0
lines changed
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
FreezeGun to TimeMachine Migration Example
2+
3+
This example demonstrates how to use Codegen to automatically migrate test code from FreezeGun to TimeMachine for time mocking. The migration script makes this process simple by handling all the tedious manual updates automatically.
4+
5+
## How the Migration Script Works
6+
7+
The script (`run.py`) automates the entire migration process in a few key steps:
8+
9+
1. **Codebase Loading**
10+
```python
11+
codebase = Codebase.from_repo(
12+
"getmoto/moto", commit="786a8ada7ed0c7f9d8b04d49f24596865e4b7901")
13+
```
14+
- Loads your codebase into Codegen's intelligent code analysis engine
15+
- Provides a simple SDK for making codebase-wide changes
16+
- Supports specific commit targeting for version control
17+
18+
2. **Test File Detection**
19+
```python
20+
if "tests" not in file.filepath:
21+
continue
22+
```
23+
- Automatically identifies test files using Codegen's file APIs
24+
- Skips non-test files to avoid unnecessary processing
25+
- Focuses changes where time mocking is most commonly used
26+
27+
3. **Import Updates**
28+
```python
29+
for imp in file.imports:
30+
if imp.symbol_name and 'freezegun' in imp.source:
31+
if imp.name == 'freeze_time':
32+
imp.edit('from time_machine import travel')
33+
```
34+
- Uses Codegen's import analysis to find and update imports
35+
- Handles both direct and aliased imports
36+
- Preserves import structure and formatting
37+
38+
4. **Function Call Transformation**
39+
```python
40+
for fcall in file.function_calls:
41+
if 'freeze_time' not in fcall.source:
42+
continue
43+
# Transform freeze_time to travel with tick=False
44+
```
45+
- Uses Codegen's function call analysis to find all usages
46+
- Adds required TimeMachine parameters
47+
- Maintains existing arguments and formatting
48+
49+
## Why This Makes Migration Easy
50+
51+
1. **Zero Manual Updates**
52+
- Codegen SDK handles all the file searching and updating
53+
- No tedious copy-paste work
54+
55+
2. **Consistent Changes**
56+
- Codegen ensures all transformations follow the same patterns
57+
- Maintains code style consistency
58+
59+
3. **Safe Transformations**
60+
- Codegen validates changes before applying them
61+
- Easy to review and revert if needed
62+
63+
## Common Migration Patterns
64+
65+
### Decorator Usage
66+
```python
67+
# FreezeGun
68+
@freeze_time("2023-01-01")
69+
def test_function():
70+
pass
71+
72+
# Automatically converted to:
73+
@travel("2023-01-01", tick=False)
74+
def test_function():
75+
pass
76+
```
77+
78+
### Context Manager Usage
79+
```python
80+
# FreezeGun
81+
with freeze_time("2023-01-01"):
82+
# test code
83+
84+
# Automatically converted to:
85+
with travel("2023-01-01", tick=False):
86+
# test code
87+
```
88+
89+
### Moving Time Forward
90+
```python
91+
# FreezeGun
92+
freezer = freeze_time("2023-01-01")
93+
freezer.start()
94+
freezer.move_to("2023-01-02")
95+
freezer.stop()
96+
97+
# Automatically converted to:
98+
traveller = travel("2023-01-01", tick=False)
99+
traveller.start()
100+
traveller.shift(datetime.timedelta(days=1))
101+
traveller.stop()
102+
```
103+
104+
## Key Differences to Note
105+
106+
1. **Tick Parameter**
107+
- TimeMachine requires explicit tick behavior configuration
108+
- Script automatically adds `tick=False` to match FreezeGun's default behavior
109+
110+
2. **Time Movement**
111+
- FreezeGun uses `move_to()` with datetime strings
112+
- TimeMachine uses `shift()` with timedelta objects
113+
114+
3. **Return Values**
115+
- FreezeGun's decorator returns the freezer object
116+
- TimeMachine's decorator returns a traveller object
117+
118+
## Running the Migration
119+
120+
```bash
121+
# Install Codegen
122+
pip install codegen
123+
# Run the migration
124+
python run.py
125+
```
126+
127+
## Learn More
128+
129+
- [TimeMachine Documentation](https://github.com/adamchainz/time-machine)
130+
- [FreezeGun Documentation](https://github.com/spulec/freezegun)
131+
- [Codegen Documentation](https://docs.codegen.com)
132+
133+
## Contributing
134+
135+
Feel free to submit issues and enhancement requests!
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from codegen import Codebase
2+
codebase = Codebase.from_repo("getmoto/moto", commit="786a8ada7ed0c7f9d8b04d49f24596865e4b7901")
3+
4+
print("🚀 Starting FreezeGun to TimeMachine conversion...")
5+
6+
for file in codebase.files:
7+
if "tests" not in file.filepath:
8+
continue
9+
print(f"📝 Processing: {file.filepath}")
10+
# Update imports
11+
for imp in file.imports:
12+
if imp.symbol_name and 'freezegun' in imp.source:
13+
if imp.name == 'freeze_time':
14+
# required due to Codegen limitations
15+
imp.edit('from time_machine import travel')
16+
else:
17+
imp.set_import_module('time_machine')
18+
# Find all function calls in the file
19+
for fcall in file.function_calls:
20+
# Skip if not a freeze_time call
21+
if 'freeze_time' not in fcall.source:
22+
continue
23+
# Get original source and prepare new source
24+
new_source = fcall.source
25+
# Add tick parameter if not present
26+
if not fcall.get_arg_by_parameter_name('tick'):
27+
if new_source.endswith(')'):
28+
new_source = new_source[:-1]
29+
if not new_source.endswith('('):
30+
new_source += ','
31+
new_source += ' tick=False)'
32+
# Replace freeze_time with travel
33+
if '.' in new_source:
34+
new_source = new_source.replace(
35+
'freeze_time', 'travel').replace('freezegun', 'time_machine')
36+
else:
37+
new_source = 'travel' + new_source[len('freeze_time'):]
38+
# Make single edit with complete changes
39+
fcall.edit(new_source)
40+
codebase.commit()
41+
42+
print("✅ FreezeGun to TimeMachine conversion completed successfully!")

0 commit comments

Comments
 (0)