fastframe-pandas 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.
- fastframe_pandas-0.1.0/LICENSE +21 -0
- fastframe_pandas-0.1.0/PKG-INFO +392 -0
- fastframe_pandas-0.1.0/README.md +358 -0
- fastframe_pandas-0.1.0/pyproject.toml +83 -0
- fastframe_pandas-0.1.0/setup.cfg +4 -0
- fastframe_pandas-0.1.0/src/fastframe/__init__.py +11 -0
- fastframe_pandas-0.1.0/src/fastframe/antipatterns.py +465 -0
- fastframe_pandas-0.1.0/src/fastframe/bench.py +115 -0
- fastframe_pandas-0.1.0/src/fastframe/cli.py +196 -0
- fastframe_pandas-0.1.0/src/fastframe/detect.py +5 -0
- fastframe_pandas-0.1.0/src/fastframe/policy.py +56 -0
- fastframe_pandas-0.1.0/src/fastframe/report.py +188 -0
- fastframe_pandas-0.1.0/src/fastframe/rewrite.py +5 -0
- fastframe_pandas-0.1.0/src/fastframe/scan.py +141 -0
- fastframe_pandas-0.1.0/src/fastframe/verify.py +166 -0
- fastframe_pandas-0.1.0/src/fastframe_pandas.egg-info/PKG-INFO +392 -0
- fastframe_pandas-0.1.0/src/fastframe_pandas.egg-info/SOURCES.txt +28 -0
- fastframe_pandas-0.1.0/src/fastframe_pandas.egg-info/dependency_links.txt +1 -0
- fastframe_pandas-0.1.0/src/fastframe_pandas.egg-info/entry_points.txt +2 -0
- fastframe_pandas-0.1.0/src/fastframe_pandas.egg-info/requires.txt +12 -0
- fastframe_pandas-0.1.0/src/fastframe_pandas.egg-info/top_level.txt +1 -0
- fastframe_pandas-0.1.0/tests/test_antipatterns.py +62 -0
- fastframe_pandas-0.1.0/tests/test_cli.py +91 -0
- fastframe_pandas-0.1.0/tests/test_edge_cases.py +190 -0
- fastframe_pandas-0.1.0/tests/test_properties.py +99 -0
- fastframe_pandas-0.1.0/tests/test_report.py +30 -0
- fastframe_pandas-0.1.0/tests/test_runtime_edges.py +184 -0
- fastframe_pandas-0.1.0/tests/test_safety.py +59 -0
- fastframe_pandas-0.1.0/tests/test_scan.py +121 -0
- fastframe_pandas-0.1.0/tests/test_verify_bench.py +63 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 FastFrame contributors
|
|
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,392 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fastframe-pandas
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Deterministic source rewrites for common pandas anti-patterns
|
|
5
|
+
Author: FastFrame contributors
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/anurag-23werty/FastFrame
|
|
8
|
+
Project-URL: Repository, https://github.com/anurag-23werty/FastFrame
|
|
9
|
+
Project-URL: Issues, https://github.com/anurag-23werty/FastFrame/issues
|
|
10
|
+
Project-URL: Documentation, https://anurag-23werty.github.io/FastFrame/
|
|
11
|
+
Keywords: pandas,numpy,performance,linting,refactoring
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
18
|
+
Classifier: Topic :: Software Development :: Testing
|
|
19
|
+
Requires-Python: <3.13,>=3.12
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: libcst<2,>=1.0
|
|
23
|
+
Requires-Dist: numpy<3,>=1.26
|
|
24
|
+
Requires-Dist: pandas<3,>=2.0
|
|
25
|
+
Requires-Dist: rich<15,>=13
|
|
26
|
+
Requires-Dist: typer<1,>=0.12
|
|
27
|
+
Provides-Extra: test
|
|
28
|
+
Requires-Dist: hypothesis<7,>=6; extra == "test"
|
|
29
|
+
Requires-Dist: mypy<2,>=1.15; extra == "test"
|
|
30
|
+
Requires-Dist: pytest<10,>=8; extra == "test"
|
|
31
|
+
Requires-Dist: pytest-cov<8,>=6; extra == "test"
|
|
32
|
+
Requires-Dist: ruff<1,>=0.11; extra == "test"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# FastFrame
|
|
36
|
+
|
|
37
|
+
[](https://github.com/anurag-23werty/FastFrame/actions/workflows/ci.yml)
|
|
38
|
+
[](https://github.com/anurag-23werty/FastFrame/actions/workflows/ci.yml)
|
|
39
|
+
|
|
40
|
+
> FastFrame finds slow pandas/NumPy idioms, rewrites only safe patterns deterministically, and proves equivalence before reporting performance.
|
|
41
|
+
|
|
42
|
+
## Problem
|
|
43
|
+
|
|
44
|
+
Row-wise `apply`, `iterrows`, repeated DataFrame concatenation, and repeated
|
|
45
|
+
`np.append` hide vectorizable work behind Python loops or repeated allocation.
|
|
46
|
+
FastFrame scans Python files, directories, and notebook code cells; applies
|
|
47
|
+
conservative LibCST rewrites; executes both versions in subprocesses; and
|
|
48
|
+
compares their results and stdout. Runtime has no LLM or network dependency.
|
|
49
|
+
|
|
50
|
+
## Install
|
|
51
|
+
|
|
52
|
+
### End users
|
|
53
|
+
|
|
54
|
+
After FastFrame is published to PyPI, a user with Python 3.12 can install it
|
|
55
|
+
without cloning this repository:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
python -m pip install fastframe
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
This installs the `fastframe` command. For example:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
fastframe scan my_script.py
|
|
65
|
+
fastframe fix my_script.py -o my_script_fast.py
|
|
66
|
+
fastframe verify my_script.py my_script_fast.py
|
|
67
|
+
fastframe bench my_script.py my_script_fast.py --runs 5
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
FastFrame executes supplied scripts during `fix` verification, `verify`, and
|
|
71
|
+
`bench`; do not run it on untrusted scripts without a separate sandbox.
|
|
72
|
+
|
|
73
|
+
### uv
|
|
74
|
+
|
|
75
|
+
For contributors working from the source repository:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
uv sync --locked --extra test
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Real output from this repository:
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
Resolved 31 packages in 29ms
|
|
85
|
+
Checked 30 packages in 13ms
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Docker
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
docker build -t fastframe:buildathon .
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The image runs as non-root user `fastframe` and has `fastframe` as its
|
|
95
|
+
entrypoint. Run a scan with:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
docker run --rm --network none fastframe:buildathon scan examples/sales_analysis_slow.py
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Run the complete offline test command by overriding the CLI entrypoint:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
docker run --rm --network none --entrypoint make fastframe:buildathon test
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Terminal demo
|
|
108
|
+
|
|
109
|
+
```text
|
|
110
|
+
$ uv run fastframe scan examples/sales_analysis_slow.py
|
|
111
|
+
┏━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┓
|
|
112
|
+
┃ Location ┃ Pattern ┃ Explanation ┃ Suggested action ┃
|
|
113
|
+
┡━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━┩
|
|
114
|
+
│ examples/sales_anal… │ AP001 │ row-wise │ vectorize with │
|
|
115
|
+
│ │ │ DataFrame.apply │ fastframe fix │
|
|
116
|
+
│ │ │ arithmetic │ │
|
|
117
|
+
│ examples/sales_anal… │ AP002 │ Series.apply │ vectorize with │
|
|
118
|
+
│ │ │ arithmetic lambda │ fastframe fix │
|
|
119
|
+
│ examples/sales_anal… │ AP003 │ iterrows arithmetic │ vectorize with │
|
|
120
|
+
│ │ │ append-to-list │ fastframe fix │
|
|
121
|
+
│ examples/sales_anal… │ AP004 │ growing DataFrame │ vectorize with │
|
|
122
|
+
│ │ │ with concat/append │ fastframe fix │
|
|
123
|
+
│ │ │ in a loop │ │
|
|
124
|
+
│ examples/sales_anal… │ AP005 │ growing NumPy array │ vectorize with │
|
|
125
|
+
│ │ │ with np.append in a │ fastframe fix │
|
|
126
|
+
│ │ │ loop │ │
|
|
127
|
+
│ examples/sales_anal… │ AP006 │ downcastable │ manual review │
|
|
128
|
+
│ │ │ object/int64/float64 │ │
|
|
129
|
+
│ │ │ column (manual │ │
|
|
130
|
+
│ │ │ review) │ │
|
|
131
|
+
└──────────────────────┴─────────┴──────────────────────┴──────────────────────┘
|
|
132
|
+
EXIT_CODE=1
|
|
133
|
+
|
|
134
|
+
$ uv run fastframe fix examples/sales_analysis_slow.py -o build/sales_fast.py
|
|
135
|
+
Verification passed.
|
|
136
|
+
--- examples/sales_analysis_slow.py
|
|
137
|
+
+++ build/sales_fast.py
|
|
138
|
+
@@
|
|
139
|
+
-row_totals = work.apply(lambda row: row["units"] * row["price"], axis=1)
|
|
140
|
+
+row_totals = work["units"] * work["price"]
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## CLI
|
|
144
|
+
|
|
145
|
+
### Scan
|
|
146
|
+
|
|
147
|
+
Scan a file, directory recursively, or notebook code cells:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
uv run fastframe scan examples/sales_analysis_slow.py
|
|
151
|
+
uv run fastframe scan src --format json
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
`scan --format json` emits machine-readable findings and exits `1` when any
|
|
155
|
+
finding exists, otherwise `0`.
|
|
156
|
+
|
|
157
|
+
Inline suppressions are supported:
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
out = df["a"].apply(lambda x: x * 2) # fastframe: ignore
|
|
161
|
+
out = df["b"].apply(lambda x: x * 2) # fastframe: ignore[AP002]
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Project configuration lives in `pyproject.toml`:
|
|
165
|
+
|
|
166
|
+
```toml
|
|
167
|
+
[tool.fastframe]
|
|
168
|
+
select = ["AP001", "AP002"]
|
|
169
|
+
ignore = ["AP006"]
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Fix
|
|
173
|
+
|
|
174
|
+
Fix verifies by default and refuses to write if verification fails:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
uv run fastframe fix examples/sales_analysis_slow.py -o build/sales_fast.py
|
|
178
|
+
uv run fastframe fix examples/sales_analysis_slow.py --diff
|
|
179
|
+
uv run fastframe fix examples/sales_analysis_slow.py --in-place
|
|
180
|
+
uv run fastframe fix examples/sales_analysis_slow.py -o build/sales_fast.py --no-verify
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
`--in-place` keeps `sales_analysis_slow.py.bak`. `--no-verify` prints a warning.
|
|
184
|
+
Notebook fixes write rewritten code cells to a copy; Markdown cells are kept.
|
|
185
|
+
|
|
186
|
+
### Verify
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
uv run fastframe verify examples/sales_analysis_slow.py build/sales_fast.py
|
|
190
|
+
uv run fastframe verify examples/sales_analysis_slow.py build/sales_fast.py --json
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Real readable output:
|
|
194
|
+
|
|
195
|
+
```text
|
|
196
|
+
PASS verification
|
|
197
|
+
┏━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┓
|
|
198
|
+
┃ Variable ┃ Status ┃ Details ┃
|
|
199
|
+
┡━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━┩
|
|
200
|
+
│ amounts │ PASS │ equivalent │
|
|
201
|
+
│ combined │ PASS │ equivalent │
|
|
202
|
+
│ row_totals │ PASS │ equivalent │
|
|
203
|
+
│ scaled_units │ PASS │ equivalent │
|
|
204
|
+
│ values │ PASS │ equivalent │
|
|
205
|
+
└──────────────┴────────┴────────────┘
|
|
206
|
+
stdout: PASS
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Verification reports original variables missing from the rewritten script as
|
|
210
|
+
failures, compares captured stdout, uses the original script directory for
|
|
211
|
+
relative paths and `__file__`, and has a 60-second subprocess timeout.
|
|
212
|
+
|
|
213
|
+
### Bench
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
uv run fastframe bench examples/sales_analysis_slow.py build/sales_fast.py --runs 1
|
|
217
|
+
uv run fastframe bench examples/sales_analysis_slow.py build/sales_fast.py --runs 1 --json
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Real output from one run on the 200k-row example:
|
|
221
|
+
|
|
222
|
+
```text
|
|
223
|
+
┏━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓
|
|
224
|
+
┃ Script ┃ Median ┃ Minimum ┃ Peak memory ┃
|
|
225
|
+
┡━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩
|
|
226
|
+
│ Original │ 1.1700s │ 1.1700s │ 22,755,632 bytes │
|
|
227
|
+
│ Rewritten │ 0.0633s │ 0.0633s │ 22,753,741 bytes │
|
|
228
|
+
└───────────┴─────────┴─────────┴──────────────────┘
|
|
229
|
+
Speedup: 18.50x
|
|
230
|
+
Peak memory saved: +1,891 bytes (+0.01%)
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Timing and memory are measured in separate child runs. Imports happen before
|
|
234
|
+
timing, and each measurement path gets one warm-up run.
|
|
235
|
+
|
|
236
|
+
### Report, rules, and explain
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
uv run fastframe report examples/sales_analysis_slow.py --html docs/index.html --runs 1
|
|
240
|
+
uv run fastframe rules
|
|
241
|
+
uv run fastframe explain AP003
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
`report` writes a self-contained HTML report. `rules` lists every built-in
|
|
245
|
+
rule. `explain AP003` prints its explanation and representative before/after.
|
|
246
|
+
|
|
247
|
+
## Supported rules
|
|
248
|
+
|
|
249
|
+
### AP001 — row-wise DataFrame arithmetic
|
|
250
|
+
|
|
251
|
+
```python
|
|
252
|
+
# Before
|
|
253
|
+
out = df.apply(lambda row: row["a"] + row["b"], axis=1)
|
|
254
|
+
# After
|
|
255
|
+
out = df["a"] + df["b"]
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### AP002 — arithmetic Series lambda
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
# Before
|
|
262
|
+
out = df["a"].apply(lambda x: x * 2)
|
|
263
|
+
# After
|
|
264
|
+
out = df["a"] * 2
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### AP003 — `iterrows()` arithmetic append
|
|
268
|
+
|
|
269
|
+
```python
|
|
270
|
+
# Before
|
|
271
|
+
for _, row in df.iterrows():
|
|
272
|
+
out.append(row["a"] + row["b"])
|
|
273
|
+
# After
|
|
274
|
+
out.extend((df["a"] + df["b"]).tolist())
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### AP004 — DataFrame concat growth
|
|
278
|
+
|
|
279
|
+
```python
|
|
280
|
+
# Before
|
|
281
|
+
for chunk in chunks:
|
|
282
|
+
df = pd.concat([df, chunk], ignore_index=True)
|
|
283
|
+
# After
|
|
284
|
+
_fastframe_df_parts = [df]
|
|
285
|
+
for chunk in chunks:
|
|
286
|
+
_fastframe_df_parts.append(chunk)
|
|
287
|
+
if len(_fastframe_df_parts) > 1:
|
|
288
|
+
df = pd.concat(_fastframe_df_parts, ignore_index=True)
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### AP005 — `np.append` growth
|
|
292
|
+
|
|
293
|
+
```python
|
|
294
|
+
# Before
|
|
295
|
+
for value in values:
|
|
296
|
+
arr = np.append(arr, value)
|
|
297
|
+
# After
|
|
298
|
+
_fastframe_arr_parts = [arr]
|
|
299
|
+
for value in values:
|
|
300
|
+
_fastframe_arr_parts.append(np.atleast_1d(value))
|
|
301
|
+
if len(_fastframe_arr_parts) > 1:
|
|
302
|
+
arr = np.concatenate(_fastframe_arr_parts)
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### AP006 — downcast advisory
|
|
306
|
+
|
|
307
|
+
```python
|
|
308
|
+
# Finding; not automatically rewritten
|
|
309
|
+
df["count"] = df["count"].astype("int64")
|
|
310
|
+
# Manual review suggestion
|
|
311
|
+
df["count"] = pd.to_numeric(df["count"], downcast="integer")
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Results: 200k-row example
|
|
315
|
+
|
|
316
|
+
`examples/sales_analysis_slow.py` creates 200,000 rows with seeded RNG
|
|
317
|
+
`np.random.default_rng(2026)`. The report keeps the combined script as the
|
|
318
|
+
whole-workload measurement, while each AP001–AP005 row uses its own focused
|
|
319
|
+
100k-row script from `examples/patterns/`. The following values all came from
|
|
320
|
+
one `--runs 1` report generation:
|
|
321
|
+
|
|
322
|
+
| Benchmark | Workload | Speedup | Verification |
|
|
323
|
+
|---|---|---:|:---:|
|
|
324
|
+
| AP001 row-wise apply | `examples/patterns/ap001.py` | 147.32× | PASS |
|
|
325
|
+
| AP002 Series apply | `examples/patterns/ap002.py` | 12.01× | PASS |
|
|
326
|
+
| AP003 iterrows append | `examples/patterns/ap003.py` | 436.25× | PASS |
|
|
327
|
+
| AP004 concat growth | `examples/patterns/ap004.py` | 6.23× | PASS |
|
|
328
|
+
| AP005 `np.append` growth | `examples/patterns/ap005.py` | 5.88× | PASS |
|
|
329
|
+
| AP006 downcast advisory | no rewrite | advisory only | manual review |
|
|
330
|
+
| Whole sales workload | `examples/sales_analysis_slow.py` (200k rows) | 18.50× | PASS |
|
|
331
|
+
|
|
332
|
+
Benchmarks include subprocess execution and are machine/load dependent. The
|
|
333
|
+
focused scripts are sized to make the slow form measurable; AP004 uses 2,000
|
|
334
|
+
prebuilt 500-row chunks and AP005 uses 20,000 appends. The HTML report contains the complete
|
|
335
|
+
per-pattern timing, memory, code, diff, and badge details.
|
|
336
|
+
|
|
337
|
+
## Safety guarantees
|
|
338
|
+
|
|
339
|
+
- Only a strict arithmetic whitelist is rewritten: string-literal parameter
|
|
340
|
+
subscripts, permitted bare parameters, numeric constants, unary minus, and
|
|
341
|
+
`+ - * / // ** %`.
|
|
342
|
+
- Calls involving `groupby`, `rolling`, `resample`, `expanding`, or `ewm` are
|
|
343
|
+
never automatically rewritten.
|
|
344
|
+
- `pd.concat` rewrites require exactly `[target, piece]`.
|
|
345
|
+
- `np.append` rewrites require the target as the first argument and reject
|
|
346
|
+
`axis`.
|
|
347
|
+
- `iterrows` rewrites require `_` as the index variable; index-dependent
|
|
348
|
+
expressions are never rewritten.
|
|
349
|
+
- AP006 is always advisory because safe downcasting depends on values,
|
|
350
|
+
nullability, precision, and downstream consumers.
|
|
351
|
+
- Rewrites preserve source formatting with LibCST and `fix` verifies before
|
|
352
|
+
writing by default.
|
|
353
|
+
|
|
354
|
+
## Limitations & security
|
|
355
|
+
|
|
356
|
+
- `verify` and `bench` execute both supplied scripts with `runpy` in child
|
|
357
|
+
processes. They are not a security sandbox.
|
|
358
|
+
- Do **not** run untrusted scripts with FastFrame. Use a container or another
|
|
359
|
+
sandbox with restricted filesystem, network, CPU, and memory access.
|
|
360
|
+
- Verification compares matching top-level DataFrame, Series, ndarray, and
|
|
361
|
+
list variables plus exact captured stdout. External side effects, databases,
|
|
362
|
+
files, and network behavior are not equivalence guarantees.
|
|
363
|
+
- Benchmarks measure complete script execution after imports, not an isolated
|
|
364
|
+
function microbenchmark.
|
|
365
|
+
- Unknown source shapes are reported only when recognized; no speculative
|
|
366
|
+
rewrite is attempted.
|
|
367
|
+
- Rewrites are syntax-based rather than type-aware: a method that looks like
|
|
368
|
+
pandas `apply` on a non-pandas object can be rewritten. The default `fix`
|
|
369
|
+
verification step executes both versions and catches mismatched behavior
|
|
370
|
+
before writing the output.
|
|
371
|
+
|
|
372
|
+
## Tests and quality
|
|
373
|
+
|
|
374
|
+
```bash
|
|
375
|
+
make test
|
|
376
|
+
uv run --no-sync ruff check .
|
|
377
|
+
uv run --no-sync mypy
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
Real local result:
|
|
381
|
+
|
|
382
|
+
```text
|
|
383
|
+
90 passed
|
|
384
|
+
Required test coverage of 90% reached. Total coverage: 94.39%
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
GitHub Actions runs Ruff, mypy, coverage tests, Docker build, and the offline
|
|
388
|
+
Docker test on pushes and pull requests.
|
|
389
|
+
|
|
390
|
+
## Live demo
|
|
391
|
+
|
|
392
|
+
[Open the FastFrame GitHub Pages report](https://anurag-23werty.github.io/FastFrame/)
|