typedframes 0.6.0__tar.gz → 0.8.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.
- {typedframes-0.6.0 → typedframes-0.8.0}/PKG-INFO +13 -13
- {typedframes-0.6.0 → typedframes-0.8.0}/README.md +12 -12
- {typedframes-0.6.0 → typedframes-0.8.0}/pyproject.toml +1 -1
- {typedframes-0.6.0 → typedframes-0.8.0}/rust/Cargo.lock +1 -1
- {typedframes-0.6.0 → typedframes-0.8.0}/rust/Cargo.toml +1 -1
- {typedframes-0.6.0 → typedframes-0.8.0}/rust/src/ast_extract.rs +13 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/rust/src/constants.rs +87 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/rust/src/errors.rs +63 -0
- typedframes-0.8.0/rust/src/frame_ops.rs +1335 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/rust/src/index.rs +733 -1
- {typedframes-0.6.0 → typedframes-0.8.0}/rust/src/lib.rs +1 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/rust/src/linter.rs +4331 -305
- {typedframes-0.6.0 → typedframes-0.8.0}/rust/src/notebook.rs +116 -1
- {typedframes-0.6.0 → typedframes-0.8.0}/rust/src/pyapi.rs +6 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/src/typedframes/__init__.py +1 -1
- {typedframes-0.6.0 → typedframes-0.8.0}/src/typedframes/cli.py +224 -24
- {typedframes-0.6.0 → typedframes-0.8.0}/rust/.cargo/config.toml +0 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/rust/README.md +0 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/rust/benches/parser_bench.rs +0 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/rust/src/config.rs +0 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/rust/src/contract.rs +0 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/rust/src/main.rs +0 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/rust/src/sql.rs +0 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/rust/src/typo.rs +0 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/rust/tests/integration_test.rs +0 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/src/typedframes/_rust_checker.pyi +0 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/src/typedframes/base_schema.py +0 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/src/typedframes/column.py +0 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/src/typedframes/column_group.py +0 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/src/typedframes/column_group_error.py +0 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/src/typedframes/column_set.py +0 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/src/typedframes/missing_dependency_error.py +0 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/src/typedframes/mypy.py +0 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/src/typedframes/pandas.py +0 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/src/typedframes/pandera.py +0 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/src/typedframes/polars.py +0 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/src/typedframes/py.typed +0 -0
- {typedframes-0.6.0 → typedframes-0.8.0}/src/typedframes/schema_algebra.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: typedframes
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Classifier: Development Status :: 3 - Alpha
|
|
5
5
|
Classifier: Intended Audience :: Developers
|
|
6
6
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -42,7 +42,7 @@ Project-URL: Repository, https://github.com/w-martin/typedframes
|
|
|
42
42
|
|
|
43
43
|
> ⚠️ **Project Status: Proof of Concept**
|
|
44
44
|
>
|
|
45
|
-
> `typedframes` (v0.
|
|
45
|
+
> `typedframes` (v0.8.0) is currently an experimental proof-of-concept. The core static analysis and mypy/Rust
|
|
46
46
|
> integrations work, but expect rough edges. The codebase prioritizes demonstrating the viability of static DataFrame
|
|
47
47
|
> column checking over production-grade stability.
|
|
48
48
|
>
|
|
@@ -504,7 +504,7 @@ repos:
|
|
|
504
504
|
name: typedframes check
|
|
505
505
|
entry: typedframes check . --strict
|
|
506
506
|
language: python
|
|
507
|
-
additional_dependencies: ["typedframes==0.
|
|
507
|
+
additional_dependencies: ["typedframes==0.8.0"]
|
|
508
508
|
types_or: [python, jupyter]
|
|
509
509
|
pass_filenames: false
|
|
510
510
|
```
|
|
@@ -553,10 +553,10 @@ The action installs the PyPI wheel into a throwaway virtualenv and runs the chec
|
|
|
553
553
|
| Input | Default | |
|
|
554
554
|
|-------|---------|-|
|
|
555
555
|
| `path` | `.` | File or directory to check |
|
|
556
|
-
| `version` | `latest` | PyPI version to install, e.g. `"0.
|
|
556
|
+
| `version` | `latest` | PyPI version to install, e.g. `"0.8.0"` |
|
|
557
557
|
| `strict` | `true` | Fail the step on errors — `typedframes check` exits 0 without it |
|
|
558
558
|
| `coverage-fail-under` | *(unset)* | Minimum DataFrame schema coverage, e.g. `"90"` |
|
|
559
|
-
| `coverage-detail` | `summary` | Or `term-missing` for the per-file breakdown |
|
|
559
|
+
| `coverage-detail` | `summary` | Or `term-missing` for the per-file breakdown, `explain` to diagnose a lower-than-expected total |
|
|
560
560
|
| `no-warnings` | `false` | Suppress warning-level diagnostics |
|
|
561
561
|
| `args` | *(empty)* | Escape hatch for `--no-index`, `--lenient-ingest`, `--no-info` |
|
|
562
562
|
|
|
@@ -667,17 +667,17 @@ plus the requested features, so both halves get checked normally. See
|
|
|
667
667
|
Fast feedback reduces development time. The typedframes Rust binary provides near-instant column checking.
|
|
668
668
|
|
|
669
669
|
**Benchmark results** (20 runs, 3 warmup, caches cleared between runs):
|
|
670
|
-
*2026-
|
|
670
|
+
*2026-09-28 · Darwin 27.0.0 · arm · CPython 3.14.4 · 64GiB RAM · Great Expectations pinned @ 1.20.0*
|
|
671
671
|
|
|
672
672
|
| Tool | Version | What it does | typedframes (13 files) | great_expectations (485 files) |
|
|
673
673
|
|------|---------|--------------|------------------------|--------------------------------|
|
|
674
|
-
| typedframes | 0.
|
|
675
|
-
| ruff | 0.16.3 | Linter (no type checking) | 30ms ±
|
|
676
|
-
| ty | 0.0.72 | Type checker |
|
|
677
|
-
| pyrefly | 1.2.0 | Type checker |
|
|
678
|
-
| mypy | 2.3.1 | Type checker (no plugin) |
|
|
679
|
-
| mypy + typedframes | 2.3.1 | Type checker + column checker |
|
|
680
|
-
| pyright | 1.1.411 | Type checker |
|
|
674
|
+
| typedframes | 0.8.0 | DataFrame column checker | 49ms ±349µs (IQR 513µs) | 258ms ±2ms (IQR 2ms) |
|
|
675
|
+
| ruff | 0.16.3 | Linter (no type checking) | 30ms ±981µs (IQR 1ms) | 236ms ±4ms (IQR 6ms) |
|
|
676
|
+
| ty | 0.0.72 | Type checker | 72ms ±1ms (IQR 959µs) | 773ms ±8ms (IQR 14ms) |
|
|
677
|
+
| pyrefly | 1.2.0 | Type checker | 98ms ±1ms (IQR 1ms) | 273ms ±8ms (IQR 11ms) |
|
|
678
|
+
| mypy | 2.3.1 | Type checker (no plugin) | 2.79s ±93ms (IQR 61ms) | 4.14s ±41ms (IQR 52ms) |
|
|
679
|
+
| mypy + typedframes | 2.3.1 | Type checker + column checker | 2.78s ±13ms (IQR 14ms) | 4.50s ±26ms (IQR 33ms) |
|
|
680
|
+
| pyright | 1.1.411 | Type checker | 841ms ±35ms (IQR 46ms) | 3.30s ±24ms (IQR 32ms) |
|
|
681
681
|
|
|
682
682
|
*Run `uv run python benchmarks/benchmark_checkers.py` to reproduce.*
|
|
683
683
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
> ⚠️ **Project Status: Proof of Concept**
|
|
10
10
|
>
|
|
11
|
-
> `typedframes` (v0.
|
|
11
|
+
> `typedframes` (v0.8.0) is currently an experimental proof-of-concept. The core static analysis and mypy/Rust
|
|
12
12
|
> integrations work, but expect rough edges. The codebase prioritizes demonstrating the viability of static DataFrame
|
|
13
13
|
> column checking over production-grade stability.
|
|
14
14
|
>
|
|
@@ -470,7 +470,7 @@ repos:
|
|
|
470
470
|
name: typedframes check
|
|
471
471
|
entry: typedframes check . --strict
|
|
472
472
|
language: python
|
|
473
|
-
additional_dependencies: ["typedframes==0.
|
|
473
|
+
additional_dependencies: ["typedframes==0.8.0"]
|
|
474
474
|
types_or: [python, jupyter]
|
|
475
475
|
pass_filenames: false
|
|
476
476
|
```
|
|
@@ -519,10 +519,10 @@ The action installs the PyPI wheel into a throwaway virtualenv and runs the chec
|
|
|
519
519
|
| Input | Default | |
|
|
520
520
|
|-------|---------|-|
|
|
521
521
|
| `path` | `.` | File or directory to check |
|
|
522
|
-
| `version` | `latest` | PyPI version to install, e.g. `"0.
|
|
522
|
+
| `version` | `latest` | PyPI version to install, e.g. `"0.8.0"` |
|
|
523
523
|
| `strict` | `true` | Fail the step on errors — `typedframes check` exits 0 without it |
|
|
524
524
|
| `coverage-fail-under` | *(unset)* | Minimum DataFrame schema coverage, e.g. `"90"` |
|
|
525
|
-
| `coverage-detail` | `summary` | Or `term-missing` for the per-file breakdown |
|
|
525
|
+
| `coverage-detail` | `summary` | Or `term-missing` for the per-file breakdown, `explain` to diagnose a lower-than-expected total |
|
|
526
526
|
| `no-warnings` | `false` | Suppress warning-level diagnostics |
|
|
527
527
|
| `args` | *(empty)* | Escape hatch for `--no-index`, `--lenient-ingest`, `--no-info` |
|
|
528
528
|
|
|
@@ -633,17 +633,17 @@ plus the requested features, so both halves get checked normally. See
|
|
|
633
633
|
Fast feedback reduces development time. The typedframes Rust binary provides near-instant column checking.
|
|
634
634
|
|
|
635
635
|
**Benchmark results** (20 runs, 3 warmup, caches cleared between runs):
|
|
636
|
-
*2026-
|
|
636
|
+
*2026-09-28 · Darwin 27.0.0 · arm · CPython 3.14.4 · 64GiB RAM · Great Expectations pinned @ 1.20.0*
|
|
637
637
|
|
|
638
638
|
| Tool | Version | What it does | typedframes (13 files) | great_expectations (485 files) |
|
|
639
639
|
|------|---------|--------------|------------------------|--------------------------------|
|
|
640
|
-
| typedframes | 0.
|
|
641
|
-
| ruff | 0.16.3 | Linter (no type checking) | 30ms ±
|
|
642
|
-
| ty | 0.0.72 | Type checker |
|
|
643
|
-
| pyrefly | 1.2.0 | Type checker |
|
|
644
|
-
| mypy | 2.3.1 | Type checker (no plugin) |
|
|
645
|
-
| mypy + typedframes | 2.3.1 | Type checker + column checker |
|
|
646
|
-
| pyright | 1.1.411 | Type checker |
|
|
640
|
+
| typedframes | 0.8.0 | DataFrame column checker | 49ms ±349µs (IQR 513µs) | 258ms ±2ms (IQR 2ms) |
|
|
641
|
+
| ruff | 0.16.3 | Linter (no type checking) | 30ms ±981µs (IQR 1ms) | 236ms ±4ms (IQR 6ms) |
|
|
642
|
+
| ty | 0.0.72 | Type checker | 72ms ±1ms (IQR 959µs) | 773ms ±8ms (IQR 14ms) |
|
|
643
|
+
| pyrefly | 1.2.0 | Type checker | 98ms ±1ms (IQR 1ms) | 273ms ±8ms (IQR 11ms) |
|
|
644
|
+
| mypy | 2.3.1 | Type checker (no plugin) | 2.79s ±93ms (IQR 61ms) | 4.14s ±41ms (IQR 52ms) |
|
|
645
|
+
| mypy + typedframes | 2.3.1 | Type checker + column checker | 2.78s ±13ms (IQR 14ms) | 4.50s ±26ms (IQR 33ms) |
|
|
646
|
+
| pyright | 1.1.411 | Type checker | 841ms ±35ms (IQR 46ms) | 3.30s ±24ms (IQR 32ms) |
|
|
647
647
|
|
|
648
648
|
*Run `uv run python benchmarks/benchmark_checkers.py` to reproduce.*
|
|
649
649
|
|
|
@@ -4,7 +4,7 @@ build-backend = "maturin"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "typedframes"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.8.0"
|
|
8
8
|
description = "Static analysis for pandas and polars DataFrames. Catch column errors at lint-time, not runtime."
|
|
9
9
|
keywords = ["pandas", "polars", "type-checking", "static-analysis", "dataframe", "linter", "mypy-plugin"]
|
|
10
10
|
readme = "README.md"
|
|
@@ -16,6 +16,19 @@ pub(crate) fn is_schema_base(name: &str) -> bool {
|
|
|
16
16
|
)
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
// The bare name of a decorator expression: `staticmethod` for `@staticmethod`,
|
|
20
|
+
// `wraps` for both `@wraps(f)` and `@functools.wraps(f)`. `None` for anything else
|
|
21
|
+
// (an attribute chain deeper than one level, a subscript, a call with no simple
|
|
22
|
+
// name, ...) -- callers treat that the same as an unrecognized name.
|
|
23
|
+
pub(crate) fn decorator_name(expr: &Expr) -> Option<&str> {
|
|
24
|
+
match expr {
|
|
25
|
+
Expr::Name(name) => Some(name.id.as_str()),
|
|
26
|
+
Expr::Attribute(attr) => Some(attr.attr.as_str()),
|
|
27
|
+
Expr::Call(call) => decorator_name(&call.func),
|
|
28
|
+
_ => None,
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
19
32
|
pub(crate) fn extract_string_literal(expr: &Expr) -> Option<&str> {
|
|
20
33
|
if let Expr::StringLiteral(s) = expr {
|
|
21
34
|
Some(s.value.to_str())
|
|
@@ -182,6 +182,9 @@ pub(crate) const LOAD_FUNCTIONS: &[&str] = &[
|
|
|
182
182
|
"read_database",
|
|
183
183
|
"read_database_uri",
|
|
184
184
|
"read_gbq",
|
|
185
|
+
// Not an I/O read, but shares the same usecols=/columns=/dtype=/schema= recognition
|
|
186
|
+
// and bare-load-without-a-hint fallback as every function above it.
|
|
187
|
+
"DataFrame",
|
|
185
188
|
];
|
|
186
189
|
|
|
187
190
|
pub(crate) const LOAD_MODULES: &[&str] = &["pd", "pandas", "pl", "polars"];
|
|
@@ -241,6 +244,90 @@ pub(crate) const SQL_PRODUCING_METHODS: &[&str] = &["query", "sql"];
|
|
|
241
244
|
// checker's existing "empty string = none" sentinel convention for the same fields.
|
|
242
245
|
pub(crate) const OPEN_FRAME_MARKER: &str = "__typedframes_open_frame__";
|
|
243
246
|
|
|
247
|
+
// Methods that return a frame with the same columns as their receiver, beyond
|
|
248
|
+
// `ROW_PASSTHROUGH_METHODS` (which the assignment dispatch already propagates
|
|
249
|
+
// into a new binding). Consulted only by `frame_ops::classify_rhs`, to tell a
|
|
250
|
+
// reassignment that leaves a tracked frame's schema intact (`df = df.copy()`)
|
|
251
|
+
// apart from one that may change it. Deliberately conservative: anything not
|
|
252
|
+
// listed here is treated as possibly schema-changing.
|
|
253
|
+
pub(crate) const SCHEMA_PRESERVING_METHODS: &[&str] = &[
|
|
254
|
+
"copy",
|
|
255
|
+
"drop_duplicates",
|
|
256
|
+
"astype",
|
|
257
|
+
"replace",
|
|
258
|
+
"round",
|
|
259
|
+
"abs",
|
|
260
|
+
"clip",
|
|
261
|
+
"where",
|
|
262
|
+
"mask",
|
|
263
|
+
"sort_index",
|
|
264
|
+
"interpolate",
|
|
265
|
+
"shift",
|
|
266
|
+
"convert_dtypes",
|
|
267
|
+
"infer_objects",
|
|
268
|
+
"explode",
|
|
269
|
+
"isna",
|
|
270
|
+
"isnull",
|
|
271
|
+
"notna",
|
|
272
|
+
"notnull",
|
|
273
|
+
"clone",
|
|
274
|
+
"unique",
|
|
275
|
+
"drop_nulls",
|
|
276
|
+
"fill_null",
|
|
277
|
+
"fill_nan",
|
|
278
|
+
"slice",
|
|
279
|
+
"limit",
|
|
280
|
+
"reverse",
|
|
281
|
+
"lazy",
|
|
282
|
+
"collect",
|
|
283
|
+
"to_pandas",
|
|
284
|
+
"to_polars",
|
|
285
|
+
];
|
|
286
|
+
|
|
287
|
+
// Methods whose result is a Series, scalar, list, dict, or a serialisation --
|
|
288
|
+
// never a frame -- so a name reassigned from one is no longer the tracked frame.
|
|
289
|
+
pub(crate) const NON_FRAME_METHODS: &[&str] = &[
|
|
290
|
+
"sum",
|
|
291
|
+
"mean",
|
|
292
|
+
"median",
|
|
293
|
+
"std",
|
|
294
|
+
"var",
|
|
295
|
+
"min",
|
|
296
|
+
"max",
|
|
297
|
+
"count",
|
|
298
|
+
"nunique",
|
|
299
|
+
"idxmax",
|
|
300
|
+
"idxmin",
|
|
301
|
+
"any",
|
|
302
|
+
"all",
|
|
303
|
+
"prod",
|
|
304
|
+
"value_counts",
|
|
305
|
+
"to_dict",
|
|
306
|
+
"to_list",
|
|
307
|
+
"tolist",
|
|
308
|
+
"to_numpy",
|
|
309
|
+
"to_csv",
|
|
310
|
+
"to_parquet",
|
|
311
|
+
"to_json",
|
|
312
|
+
"to_string",
|
|
313
|
+
"to_html",
|
|
314
|
+
"to_markdown",
|
|
315
|
+
"to_latex",
|
|
316
|
+
"to_excel",
|
|
317
|
+
"to_sql",
|
|
318
|
+
"to_records",
|
|
319
|
+
"memory_usage",
|
|
320
|
+
"iterrows",
|
|
321
|
+
"itertuples",
|
|
322
|
+
"items",
|
|
323
|
+
"pop",
|
|
324
|
+
"get",
|
|
325
|
+
"squeeze",
|
|
326
|
+
"item",
|
|
327
|
+
"keys",
|
|
328
|
+
"insert",
|
|
329
|
+
];
|
|
330
|
+
|
|
244
331
|
pub(crate) const ROW_PASSTHROUGH_METHODS: &[&str] = &[
|
|
245
332
|
"filter",
|
|
246
333
|
"query",
|
|
@@ -63,6 +63,17 @@ pub struct FileStats {
|
|
|
63
63
|
pub dataframes_total: usize,
|
|
64
64
|
pub dataframes_typed: usize,
|
|
65
65
|
pub untyped_sites: Vec<UntypedSite>,
|
|
66
|
+
pub typed_sites: Vec<TypedSite>,
|
|
67
|
+
/// Every `<load module>.<load function>(...)`-shaped call found anywhere in the
|
|
68
|
+
/// file by an unconditional, position-independent scan (see
|
|
69
|
+
/// `linter::LoadCallSiteCollector`) -- populated regardless of whether the site
|
|
70
|
+
/// was actually recognized as an origin by the targeted (`Assign`/`AnnAssign`-only)
|
|
71
|
+
/// counting logic. Powers `--coverage-detail=explain`: cross-referencing this list
|
|
72
|
+
/// against `typed_sites`/`untyped_sites` by line is what tells a reader whether a
|
|
73
|
+
/// given call was counted at all, not just whether it was typed.
|
|
74
|
+
pub all_dataframe_calls: Vec<DataFrameCallSite>,
|
|
75
|
+
/// Every place a tracked frame stopped carrying its column set -- see [`LegEvent`].
|
|
76
|
+
pub leg_events: Vec<LegEvent>,
|
|
66
77
|
}
|
|
67
78
|
|
|
68
79
|
/// One DataFrame origin the linter recognized but could not resolve columns for.
|
|
@@ -85,6 +96,58 @@ pub struct UntypedSite {
|
|
|
85
96
|
pub var: String,
|
|
86
97
|
}
|
|
87
98
|
|
|
99
|
+
/// A recognized DataFrame origin that DID resolve to a concrete column set --
|
|
100
|
+
/// the `dataframes_typed` counterpart of [`UntypedSite`]. Line and column are
|
|
101
|
+
/// 1-indexed, matching [`LintError`].
|
|
102
|
+
#[derive(Debug, Serialize)]
|
|
103
|
+
pub struct TypedSite {
|
|
104
|
+
pub line: usize,
|
|
105
|
+
pub col: usize,
|
|
106
|
+
/// The assigned variable name where one was available, else a generic stand-in.
|
|
107
|
+
pub var: String,
|
|
108
|
+
/// A human-readable rendering of the resolved schema, from
|
|
109
|
+
/// `Linter::schema_display`: the schema's class name and column set for a named
|
|
110
|
+
/// `BaseSchema`, or `inferred column set {...}` (plus an origin, where known)
|
|
111
|
+
/// for one inferred from `usecols=`/a dict literal/etc.
|
|
112
|
+
pub schema: String,
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/// A statement after which a tracked DataFrame no longer has a column set the checker
|
|
116
|
+
/// can vouch for. Powers `--coverage-detail=explain`'s "tracking ended" listing, so a
|
|
117
|
+
/// run can say exactly which line lost a frame and why.
|
|
118
|
+
///
|
|
119
|
+
/// `outcome` is `"unresolved"` (the frame is still a DataFrame, but its columns are
|
|
120
|
+
/// unknown from here) or `"untracked"` (the name no longer holds that frame, or the
|
|
121
|
+
/// checker can make no claim about it). Line and column are 1-indexed, matching
|
|
122
|
+
/// [`LintError`].
|
|
123
|
+
#[derive(Debug, Serialize)]
|
|
124
|
+
pub struct LegEvent {
|
|
125
|
+
pub line: usize,
|
|
126
|
+
pub col: usize,
|
|
127
|
+
pub var: String,
|
|
128
|
+
pub outcome: String,
|
|
129
|
+
pub reason: String,
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/// One `<load module>.<load function>(...)`-shaped call site found anywhere in a
|
|
133
|
+
/// file by [`crate::linter::LoadCallSiteCollector`]'s unconditional scan -- see
|
|
134
|
+
/// [`FileStats::all_dataframe_calls`]. Line and column are 1-indexed and point at
|
|
135
|
+
/// the call expression itself (e.g. the `pd` in `pd.DataFrame(...)`), NOT at an
|
|
136
|
+
/// enclosing assignment statement the way [`UntypedSite`]/[`TypedSite`] do -- the two
|
|
137
|
+
/// coordinate systems are cross-referenced by LINE only (see
|
|
138
|
+
/// `--coverage-detail=explain` in the CLI), not by column.
|
|
139
|
+
#[derive(Debug, Serialize)]
|
|
140
|
+
pub struct DataFrameCallSite {
|
|
141
|
+
pub line: usize,
|
|
142
|
+
pub col: usize,
|
|
143
|
+
/// E.g. `"pd.DataFrame"`, `"pl.read_csv"`.
|
|
144
|
+
pub label: String,
|
|
145
|
+
/// Human-readable description of the syntactic position this call was found in
|
|
146
|
+
/// (direct assignment, return value, call argument, collection element, ...) --
|
|
147
|
+
/// see `linter::CallContext::describe`.
|
|
148
|
+
pub context: String,
|
|
149
|
+
}
|
|
150
|
+
|
|
88
151
|
/// The JSON payload returned by the `check_file` entry point: the diagnostics plus
|
|
89
152
|
/// coverage stats.
|
|
90
153
|
#[derive(Debug, Serialize)]
|