diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index aff6f1f..d5561bb 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -4,6 +4,10 @@ name: Tests on: [push, pull_request] +env: + # Reruns share run_id; each attempt needs its own parallel coverage report. + COVERALLS_SERVICE_NUMBER: ${{ github.run_id }}-${{ github.run_attempt }} + jobs: packaging: runs-on: ubuntu-latest @@ -40,13 +44,43 @@ jobs: strategy: fail-fast: true matrix: - python-version: ["3.9", "3.10", "3.11"] - polars-version: ["latest"] include: + - python-version: "3.9" + pandas-version: "minimum" + pyarrow-version: "minimum" + polars-version: "none" + - python-version: "3.10" + pandas-version: "latest" + pyarrow-version: "latest" + polars-version: "none" + - python-version: "3.11" + pandas-version: "latest" + pyarrow-version: "latest" + polars-version: "none" + - python-version: "3.11" + pandas-version: "latest" + pyarrow-version: "minimum" + polars-version: "none" + - python-version: "3.11" + pandas-version: "2.3.3" + pyarrow-version: "latest" + polars-version: "none" - python-version: "3.11" + pandas-version: "latest" + pyarrow-version: "latest" + polars-version: "minimum" + - python-version: "3.11" + pandas-version: "latest" + pyarrow-version: "latest" polars-version: "1.31.0" - python-version: "3.11" + pandas-version: "latest" + pyarrow-version: "latest" polars-version: "1.32.0" + - python-version: "3.11" + pandas-version: "latest" + pyarrow-version: "latest" + polars-version: "latest" steps: - name: Checkout repository @@ -61,9 +95,36 @@ jobs: python -m pip install ruff pytest pytest-cov coveralls pip install -r requirements.txt pip install . - - name: Install compatibility Polars version - if: matrix.polars-version != 'latest' - run: python -m pip install 'polars==${{ matrix.polars-version }}' + - name: Install compatibility dependency versions + env: + PANDAS_VERSION: ${{ matrix.pandas-version }} + PYARROW_VERSION: ${{ matrix.pyarrow-version }} + POLARS_VERSION: ${{ matrix.polars-version }} + run: | + python - <<'PY' + import os + import subprocess + import sys + from importlib.metadata import requires + from packaging.requirements import Requirement + + requirements = [Requirement(text) for text in requires("gtfparse")] + pins = [] + for name in ("pandas", "pyarrow", "polars"): + version = os.environ[f"{name.upper()}_VERSION"] + if version == "none": + continue + if version == "minimum": + requirement = next(r for r in requirements if r.name == name) + version = next(s.version for s in requirement.specifier if s.operator == ">=") + pins.append(name if version == "latest" else f"{name}=={version}") + subprocess.run([sys.executable, "-m", "pip", "install", *pins], check=True) + PY + - name: Verify base installation has no Polars + if: matrix.polars-version == 'none' + run: python -c "from importlib.util import find_spec; assert find_spec('polars') is None" + - name: Check installed dependency requirements + run: python -m pip check - name: Run default linting script run: | ./lint.sh @@ -74,7 +135,7 @@ jobs: if: matrix.python-version == '3.11' uses: coverallsapp/github-action@v2.2.3 with: - flag-name: polars-${{ matrix.polars-version }} + flag-name: pandas-${{ matrix.pandas-version }}-arrow-${{ matrix.pyarrow-version }}-polars-${{ matrix.polars-version }} parallel: true coverage: diff --git a/MANIFEST.in b/MANIFEST.in index ba435b8..6dc3690 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,4 @@ include lint.sh test.sh recursive-include tests *.py recursive-include tests/data *.gtf *.gtf.gz +recursive-include benchmarks *.py *.md *.json diff --git a/README.md b/README.md index d88fd21..ed2585f 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,41 @@ gtfparse ======== Parsing tools for GTF (gene transfer format) files. +## Version 3 migration + +`read_gtf`, `parse_gtf`, and `parse_gtf_and_expand_attributes` now return pandas +DataFrames by default. GTF reading uses PyArrow; attribute processing and writing +use pandas. Polars is no longer a required dependency and is imported only for +explicit Polars conversion. Ordinary installations need only pandas and PyArrow. + +```sh +pip install gtfparse +# Optional, for applications that still request Polars frames: +pip install 'gtfparse[polars]' +``` + +```python +from gtfparse import read_gtf, write_gtf + +df = read_gtf("gene_annotations.gtf") # pandas.DataFrame +write_gtf(df, "gene_annotations.gtf.gz") + +# Requires the optional extra: +polars_df = read_gtf("gene_annotations.gtf", result_type="polars") +``` + +Existing pandas and dictionary callers retain their output shape, fixed-column +dtypes, attribute handling, filters, converters and progress callbacks. Applications +that used the previous default Polars output should add `result_type="polars"` +and install the extra, or use pandas methods. `write_gtf` accepts either frame +type. The legacy `parse_with_polars_lazy` helper remains an optional adapter: +it reads the file eagerly and returns a Polars LazyFrame, as before. + +Empty or malformed GTF fields now raise `gtfparse.ParsingError`, including wrong +field counts and invalid numeric fields. Whole comment lines are ignored; +literal `#` inside attributes is preserved. Text and binary streams stay open +after parsing, and gzip is detected from its contents. + ## Reporting parsing progress Pass `progress_callback(stage, completed, total)` to `read_gtf` to connect @@ -17,7 +52,7 @@ does not display a progress bar or add a progress-library dependency. | Stage | Reports | | --- | --- | -| `read` | `(0, None)` before Polars loads/filters the file; `(rows, rows)` after it succeeds | +| `read` | `(0, None)` before loading/filtering the file; `(rows, rows)` after it succeeds | | `attributes` | `(0, rows)`, then every 10,000 rows, then `(rows, rows)` | | `convert` | `(0, None)` before output conversion/transforms; `(rows, rows)` after success | @@ -26,8 +61,7 @@ percentages. `None` means the total is unknown: loading and conversion expose only stage boundaries, so use an indeterminate indicator during those steps. Attribute expansion is omitted when `expand_attribute_column=False`. A stage that fails does not emit completion. An empty filtered result is supported; -its attributes stage emits a single `(0, 0)` event. Empty input files retain -the existing Polars `NoDataError` behavior. +its attributes stage emits a single `(0, 0)` event. Empty input files raise `gtfparse.ParsingError`. For example, with the optional `tqdm` package installed: diff --git a/benchmarks/README.md b/benchmarks/README.md new file mode 100644 index 0000000..06379db --- /dev/null +++ b/benchmarks/README.md @@ -0,0 +1,110 @@ +# GTF reader backend comparison + +Version 3 uses PyArrow for fixed-column parsing and pandas for attribute +processing and writing. Polars is an optional output adapter. This directory +contains the measurement harness and the evidence for that decision. + +## Reproduction + +The recorded runs use Python 3.12.6, NumPy 2.5.3, PyArrow 25.0.1, Polars 1.44.2, +and pandas 2.3.3 or 3.0.6. Install the checkout with `pip install '.[dev,polars]'` +in isolated environments. Run one fresh process at a time with four threads: + +```sh +POLARS_MAX_THREADS=4 python benchmarks/compare_readers.py sample.gtf --backend production +POLARS_MAX_THREADS=4 python benchmarks/compare_readers.py sample.gtf --backend pandas +POLARS_MAX_THREADS=4 python benchmarks/compare_readers.py sample.gtf --backend arrow +POLARS_MAX_THREADS=4 python benchmarks/compare_readers.py sample.gtf --backend arrow-extension +``` + +For the old production baseline, extract commit `3e0912c` (gtfparse 2.9.1) into +a separate directory and use the same harness with `--library-root /path/to/baseline`. +Repeat each combination three times, interleaving readers and reversing their +order for the second repetition. Imports and validation are outside wall/CPU +timing. Peak RSS is the process high-water mark, including imports, captured +before checksumming or constructing a reference frame. OS caches are not flushed. +The shared workstation and short runs limit precise throughput claims. + +Each invocation emits JSON with wall/CPU time, stage timings, pre-validation +peak RSS, versions, dimensions, column order and a content checksum. Hashing +normalizes equivalent string/categorical representations and ordinary numeric +representations. The corpus coordinates are below float64's exact-integer limit; +separate regression tests verify exact parsing of larger int64 coordinates. +Use `--verify` for DataFrame equality against production on small inputs. +`--features exon`, `--usecols seqname start end gene_id transcript_id`, and +`--result-type polars` exercise selective reads and optional conversion. + +## Corpus and equivalence + +- [Ensembl release 114, human GRCh38](https://ftp.ensembl.org/pub/release-114/gtf/homo_sapiens/Homo_sapiens.GRCh38.114.gtf.gz) +- [GENCODE v48, human primary assembly](https://ftp.ebi.ac.uk/pub/databases/gencode/Gencode_human/release_48/gencode.v48.primary_assembly.annotation.gtf.gz) + +The repeated sweep uses the first 250,000 annotation rows of each source with +its original header, in plain and gzip form. The full GENCODE gzip file provides +a separate scaling check on 4,119,244 rows. Original GTFs are not committed. +Input byte sizes, SHA-256 hashes, source URLs and selection rules are in +[results.json](results.json), alongside all 122 retained measurement records, +three-run medians/ranges and stage medians. Discarded production measurements +from before the final filtering changes are excluded. + +All measured readers produce matching hashes, including the full-file pair. +The five real repository fixtures also pass 50 old/new API comparisons and +30 prototype comparisons on each pandas version (160 checks). The API checks +include raw attributes, filtering, selection, aliases, version casts, biotype +inference and converters; separate regressions cover streams, nullable fields, +comments, malformed inputs and progress/cancellation semantics. + +## Production results + +The table shows three-run medians for equivalent pandas output. Complete load +time includes fixed-column reading, attribute expansion, assembly and transforms. + +| pandas | Input (250k rows) | Old seconds | New seconds | Old peak MiB | New peak MiB | +| --- | --- | ---: | ---: | ---: | ---: | +| 2.3.3 | ensembl-250k.gtf | 2.51 | 2.75 | 560 | 614 | +| 2.3.3 | ensembl-250k.gtf.gz | 2.54 | 2.79 | 561 | 613 | +| 2.3.3 | gencode-250k.gtf | 2.08 | 2.42 | 567 | 581 | +| 2.3.3 | gencode-250k.gtf.gz | 2.16 | 2.42 | 568 | 581 | +| 3.0.6 | ensembl-250k.gtf | 2.28 | 2.69 | 552 | 601 | +| 3.0.6 | ensembl-250k.gtf.gz | 2.27 | 2.69 | 553 | 603 | +| 3.0.6 | gencode-250k.gtf | 2.01 | 2.41 | 560 | 597 | +| 3.0.6 | gencode-250k.gtf.gz | 2.03 | 2.44 | 560 | 592 | + +Across these subsets, the new reader takes 1.10–1.20x the old total time and +1.03–1.10x the peak RSS. The single full GENCODE check with pandas 2.3.3 takes +38.88s / 6189 MiB for the baseline and 45.40s / 5348 MiB for version 3: matching +content, 1.17x time, and lower peak memory. This pair verifies scaling and +correctness; one observation per reader does not establish stable throughput. + +The complete-load result meets #69's proposed 1.5x total-time threshold. The +callback `read` stages are different contracts for timing: version 3 includes +stream preprocessing and Arrow-to-pandas conversion; the old reader constructs +Polars frames and converts to pandas later. The reported read-stage times do +not establish the proposed 3x raw-CSV threshold. This migration is justified by +the measured complete-load cost and the user's preference to remove the required +Polars dependency, rather than a claim that Arrow is faster at raw CSV parsing. +Python attribute expansion remains the largest stage (roughly 1.7–1.8s on these +subsets). Eliminating it or changing its semantics is outside this change. + +## Candidate evaluation and limits + +The pandas C prototype is slower end to end on this corpus. The direct Arrow +and Arrow-extension prototypes have similar complete-load costs; extension +scalars introduce iteration/conversion overhead, and nullable dictionary casts +need an object bridge on pandas 2.3.3. These costs are included in the results. +The conventional Arrow-to-pandas path avoids that bridge and preserves the +established fixed-column and attribute output types. + +The three prototypes are measurement tools. They support the paths, gzip, +filters, column selection and result types used here, but not the entire public +API. They omit buffers, custom converters, aliases, biotype inference, quote +cleanup, raw mode and complete progress/failure behavior. The pandas prototype +skips leading comments; the Arrow prototypes skip comment rows only on a field +count mismatch. The production reader implements whole-line comment filtering, +BOM and stream handling, exact field counts, declared numeric types and filtering +before pandas conversion so discarded null coordinates do not change dtypes. + +Pandas reader behavior is documented in +[read_csv](https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html), +and Arrow's typed CSV options in its +[CSV guide](https://arrow.apache.org/docs/python/csv.html). diff --git a/benchmarks/compare_readers.py b/benchmarks/compare_readers.py new file mode 100644 index 0000000..d41778e --- /dev/null +++ b/benchmarks/compare_readers.py @@ -0,0 +1,279 @@ +"""Backend experiment, not an alternative supported reader. + +Run each invocation in a fresh process. See README.md for corpus provenance, +repetition, equivalence checks, and limitations of the experimental readers. +""" + +import argparse +import csv +import gzip +import hashlib +import importlib +import json +import os +import platform +import resource +import sys +from pathlib import Path +from time import perf_counter, process_time + +import pandas as pd +import pyarrow as pa +import pyarrow.compute as pc +import pyarrow.csv as pacsv + +try: + import polars as pl +except ModuleNotFoundError as error: + if error.name != "polars": + raise + pl = None + +# Use the requested checkout before importing gtfparse, for baseline comparisons. +import_options = argparse.ArgumentParser(add_help=False) +import_options.add_argument("--library-root", type=Path) +import_args, _ = import_options.parse_known_args() +library_root = import_args.library_root or Path(__file__).resolve().parents[1] +if not (library_root / "gtfparse" / "__init__.py").is_file(): + import_options.error("--library-root must contain the gtfparse package") +sys.path.insert(0, str(library_root)) +package = importlib.import_module("gtfparse") +__version__ = package.__version__ +expand_attribute_strings = package.expand_attribute_strings +read_gtf = package.read_gtf + +reader = importlib.import_module("gtfparse.read_gtf") +CATEGORIES = ("seqname", "source", "feature", "strand") + + +class Timings: + def __init__(self): + self.stages = {} + self.starts = {} + + def callback(self, stage, completed, total): + if completed == 0: + self.starts[stage] = perf_counter() + if total is not None and completed == total: + self.stages[stage] = perf_counter() - self.starts[stage] + + def run(self, stage, fn): + start = perf_counter() + result = fn() + self.stages[stage] = perf_counter() - start + return result + + +def leading_comments(path): + opener = gzip.open if str(path).endswith(".gz") else open + with opener(path, "rt") as stream: + count = 0 + for line in stream: + if not line.startswith("#"): + break + count += 1 + return count + + +def pandas_read(path, features): + # Explicit object strings match Polars.to_pandas and avoid pandas' default + # NA vocabulary interpreting valid names such as "NA" as missing values. + types = dict.fromkeys(CATEGORIES, "category") + types.update(start="int64", end="int64", score="float32", frame="float64", attribute=object) + frame = pd.read_csv( + path, + sep="\t", + header=None, + names=reader.REQUIRED_COLUMNS, + dtype=types, + engine="c", + quoting=csv.QUOTE_NONE, + skiprows=leading_comments(path), + keep_default_na=False, + na_values=[".", ""], + ) + frame = frame.loc[frame.seqname.notna()] + frame["frame"] = frame["frame"].fillna(0).astype("uint32") + if features: + frame = frame.loc[frame.feature.isin(features)] + frame["attribute"] = frame.attribute.where(frame.attribute.notna(), None) + return frame.reset_index(drop=True) + + +def arrow_read(path, features, extension=False): + types = dict.fromkeys(CATEGORIES, pa.dictionary(pa.int32(), pa.string())) + types.update( + start=pa.int64(), + end=pa.int64(), + score=pa.float32(), + frame=pa.uint32(), + attribute=pa.string(), + ) + table = pacsv.read_csv( + path, + read_options=pacsv.ReadOptions(column_names=reader.REQUIRED_COLUMNS), + parse_options=pacsv.ParseOptions( + delimiter="\t", + quote_char=False, + invalid_row_handler=lambda row: "skip" if row.text.startswith("#") else "error", + ), + convert_options=pacsv.ConvertOptions( + column_types=types, null_values=[".", ""], strings_can_be_null=True + ), + ) + table = table.filter(pc.is_valid(table["seqname"])) + table = table.set_column(7, "frame", pc.fill_null(table["frame"], 0)) + if features: + table = table.filter(pc.is_in(table["feature"], value_set=pa.array(features))) + return table.to_pandas(types_mapper=pd.ArrowDtype if extension else None) + + +def prototype(path, backend, timings, features, usecols, result_type): + if backend == "pandas": + frame = timings.run("read", lambda: pandas_read(path, features)) + else: + frame = timings.run( + "read", lambda: arrow_read(path, features, backend == "arrow-extension") + ) + attributes = frame.pop("attribute") + # Arrow extension scalars use pd.NA; the production expander accepts None. + values = (None if value is pd.NA else value for value in attributes) + if backend == "arrow-extension": + # Materialization belongs in the measured expansion time. + class SizedValues: + def __len__(self): + return len(attributes) + + def __iter__(self): + return values + + attributes_for_expansion = SizedValues() + else: + attributes_for_expansion = attributes + expanded = timings.run( + "attributes", lambda: expand_attribute_strings(attributes_for_expansion, usecols=usecols) + ) + # Match pandas 2 object strings / pandas 3 inferred StringDtype, as returned + # by the production reader's Arrow-to-pandas conversion on each version. + frame = timings.run("assemble", lambda: pd.concat([frame, pd.DataFrame(expanded)], axis=1)) + attributes = attributes_for_expansion = values = expanded = None + + def finish(): + nonlocal frame + if backend == "arrow-extension": + for name in CATEGORIES: + # pandas 2.3 cannot directly cast an Arrow dictionary with + # null indices to category (its zero-copy conversion fails). + # Include the object bridge in this prototype's measured cost. + frame[name] = frame[name].astype(object).astype("category") + for name, dtype in { + "start": "int64", + "end": "int64", + "score": "float32", + "frame": "uint32", + }.items(): + frame[name] = frame[name].astype(dtype) + frame = reader._cast_version_columns(frame) + if usecols is not None: + frame = frame[[name for name in usecols if name in frame]] + return pl.from_pandas(frame) if result_type == "polars" else frame + + return timings.run("convert", finish) + + +def checksum(frame): + """Hash all values and column order, ignoring categorical dictionary order.""" + if pl is not None and isinstance(frame, pl.DataFrame): + frame = frame.to_pandas() + digest = hashlib.sha256(json.dumps(list(frame.columns)).encode()) + for name in frame.columns: + values = frame[name] + if pd.api.types.is_numeric_dtype(values.dtype): + values = values.astype("float64") + else: + values = values.astype(object).where(values.notna(), None) + digest.update(pd.util.hash_pandas_object(values, index=False).values.tobytes()) + return digest.hexdigest() + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("path", type=Path) + parser.add_argument("--library-root", type=Path, help="Read from another gtfparse checkout") + parser.add_argument( + "--backend", + choices=["production", "pandas", "arrow", "arrow-extension"], + default="production", + ) + parser.add_argument("--threads", type=int, default=4) + parser.add_argument("--result-type", choices=["pandas", "polars"], default="pandas") + parser.add_argument("--features", nargs="+") + parser.add_argument("--usecols", nargs="+") + parser.add_argument( + "--verify", + action="store_true", + help="Compare to production output after timing (small inputs).", + ) + args = parser.parse_args() + if args.result_type == "polars" and pl is None: + parser.error("Polars output requires pip install 'gtfparse[polars]'") + if pl is not None and pl.thread_pool_size() != args.threads: + parser.error("Set POLARS_MAX_THREADS before starting the process to match --threads") + pa.set_cpu_count(args.threads) + timings = Timings() + start, cpu_start = perf_counter(), process_time() + if args.backend == "production": + frame = read_gtf( + str(args.path), + result_type=args.result_type, + features=args.features, + usecols=args.usecols, + progress_callback=timings.callback, + ) + else: + frame = prototype( + str(args.path), args.backend, timings, args.features, args.usecols, args.result_type + ) + elapsed, cpu = perf_counter() - start, process_time() - cpu_start + peak = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + peak_mib = peak / (1024**2 if sys.platform == "darwin" else 1024) + # Capture the high-water mark BEFORE hashing, comparison, or output sizing. + timings.stages["other"] = elapsed - sum(timings.stages.values()) + output = { + "path": str(args.path), + "input_bytes": args.path.stat().st_size, + "backend": args.backend, + "result_type": args.result_type, + "features": args.features, + "usecols": args.usecols, + "threads": args.threads, + "wall_seconds": elapsed, + "cpu_seconds": cpu, + "peak_rss_mib": peak_mib, + "stages": timings.stages, + "rows": len(frame), + "columns": list(frame.columns), + "checksum": checksum(frame), + "versions": { + "gtfparse": __version__, + "pandas": pd.__version__, + "polars": pl.__version__ if pl is not None else None, + "pyarrow": pa.__version__, + "python": platform.python_version(), + }, + "platform": platform.platform(), + "cpu_count": os.cpu_count(), + } + if args.verify: + reference = read_gtf( + str(args.path), result_type="pandas", features=args.features, usecols=args.usecols + ) + actual = frame.to_pandas() if pl is not None and isinstance(frame, pl.DataFrame) else frame + pd.testing.assert_frame_equal(reference, actual, check_categorical=False) + assert checksum(reference) == output["checksum"] + output["verified"] = True + print(json.dumps(output, sort_keys=True)) + + +if __name__ == "__main__": + main() diff --git a/benchmarks/results.json b/benchmarks/results.json new file mode 100644 index 0000000..e780deb --- /dev/null +++ b/benchmarks/results.json @@ -0,0 +1,8335 @@ +{ + "description": "Fresh-process runs; production pairs restarted after final reader changes. Prototypes unchanged. Full GENCODE scaling check is one run per reader, not a throughput estimate.", + "date": "2026-10-05", + "threads": 4, + "numpy_version": "2.5.3", + "inputs": { + "ensembl-250k.gtf": { + "bytes": 111900013, + "sha256": "ac84dc46b89df30eea025c5a36ea3c452f6546be037f77d1eb68fa813226958e", + "rows": 250000, + "source_url": "https://ftp.ensembl.org/pub/release-114/gtf/homo_sapiens/Homo_sapiens.GRCh38.114.gtf.gz", + "selection": "first 250000 annotation rows plus original header" + }, + "ensembl-250k.gtf.gz": { + "bytes": 3524624, + "sha256": "3000128cb22ea68754c01bd3d72fe347c9c86d05b9cae9fed65d1440c57291cd", + "rows": 250000, + "source_url": "https://ftp.ensembl.org/pub/release-114/gtf/homo_sapiens/Homo_sapiens.GRCh38.114.gtf.gz", + "selection": "first 250000 annotation rows plus original header" + }, + "gencode-250k.gtf": { + "bytes": 109586053, + "sha256": "04e929726d7c7837c7669b3795883b55537d389274ba6661a8ab56b5df06bc23", + "rows": 250000, + "source_url": "https://ftp.ebi.ac.uk/pub/databases/gencode/Gencode_human/release_48/gencode.v48.primary_assembly.annotation.gtf.gz", + "selection": "first 250000 annotation rows plus original header" + }, + "gencode-250k.gtf.gz": { + "bytes": 3520115, + "sha256": "6d560c4098d78e6beb8616f08e2bdbbf3071a026edca622e505e294be7f5011d", + "rows": 250000, + "source_url": "https://ftp.ebi.ac.uk/pub/databases/gencode/Gencode_human/release_48/gencode.v48.primary_assembly.annotation.gtf.gz", + "selection": "first 250000 annotation rows plus original header" + }, + "gencode.v48.primary_assembly.annotation.gtf.gz": { + "bytes": 59094311, + "sha256": "ad15e956fb7643172afca6dcaae176cc76400532392978a191c981d0a052e668", + "rows": 4119244, + "source_url": "https://ftp.ebi.ac.uk/pub/databases/gencode/Gencode_human/release_48/gencode.v48.primary_assembly.annotation.gtf.gz", + "selection": "full file" + } + }, + "summaries": [ + { + "pandas": "2.3.3", + "input": "ensembl-250k.gtf", + "backend": "baseline-polars", + "runs": 3, + "wall_seconds": { + "median": 2.50767745799385, + "min": 2.4167797090049135, + "max": 2.6048407500056783 + }, + "cpu_seconds": { + "median": 2.532277, + "min": 2.509217, + "max": 2.586528 + }, + "peak_rss_mib": { + "median": 560.234375, + "min": 559.875, + "max": 618.859375 + }, + "stage_medians": { + "attributes": 1.8099998749967199, + "convert": 0.3262738339981297, + "other": 0.22537416701379698, + "read": 0.07233362500846852 + }, + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8" + }, + { + "pandas": "2.3.3", + "input": "ensembl-250k.gtf", + "backend": "production-arrow", + "runs": 3, + "wall_seconds": { + "median": 2.748753874999238, + "min": 2.74568508300581, + "max": 2.8131792500062147 + }, + "cpu_seconds": { + "median": 2.830405, + "min": 2.8301100000000003, + "max": 2.9099049999999997 + }, + "peak_rss_mib": { + "median": 614.1875, + "min": 612.34375, + "max": 614.21875 + }, + "stage_medians": { + "attributes": 1.7827446669980418, + "convert": 0.2741778339986922, + "other": 0.43743074900703505, + "read": 0.25886041700141504 + }, + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8" + }, + { + "pandas": "2.3.3", + "input": "ensembl-250k.gtf", + "backend": "prototype-arrow", + "runs": 3, + "wall_seconds": { + "median": 2.69034579199797, + "min": 2.644828125005006, + "max": 2.805704082988086 + }, + "cpu_seconds": { + "median": 2.752299, + "min": 2.7294769999999997, + "max": 2.7703979999999997 + }, + "peak_rss_mib": { + "median": 795.484375, + "min": 777.296875, + "max": 797.359375 + }, + "stage_medians": { + "assemble": 0.46840795800380874, + "attributes": 1.7804561669909162, + "convert": 0.2713034580083331, + "other": 0.03142008300346788, + "read": 0.10576299999956973 + }, + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8" + }, + { + "pandas": "2.3.3", + "input": "ensembl-250k.gtf", + "backend": "prototype-arrow-extension", + "runs": 3, + "wall_seconds": { + "median": 2.7656924999901094, + "min": 2.733067666005809, + "max": 2.783953542006202 + }, + "cpu_seconds": { + "median": 2.838592, + "min": 2.808318, + "max": 2.848519 + }, + "peak_rss_mib": { + "median": 676.09375, + "min": 672.6875, + "max": 677.25 + }, + "stage_medians": { + "assemble": 0.4772016249917215, + "attributes": 1.9034146659978433, + "convert": 0.3002569590025814, + "other": 0.024680625996552408, + "read": 0.045068040999467485 + }, + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8" + }, + { + "pandas": "2.3.3", + "input": "ensembl-250k.gtf", + "backend": "prototype-pandas-c", + "runs": 3, + "wall_seconds": { + "median": 3.4266044160031015, + "min": 3.426066957996227, + "max": 3.4696247919928282 + }, + "cpu_seconds": { + "median": 3.408847, + "min": 3.408119, + "max": 3.450481 + }, + "peak_rss_mib": { + "median": 592.921875, + "min": 590.515625, + "max": 593.5 + }, + "stage_medians": { + "assemble": 0.4621411660045851, + "attributes": 1.7807112499867799, + "convert": 0.26976025001204107, + "other": 0.03221445700910408, + "read": 0.8835250840056688 + }, + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8" + }, + { + "pandas": "2.3.3", + "input": "ensembl-250k.gtf.gz", + "backend": "baseline-polars", + "runs": 3, + "wall_seconds": { + "median": 2.536495082997135, + "min": 2.463866334001068, + "max": 2.569504541999777 + }, + "cpu_seconds": { + "median": 2.583748, + "min": 2.55136, + "max": 2.655658 + }, + "peak_rss_mib": { + "median": 561.125, + "min": 561.0, + "max": 561.1875 + }, + "stage_medians": { + "attributes": 1.8108490000013262, + "convert": 0.3234495000069728, + "other": 0.21961133400327526, + "read": 0.12502779100032058 + }, + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8" + }, + { + "pandas": "2.3.3", + "input": "ensembl-250k.gtf.gz", + "backend": "production-arrow", + "runs": 3, + "wall_seconds": { + "median": 2.7918276249984046, + "min": 2.783365875002346, + "max": 2.7975592910079286 + }, + "cpu_seconds": { + "median": 2.8766249999999998, + "min": 2.8691079999999998, + "max": 2.8841460000000003 + }, + "peak_rss_mib": { + "median": 612.9375, + "min": 612.640625, + "max": 614.984375 + }, + "stage_medians": { + "attributes": 1.7776395420078188, + "convert": 0.27137179199780803, + "other": 0.4791868339962093, + "read": 0.2667071250034496 + }, + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8" + }, + { + "pandas": "2.3.3", + "input": "ensembl-250k.gtf.gz", + "backend": "prototype-arrow", + "runs": 3, + "wall_seconds": { + "median": 2.695920208003372, + "min": 2.6938214999972843, + "max": 2.7072011249983916 + }, + "cpu_seconds": { + "median": 2.780826, + "min": 2.772733, + "max": 2.786536 + }, + "peak_rss_mib": { + "median": 795.265625, + "min": 780.796875, + "max": 809.765625 + }, + "stage_medians": { + "assemble": 0.4699894580116961, + "attributes": 1.777190792010515, + "convert": 0.2708022079896182, + "other": 0.031385291993501596, + "read": 0.14110441699449439 + }, + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8" + }, + { + "pandas": "2.3.3", + "input": "ensembl-250k.gtf.gz", + "backend": "prototype-arrow-extension", + "runs": 3, + "wall_seconds": { + "median": 2.7992065409926, + "min": 2.786770292004803, + "max": 2.870876999993925 + }, + "cpu_seconds": { + "median": 2.879623, + "min": 2.864295, + "max": 2.9541489999999997 + }, + "peak_rss_mib": { + "median": 676.734375, + "min": 674.515625, + "max": 678.125 + }, + "stage_medians": { + "assemble": 0.4658856250025565, + "attributes": 1.9208032500027912, + "convert": 0.3009340420103399, + "other": 0.024476584017975256, + "read": 0.08551900000020396 + }, + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8" + }, + { + "pandas": "2.3.3", + "input": "ensembl-250k.gtf.gz", + "backend": "prototype-pandas-c", + "runs": 3, + "wall_seconds": { + "median": 3.4536602919979487, + "min": 3.4344881660072133, + "max": 3.466108250009711 + }, + "cpu_seconds": { + "median": 3.438771, + "min": 3.423718, + "max": 3.4502949999999997 + }, + "peak_rss_mib": { + "median": 591.796875, + "min": 591.765625, + "max": 593.765625 + }, + "stage_medians": { + "assemble": 0.46626166701025795, + "attributes": 1.7850957499904325, + "convert": 0.26819329100544564, + "other": 0.032728042016969994, + "read": 0.9014286669989815 + }, + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8" + }, + { + "pandas": "2.3.3", + "input": "gencode-250k.gtf", + "backend": "baseline-polars", + "runs": 3, + "wall_seconds": { + "median": 2.08075937499234, + "min": 2.0796830839972245, + "max": 2.2701515420048963 + }, + "cpu_seconds": { + "median": 2.170746, + "min": 2.167786, + "max": 2.204866 + }, + "peak_rss_mib": { + "median": 567.265625, + "min": 566.90625, + "max": 567.546875 + }, + "stage_medians": { + "attributes": 1.7048044170078356, + "convert": 0.06747745799657423, + "other": 0.24779787599982228, + "read": 0.0663892080046935 + }, + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641" + }, + { + "pandas": "2.3.3", + "input": "gencode-250k.gtf", + "backend": "production-arrow", + "runs": 3, + "wall_seconds": { + "median": 2.420598124997923, + "min": 2.407677416995284, + "max": 2.4845118329976685 + }, + "cpu_seconds": { + "median": 2.4982200000000003, + "min": 2.49164, + "max": 2.502798 + }, + "peak_rss_mib": { + "median": 580.640625, + "min": 580.46875, + "max": 581.703125 + }, + "stage_medians": { + "attributes": 1.6796663339919178, + "convert": 6.991699046920985e-05, + "other": 0.49265141601790674, + "read": 0.23747916700085625 + }, + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641" + }, + { + "pandas": "2.3.3", + "input": "gencode-250k.gtf", + "backend": "prototype-arrow", + "runs": 3, + "wall_seconds": { + "median": 2.335685250000097, + "min": 2.3259424999996554, + "max": 2.3647148750023916 + }, + "cpu_seconds": { + "median": 2.4162429999999997, + "min": 2.41204, + "max": 2.439682 + }, + "peak_rss_mib": { + "median": 769.015625, + "min": 743.84375, + "max": 770.25 + }, + "stage_medians": { + "assemble": 0.5368626249983208, + "attributes": 1.6809838750050403, + "convert": 7.208299939520657e-05, + "other": 0.028512125994893722, + "read": 0.08925720800471026 + }, + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641" + }, + { + "pandas": "2.3.3", + "input": "gencode-250k.gtf", + "backend": "prototype-arrow-extension", + "runs": 3, + "wall_seconds": { + "median": 2.457704875007039, + "min": 2.457704082989949, + "max": 2.52258275001077 + }, + "cpu_seconds": { + "median": 2.541571, + "min": 2.528665, + "max": 2.6052470000000003 + }, + "peak_rss_mib": { + "median": 673.8125, + "min": 668.0625, + "max": 673.96875 + }, + "stage_medians": { + "assemble": 0.5393599590024678, + "attributes": 1.827468333998695, + "convert": 0.033272499989834614, + "other": 0.023252166007296182, + "read": 0.04739100000006147 + }, + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641" + }, + { + "pandas": "2.3.3", + "input": "gencode-250k.gtf", + "backend": "prototype-pandas-c", + "runs": 3, + "wall_seconds": { + "median": 2.9740136670006905, + "min": 2.932476208996377, + "max": 2.9861979999986943 + }, + "cpu_seconds": { + "median": 2.962694, + "min": 2.919864, + "max": 2.964733 + }, + "peak_rss_mib": { + "median": 558.890625, + "min": 557.3125, + "max": 559.03125 + }, + "stage_medians": { + "assemble": 0.5376986250048503, + "attributes": 1.6928435830050148, + "convert": 7.56250083213672e-05, + "other": 0.025882959977025166, + "read": 0.690131666007801 + }, + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641" + }, + { + "pandas": "2.3.3", + "input": "gencode-250k.gtf.gz", + "backend": "baseline-polars", + "runs": 3, + "wall_seconds": { + "median": 2.1628670829959447, + "min": 2.157319291989552, + "max": 2.195697041999665 + }, + "cpu_seconds": { + "median": 2.242196, + "min": 2.227829, + "max": 2.279296 + }, + "peak_rss_mib": { + "median": 568.15625, + "min": 567.421875, + "max": 568.171875 + }, + "stage_medians": { + "attributes": 1.7160745419969317, + "convert": 0.06709170900285244, + "other": 0.277263915995718, + "read": 0.11776566600019578 + }, + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641" + }, + { + "pandas": "2.3.3", + "input": "gencode-250k.gtf.gz", + "backend": "production-arrow", + "runs": 3, + "wall_seconds": { + "median": 2.416197208003723, + "min": 2.4016492090013344, + "max": 2.4482553330017254 + }, + "cpu_seconds": { + "median": 2.499142, + "min": 2.483425, + "max": 2.535609 + }, + "peak_rss_mib": { + "median": 581.4375, + "min": 579.578125, + "max": 583.34375 + }, + "stage_medians": { + "attributes": 1.6758758750074776, + "convert": 6.670800212305039e-05, + "other": 0.4930691249901429, + "read": 0.2519053330033785 + }, + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641" + }, + { + "pandas": "2.3.3", + "input": "gencode-250k.gtf.gz", + "backend": "prototype-arrow", + "runs": 3, + "wall_seconds": { + "median": 2.359796542004915, + "min": 2.3514505829953123, + "max": 2.6530983749980805 + }, + "cpu_seconds": { + "median": 2.437506, + "min": 2.4297129999999996, + "max": 2.7121690000000003 + }, + "peak_rss_mib": { + "median": 741.953125, + "min": 740.40625, + "max": 743.296875 + }, + "stage_medians": { + "assemble": 0.5307892499986337, + "attributes": 1.6777252500032773, + "convert": 7.454201113432646e-05, + "other": 0.027927374001592398, + "read": 0.12612445799459238 + }, + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641" + }, + { + "pandas": "2.3.3", + "input": "gencode-250k.gtf.gz", + "backend": "prototype-arrow-extension", + "runs": 3, + "wall_seconds": { + "median": 2.4941829579911428, + "min": 2.4861365419928916, + "max": 2.6947343749925494 + }, + "cpu_seconds": { + "median": 2.569193, + "min": 2.5599760000000003, + "max": 2.769798 + }, + "peak_rss_mib": { + "median": 669.984375, + "min": 669.65625, + "max": 672.3125 + }, + "stage_medians": { + "assemble": 0.5313982910010964, + "attributes": 1.827811124996515, + "convert": 0.03409316699253395, + "other": 0.02363874900038354, + "read": 0.08316808300151024 + }, + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641" + }, + { + "pandas": "2.3.3", + "input": "gencode-250k.gtf.gz", + "backend": "prototype-pandas-c", + "runs": 3, + "wall_seconds": { + "median": 2.9502709999942454, + "min": 2.94213112500438, + "max": 3.220512708008755 + }, + "cpu_seconds": { + "median": 2.93263, + "min": 2.9312679999999998, + "max": 3.162574 + }, + "peak_rss_mib": { + "median": 556.96875, + "min": 554.921875, + "max": 559.984375 + }, + "stage_medians": { + "assemble": 0.5318250420095865, + "attributes": 1.6793515419994947, + "convert": 7.037499744910747e-05, + "other": 0.025611374992877245, + "read": 0.7157836249971297 + }, + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641" + }, + { + "pandas": "2.3.3", + "input": "gencode.v48.primary_assembly.annotation.gtf.gz", + "backend": "baseline-polars", + "runs": 1, + "wall_seconds": { + "median": 38.878170791009325, + "min": 38.878170791009325, + "max": 38.878170791009325 + }, + "cpu_seconds": { + "median": 39.251256999999995, + "min": 39.251256999999995, + "max": 39.251256999999995 + }, + "peak_rss_mib": { + "median": 6188.953125, + "min": 6188.953125, + "max": 6188.953125 + }, + "stage_medians": { + "attributes": 29.488969624988385, + "convert": 1.3856575840036385, + "other": 6.25970354101446, + "read": 1.7438400410028407 + }, + "checksum": "52d9ca5d36dd0795856c27637e70e93cff34511b12226af66a07b4eb114d3d49" + }, + { + "pandas": "2.3.3", + "input": "gencode.v48.primary_assembly.annotation.gtf.gz", + "backend": "production-arrow", + "runs": 1, + "wall_seconds": { + "median": 45.399839042001986, + "min": 45.399839042001986, + "max": 45.399839042001986 + }, + "cpu_seconds": { + "median": 45.59134400000001, + "min": 45.59134400000001, + "max": 45.59134400000001 + }, + "peak_rss_mib": { + "median": 5347.96875, + "min": 5347.96875, + "max": 5347.96875 + }, + "stage_medians": { + "attributes": 29.7058007500018, + "convert": 0.00020145899907220155, + "other": 10.916198416001862, + "read": 4.7776384169992525 + }, + "checksum": "52d9ca5d36dd0795856c27637e70e93cff34511b12226af66a07b4eb114d3d49" + }, + { + "pandas": "3.0.6", + "input": "ensembl-250k.gtf", + "backend": "baseline-polars", + "runs": 3, + "wall_seconds": { + "median": 2.2791395840031328, + "min": 2.255381042006775, + "max": 2.5150562499911757 + }, + "cpu_seconds": { + "median": 2.3615969999999997, + "min": 2.339194, + "max": 2.376628 + }, + "peak_rss_mib": { + "median": 552.375, + "min": 552.28125, + "max": 552.59375 + }, + "stage_medians": { + "attributes": 1.8084887080040062, + "convert": 0.20205358300881926, + "other": 0.2428244159964379, + "read": 0.02499925000302028 + }, + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8" + }, + { + "pandas": "3.0.6", + "input": "ensembl-250k.gtf", + "backend": "production-arrow", + "runs": 3, + "wall_seconds": { + "median": 2.692364832997555, + "min": 2.692001709001488, + "max": 2.701433875001385 + }, + "cpu_seconds": { + "median": 2.7754659999999998, + "min": 2.772764, + "max": 2.7840759999999998 + }, + "peak_rss_mib": { + "median": 600.875, + "min": 595.75, + "max": 604.296875 + }, + "stage_medians": { + "attributes": 1.7806279579963302, + "convert": 0.1821750829985831, + "other": 0.5269170020037564, + "read": 0.20570887500070967 + }, + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8" + }, + { + "pandas": "3.0.6", + "input": "ensembl-250k.gtf", + "backend": "prototype-arrow", + "runs": 3, + "wall_seconds": { + "median": 2.988341667005443, + "min": 2.7026060420030262, + "max": 3.052398665997316 + }, + "cpu_seconds": { + "median": 2.95458, + "min": 2.783836, + "max": 3.0227939999999998 + }, + "peak_rss_mib": { + "median": 588.71875, + "min": 574.140625, + "max": 595.234375 + }, + "stage_medians": { + "assemble": 0.48928570799762383, + "attributes": 2.1219689170102356, + "convert": 0.19091441699129064, + "other": 0.07707174800452776, + "read": 0.07791937500587665 + }, + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8" + }, + { + "pandas": "3.0.6", + "input": "ensembl-250k.gtf", + "backend": "prototype-arrow-extension", + "runs": 3, + "wall_seconds": { + "median": 2.986602374992799, + "min": 2.7652547920006327, + "max": 3.001149000003352 + }, + "cpu_seconds": { + "median": 2.983625, + "min": 2.850217, + "max": 3.034187 + }, + "peak_rss_mib": { + "median": 582.28125, + "min": 575.375, + "max": 599.09375 + }, + "stage_medians": { + "assemble": 0.49442504199396353, + "attributes": 2.0805143330071587, + "convert": 0.24380533400108106, + "other": 0.07692641601897776, + "read": 0.06480474999989383 + }, + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8" + }, + { + "pandas": "3.0.6", + "input": "ensembl-250k.gtf", + "backend": "prototype-pandas-c", + "runs": 3, + "wall_seconds": { + "median": 3.7077997919986956, + "min": 3.470695958007127, + "max": 4.382947917009005 + }, + "cpu_seconds": { + "median": 3.653487, + "min": 3.4492960000000004, + "max": 4.014492 + }, + "peak_rss_mib": { + "median": 573.21875, + "min": 506.640625, + "max": 573.3125 + }, + "stage_medians": { + "assemble": 0.5052536250004778, + "attributes": 1.9766707090020645, + "convert": 0.20139558298978955, + "other": 0.08260437400895171, + "read": 0.9398529580066679 + }, + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8" + }, + { + "pandas": "3.0.6", + "input": "ensembl-250k.gtf.gz", + "backend": "baseline-polars", + "runs": 3, + "wall_seconds": { + "median": 2.2739015410043066, + "min": 2.2637062090070685, + "max": 2.310322459001327 + }, + "cpu_seconds": { + "median": 2.350597, + "min": 2.341782, + "max": 2.381838 + }, + "peak_rss_mib": { + "median": 553.203125, + "min": 552.890625, + "max": 553.609375 + }, + "stage_medians": { + "attributes": 1.791869416992995, + "convert": 0.19761208399722818, + "other": 0.21492508200753946, + "read": 0.06953970799804665 + }, + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8" + }, + { + "pandas": "3.0.6", + "input": "ensembl-250k.gtf.gz", + "backend": "production-arrow", + "runs": 3, + "wall_seconds": { + "median": 2.689811375006684, + "min": 2.671162540995283, + "max": 2.717027833001339 + }, + "cpu_seconds": { + "median": 2.774547, + "min": 2.755722, + "max": 2.7980669999999996 + }, + "peak_rss_mib": { + "median": 603.453125, + "min": 588.328125, + "max": 603.671875 + }, + "stage_medians": { + "attributes": 1.7718397910066415, + "convert": 0.18202091699640732, + "other": 0.5186047930037603, + "read": 0.2146282500034431 + }, + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8" + }, + { + "pandas": "3.0.6", + "input": "ensembl-250k.gtf.gz", + "backend": "prototype-arrow", + "runs": 3, + "wall_seconds": { + "median": 2.951493667002069, + "min": 2.9194425839959877, + "max": 2.9708941249991767 + }, + "cpu_seconds": { + "median": 3.0221340000000003, + "min": 2.884428, + "max": 3.035487 + }, + "peak_rss_mib": { + "median": 594.6875, + "min": 584.59375, + "max": 595.21875 + }, + "stage_medians": { + "assemble": 0.4505555829964578, + "attributes": 2.1193705829937244, + "convert": 0.19004050000512507, + "other": 0.07287595899833832, + "read": 0.10452266701031476 + }, + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8" + }, + { + "pandas": "3.0.6", + "input": "ensembl-250k.gtf.gz", + "backend": "prototype-arrow-extension", + "runs": 3, + "wall_seconds": { + "median": 2.970901666994905, + "min": 2.8857394579972606, + "max": 3.1069664169917814 + }, + "cpu_seconds": { + "median": 3.038281, + "min": 2.94851, + "max": 3.164935 + }, + "peak_rss_mib": { + "median": 573.109375, + "min": 569.03125, + "max": 594.390625 + }, + "stage_medians": { + "assemble": 0.47618904199043754, + "attributes": 2.0443969999905676, + "convert": 0.24324787501245737, + "other": 0.08042750097229145, + "read": 0.10567258299852256 + }, + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8" + }, + { + "pandas": "3.0.6", + "input": "ensembl-250k.gtf.gz", + "backend": "prototype-pandas-c", + "runs": 3, + "wall_seconds": { + "median": 3.6533958750078455, + "min": 3.5007433330029016, + "max": 3.8157930000015767 + }, + "cpu_seconds": { + "median": 3.6022719999999997, + "min": 3.4855650000000002, + "max": 3.712797 + }, + "peak_rss_mib": { + "median": 573.640625, + "min": 573.53125, + "max": 577.890625 + }, + "stage_medians": { + "assemble": 0.5160652500053402, + "attributes": 1.881623875000514, + "convert": 0.19371162499010097, + "other": 0.09454695800377522, + "read": 0.9651943750068313 + }, + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8" + }, + { + "pandas": "3.0.6", + "input": "gencode-250k.gtf", + "backend": "baseline-polars", + "runs": 3, + "wall_seconds": { + "median": 2.010576000000583, + "min": 1.9673579999944195, + "max": 2.17220954199729 + }, + "cpu_seconds": { + "median": 2.0917120000000002, + "min": 2.04725, + "max": 2.10306 + }, + "peak_rss_mib": { + "median": 559.59375, + "min": 559.109375, + "max": 562.0 + }, + "stage_medians": { + "attributes": 1.7087899999896763, + "convert": 0.016985291003948078, + "other": 0.24184804198739585, + "read": 0.02415333299722988 + }, + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641" + }, + { + "pandas": "3.0.6", + "input": "gencode-250k.gtf", + "backend": "production-arrow", + "runs": 3, + "wall_seconds": { + "median": 2.4137702910084045, + "min": 2.4088208749890327, + "max": 2.4151808750029886 + }, + "cpu_seconds": { + "median": 2.49517, + "min": 2.489892, + "max": 2.49562 + }, + "peak_rss_mib": { + "median": 596.703125, + "min": 590.546875, + "max": 600.765625 + }, + "stage_medians": { + "attributes": 1.670675666013267, + "convert": 0.0001568750012665987, + "other": 0.5410162919870345, + "read": 0.19824704100028612 + }, + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641" + }, + { + "pandas": "3.0.6", + "input": "gencode-250k.gtf", + "backend": "prototype-arrow", + "runs": 3, + "wall_seconds": { + "median": 2.685528834001161, + "min": 2.4137239579868037, + "max": 2.800890166996396 + }, + "cpu_seconds": { + "median": 2.689543, + "min": 2.507308, + "max": 2.779331 + }, + "peak_rss_mib": { + "median": 584.21875, + "min": 539.078125, + "max": 601.65625 + }, + "stage_medians": { + "assemble": 0.5544974590011407, + "attributes": 1.9615897920011776, + "convert": 0.00021449998894240707, + "other": 0.0912805429979926, + "read": 0.05613087500387337 + }, + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641" + }, + { + "pandas": "3.0.6", + "input": "gencode-250k.gtf", + "backend": "prototype-arrow-extension", + "runs": 3, + "wall_seconds": { + "median": 2.5283115419879323, + "min": 2.4529244999866933, + "max": 2.8435980830108747 + }, + "cpu_seconds": { + "median": 2.60785, + "min": 2.534469, + "max": 2.8060419999999997 + }, + "peak_rss_mib": { + "median": 583.640625, + "min": 561.375, + "max": 585.859375 + }, + "stage_medians": { + "assemble": 0.4587894580035936, + "attributes": 1.872884750002413, + "convert": 0.048764582999865524, + "other": 0.08184995998453815, + "read": 0.06602279099752195 + }, + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641" + }, + { + "pandas": "3.0.6", + "input": "gencode-250k.gtf", + "backend": "prototype-pandas-c", + "runs": 3, + "wall_seconds": { + "median": 3.2254527500044787, + "min": 2.980735999997705, + "max": 3.315228167004534 + }, + "cpu_seconds": { + "median": 3.109371, + "min": 2.968477, + "max": 3.247476 + }, + "peak_rss_mib": { + "median": 548.09375, + "min": 547.0625, + "max": 548.28125 + }, + "stage_medians": { + "assemble": 0.5159829589974834, + "attributes": 1.859943834002479, + "convert": 0.00016987499839160591, + "other": 0.08927978998690378, + "read": 0.7600912500056438 + }, + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641" + }, + { + "pandas": "3.0.6", + "input": "gencode-250k.gtf.gz", + "backend": "baseline-polars", + "runs": 3, + "wall_seconds": { + "median": 2.0318973749963334, + "min": 2.013855249999324, + "max": 2.0424441669892985 + }, + "cpu_seconds": { + "median": 2.104431, + "min": 2.086296, + "max": 2.117636 + }, + "peak_rss_mib": { + "median": 559.90625, + "min": 559.859375, + "max": 610.75 + }, + "stage_medians": { + "attributes": 1.6907424169912701, + "convert": 0.01633008300268557, + "other": 0.2596461249922868, + "read": 0.06748079200042412 + }, + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641" + }, + { + "pandas": "3.0.6", + "input": "gencode-250k.gtf.gz", + "backend": "production-arrow", + "runs": 3, + "wall_seconds": { + "median": 2.4420907909952803, + "min": 2.437713707986404, + "max": 2.471340541000245 + }, + "cpu_seconds": { + "median": 2.523304, + "min": 2.517993, + "max": 2.554192 + }, + "peak_rss_mib": { + "median": 592.03125, + "min": 587.796875, + "max": 597.5625 + }, + "stage_medians": { + "attributes": 1.692874207990826, + "convert": 0.0001500000071246177, + "other": 0.5388103739824146, + "read": 0.21212820798973553 + }, + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641" + }, + { + "pandas": "3.0.6", + "input": "gencode-250k.gtf.gz", + "backend": "prototype-arrow", + "runs": 3, + "wall_seconds": { + "median": 2.4617267080029706, + "min": 2.454560832993593, + "max": 2.719684541996685 + }, + "cpu_seconds": { + "median": 2.537875, + "min": 2.536504, + "max": 2.780145 + }, + "peak_rss_mib": { + "median": 592.140625, + "min": 587.03125, + "max": 592.453125 + }, + "stage_medians": { + "assemble": 0.4545573340001283, + "attributes": 1.8455196660070214, + "convert": 0.00017299999308306724, + "other": 0.07983425000566058, + "read": 0.09281091700540856 + }, + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641" + }, + { + "pandas": "3.0.6", + "input": "gencode-250k.gtf.gz", + "backend": "prototype-arrow-extension", + "runs": 3, + "wall_seconds": { + "median": 2.4940239579882473, + "min": 2.4693346669955645, + "max": 2.982795707997866 + }, + "cpu_seconds": { + "median": 2.5754379999999997, + "min": 2.574937, + "max": 2.914624 + }, + "peak_rss_mib": { + "median": 583.140625, + "min": 549.953125, + "max": 599.359375 + }, + "stage_medians": { + "assemble": 0.4434820000024047, + "attributes": 1.8369666249927832, + "convert": 0.04654558400216047, + "other": 0.07880983297945932, + "read": 0.09350162500049919 + }, + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641" + }, + { + "pandas": "3.0.6", + "input": "gencode-250k.gtf.gz", + "backend": "prototype-pandas-c", + "runs": 3, + "wall_seconds": { + "median": 3.002852707999409, + "min": 2.9854611250048038, + "max": 3.273032584009343 + }, + "cpu_seconds": { + "median": 2.990229, + "min": 2.971934, + "max": 3.212746 + }, + "peak_rss_mib": { + "median": 549.453125, + "min": 548.359375, + "max": 550.40625 + }, + "stage_medians": { + "assemble": 0.5018430839991197, + "attributes": 1.703441040997859, + "convert": 0.0001787919900380075, + "other": 0.08546370899421163, + "read": 0.716718875002698 + }, + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641" + } + ], + "measurements": [ + { + "backend": "baseline-polars", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.532277, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 618.859375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.8099998749967199, + "convert": 0.32769170799292624, + "other": 0.2176985000114655, + "read": 0.24945066700456664 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.6048407500056783 + }, + { + "backend": "production-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.8301100000000003, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 614.21875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.7814332919951994, + "convert": 0.2741778339986922, + "other": 0.43743074900703505, + "read": 0.2526432080048835 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.74568508300581 + }, + { + "backend": "baseline-polars", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.583748, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 561.125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.8108490000013262, + "convert": 0.3234495000069728, + "other": 0.2224074579862645, + "read": 0.17978912500257138 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.536495082997135 + }, + { + "backend": "production-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.8691079999999998, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 614.984375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.7691715410037432, + "convert": 0.26912924999487586, + "other": 0.4791868339962093, + "read": 0.26587825000751764 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.783365875002346 + }, + { + "backend": "baseline-polars", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.204866, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 567.546875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.7136455419968115, + "convert": 0.06799566600238904, + "other": 0.24779787599982228, + "read": 0.2407124580058735 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.2701515420048963 + }, + { + "backend": "production-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.4982200000000003, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 581.703125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.7543994170118822, + "convert": 6.991699046920985e-05, + "other": 0.4925633319944609, + "read": 0.23747916700085625 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.4845118329976685 + }, + { + "backend": "baseline-polars", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.279296, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 568.15625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.7160745419969317, + "convert": 0.07259470901044551, + "other": 0.277263915995718, + "read": 0.12976387499656994 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.195697041999665 + }, + { + "backend": "production-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.535609, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 579.578125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.695659707998857, + "convert": 6.487499922513962e-05, + "other": 0.4984240000048885, + "read": 0.2541067499987548 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.4482553330017254 + }, + { + "backend": "production-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.9099049999999997, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 614.1875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.8160476249904605, + "convert": 0.2812335000053281, + "other": 0.44891000000643544, + "read": 0.2669881250039907 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.8131792500062147 + }, + { + "backend": "baseline-polars", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.586528, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 559.875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.8558079170034034, + "convert": 0.3250608340022154, + "other": 0.25447508197976276, + "read": 0.07233362500846852 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.50767745799385 + }, + { + "backend": "production-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.8841460000000003, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 612.640625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.7776395420078188, + "convert": 0.27401145799376536, + "other": 0.47920116600289475, + "read": 0.2667071250034496 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.7975592910079286 + }, + { + "backend": "baseline-polars", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.55136, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 561.0, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.7993802079872694, + "convert": 0.32471241599705536, + "other": 0.2147459190164227, + "read": 0.12502779100032058 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.463866334001068 + }, + { + "backend": "production-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.49164, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 580.640625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.6796663339919178, + "convert": 7.199999527074397e-05, + "other": 0.49265141601790674, + "read": 0.23528766699018888 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.407677416995284 + }, + { + "backend": "baseline-polars", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.170746, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 567.265625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.7048044170078356, + "convert": 0.06709412499913014, + "other": 0.24385374998382758, + "read": 0.06500708300154656 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.08075937499234 + }, + { + "backend": "production-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.499142, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 583.34375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.671151375005138, + "convert": 7.137500506360084e-05, + "other": 0.4930691249901429, + "read": 0.2519053330033785 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.416197208003723 + }, + { + "backend": "baseline-polars", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.242196, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 567.421875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.7205652499978896, + "convert": 0.06707937498867977, + "other": 0.2519090010027867, + "read": 0.11776566600019578 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.157319291989552 + }, + { + "backend": "baseline-polars", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.509217, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 560.234375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.7979443749936763, + "convert": 0.3262738339981297, + "other": 0.22537416701379698, + "read": 0.06718733299931046 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.4167797090049135 + }, + { + "backend": "production-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.830405, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 612.34375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.7827446669980418, + "convert": 0.27151629100262653, + "other": 0.4356324999971548, + "read": 0.25886041700141504 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.748753874999238 + }, + { + "backend": "baseline-polars", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.655658, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 561.1875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.9053391670022393, + "convert": 0.3231159159913659, + "other": 0.21961133400327526, + "read": 0.12143812500289641 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.569504541999777 + }, + { + "backend": "production-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.8766249999999998, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 612.9375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.7792878750042291, + "convert": 0.27137179199780803, + "other": 0.47362104199419264, + "read": 0.26754691600217484 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.7918276249984046 + }, + { + "backend": "baseline-polars", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.167786, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 566.90625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.6969510409981012, + "convert": 0.06747745799657423, + "other": 0.2488653769978555, + "read": 0.0663892080046935 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.0796830839972245 + }, + { + "backend": "production-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.502798, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 580.46875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.6786287909926614, + "convert": 5.820799560751766e-05, + "other": 0.4969912100204965, + "read": 0.24491991598915774 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.420598124997923 + }, + { + "backend": "baseline-polars", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.227829, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 568.171875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.7019458750000922, + "convert": 0.06709170900285244, + "other": 0.2795210829790449, + "read": 0.11430841601395514 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.1628670829959447 + }, + { + "backend": "production-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.483425, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 581.4375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.6758758750074776, + "convert": 6.670800212305039e-05, + "other": 0.48125904299377, + "read": 0.24444758299796376 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.4016492090013344 + }, + { + "backend": "baseline-polars", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.376628, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 552.28125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.842572041990934, + "convert": 0.22023233299842104, + "other": 0.21877529099583626, + "read": 0.23347658400598448 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.5150562499911757 + }, + { + "backend": "production-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.7754659999999998, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 600.875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.7758627080038423, + "convert": 0.18110166599217337, + "other": 0.5269170020037564, + "read": 0.20812033300171606 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.692001709001488 + }, + { + "backend": "baseline-polars", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.381838, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 553.609375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.8157908339926507, + "convert": 0.2039634160028072, + "other": 0.2122295010049129, + "read": 0.0783387080009561 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.310322459001327 + }, + { + "backend": "production-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.7980669999999996, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 588.328125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.7865361669973936, + "convert": 0.1810985000047367, + "other": 0.5351072909979848, + "read": 0.21428587500122376 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.717027833001339 + }, + { + "backend": "baseline-polars", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.10306, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 559.59375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.7138885000022128, + "convert": 0.02035516699834261, + "other": 0.24165904099936597, + "read": 0.1963068339973688 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.17220954199729 + }, + { + "backend": "production-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.49517, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 596.703125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.6751569170010043, + "convert": 0.0001568750012665987, + "other": 0.5419826240104157, + "read": 0.19647387499571778 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.4137702910084045 + }, + { + "backend": "baseline-polars", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.117636, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 610.75, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.6958254579949426, + "convert": 0.016950332996202633, + "other": 0.25999750099435914, + "read": 0.06967087500379421 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.0424441669892985 + }, + { + "backend": "production-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.517993, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 592.03125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.6885164999985136, + "convert": 0.00014441700477618724, + "other": 0.5388103739824146, + "read": 0.2102424170006998 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.437713707986404 + }, + { + "backend": "production-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.772764, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 595.75, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.7806279579963302, + "convert": 0.1821750829985831, + "other": 0.5258391670067795, + "read": 0.20372262499586213 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.692364832997555 + }, + { + "backend": "baseline-polars", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.3615969999999997, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 552.375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.8084887080040062, + "convert": 0.20205358300881926, + "other": 0.24395945899595972, + "read": 0.024637833994347602 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.2791395840031328 + }, + { + "backend": "production-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.774547, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 603.453125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.7718397910066415, + "convert": 0.18210333299066406, + "other": 0.5186047930037603, + "read": 0.2172634580056183 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.689811375006684 + }, + { + "backend": "baseline-polars", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.341782, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 553.203125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.7813152089947835, + "convert": 0.19700679200468585, + "other": 0.21584450000955258, + "read": 0.06953970799804665 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.2637062090070685 + }, + { + "backend": "production-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.489892, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 590.546875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.6704640829993878, + "convert": 0.00016466599481645972, + "other": 0.5399450849945424, + "read": 0.19824704100028612 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.4088208749890327 + }, + { + "backend": "baseline-polars", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.04725, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 559.109375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.684807917001308, + "convert": 0.016985291003948078, + "other": 0.24184804198739585, + "read": 0.02371675000176765 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 1.9673579999944195 + }, + { + "backend": "production-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.523304, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 597.5625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.692874207990826, + "convert": 0.0001500000071246177, + "other": 0.536938375007594, + "read": 0.21212820798973553 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.4420907909952803 + }, + { + "backend": "baseline-polars", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.104431, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 559.859375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.6895592079963535, + "convert": 0.01633008300268557, + "other": 0.2596461249922868, + "read": 0.06636195900500752 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.0318973749963334 + }, + { + "backend": "baseline-polars", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.339194, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 552.59375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.7900923340057489, + "convert": 0.19746504200156778, + "other": 0.2428244159964379, + "read": 0.02499925000302028 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.255381042006775 + }, + { + "backend": "production-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.7840759999999998, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 604.296875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.7844774590048473, + "convert": 0.18372120799904224, + "other": 0.5275263329967856, + "read": 0.20570887500070967 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.701433875001385 + }, + { + "backend": "baseline-polars", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.350597, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 552.890625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.791869416992995, + "convert": 0.19761208399722818, + "other": 0.21492508200753946, + "read": 0.06949495800654404 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.2739015410043066 + }, + { + "backend": "production-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.755722, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 603.671875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.771267624993925, + "convert": 0.18202091699640732, + "other": 0.5032457490015076, + "read": 0.2146282500034431 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.671162540995283 + }, + { + "backend": "baseline-polars", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.0917120000000002, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 562.0, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.7087899999896763, + "convert": 0.016200708007090725, + "other": 0.2614319590065861, + "read": 0.02415333299722988 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.010576000000583 + }, + { + "backend": "production-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.49562, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 600.765625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.670675666013267, + "convert": 0.0001449169940315187, + "other": 0.5410162919870345, + "read": 0.2033440000086557 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.4151808750029886 + }, + { + "backend": "baseline-polars", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.086296, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 559.90625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.6907424169912701, + "convert": 0.015975125003024004, + "other": 0.2396569160046056, + "read": 0.06748079200042412 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.013855249999324 + }, + { + "backend": "production-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.554192, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 587.796875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "attributes": 1.6962641249992885, + "convert": 0.00015220799832604825, + "other": 0.5618522080039838, + "read": 0.2130719999986468 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.471340541000245 + }, + { + "backend": "prototype-pandas-c", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 3.408847, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 593.5, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.4621411660045851, + "attributes": 1.779311542006326, + "convert": 0.26976025001204107, + "other": 0.031866373974480666, + "read": 0.8835250840056688 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 3.4266044160031015 + }, + { + "backend": "prototype-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.7294769999999997, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 795.484375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.45757262500410434, + "attributes": 1.7804561669909162, + "convert": 0.26961625000694767, + "other": 0.03142008300346788, + "read": 0.10576299999956973 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.644828125005006 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.808318, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 677.25, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.4631419579964131, + "attributes": 1.9024005419923924, + "convert": 0.2984712499892339, + "other": 0.024197291015298106, + "read": 0.04485662501247134 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.733067666005809 + }, + { + "backend": "prototype-pandas-c", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 3.4502949999999997, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 593.765625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.46296708298905287, + "attributes": 1.7898992090049433, + "convert": 0.2700319170107832, + "other": 0.032119208000949584, + "read": 0.911090833003982 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 3.466108250009711 + }, + { + "backend": "prototype-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.772733, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 795.265625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.47433208300208207, + "attributes": 1.7737742080062162, + "convert": 0.27322550000099, + "other": 0.031385291993501596, + "read": 0.14110441699449439 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.6938214999972843 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.9541489999999997, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 678.125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.4826122079975903, + "attributes": 1.9666686249984195, + "convert": 0.31172904100094456, + "other": 0.024348125996766612, + "read": 0.08551900000020396 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.870876999993925 + }, + { + "backend": "prototype-pandas-c", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.962694, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 557.3125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5376986250048503, + "attributes": 1.6928435830050148, + "convert": 7.762500899843872e-05, + "other": 0.02574316797836218, + "read": 0.7176506660034647 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.9740136670006905 + }, + { + "backend": "prototype-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.4162429999999997, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 770.25, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5368626249983208, + "attributes": 1.6809838750050403, + "convert": 6.941599713172764e-05, + "other": 0.028512125994893722, + "read": 0.08925720800471026 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.335685250000097 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.528665, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 673.96875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5287755419994937, + "attributes": 1.827468333998695, + "convert": 0.03293333399051335, + "other": 0.022884748002979904, + "read": 0.04564212499826681 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.457704082989949 + }, + { + "backend": "prototype-pandas-c", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.9312679999999998, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 554.921875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5318250420095865, + "attributes": 1.674411833009799, + "convert": 7.037499744910747e-05, + "other": 0.025611374992877245, + "read": 0.7102124999946682 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.94213112500438 + }, + { + "backend": "prototype-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.4297129999999996, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 741.953125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5307892499986337, + "attributes": 1.668676208006218, + "convert": 6.566698721144348e-05, + "other": 0.027927374001592398, + "read": 0.12399208400165662 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.3514505829953123 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.5599760000000003, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 669.65625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5313982910010964, + "attributes": 1.814215750011499, + "convert": 0.03409316699253395, + "other": 0.02326125098625198, + "read": 0.08316808300151024 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.4861365419928916 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.838592, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 672.6875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5105332500097575, + "attributes": 1.9034146659978433, + "convert": 0.3002569590025814, + "other": 0.024680625996552408, + "read": 0.045068040999467485 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.783953542006202 + }, + { + "backend": "prototype-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.752299, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 797.359375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.46840795800380874, + "attributes": 1.7734869580017403, + "convert": 0.42942983300599735, + "other": 0.03128133396967314, + "read": 0.10309800000686664 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.805704082988086 + }, + { + "backend": "prototype-pandas-c", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 3.408119, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 590.515625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.4610828340082662, + "attributes": 1.7807112499867799, + "convert": 0.26868229199317284, + "other": 0.03221445700910408, + "read": 0.8833761249989038 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 3.426066957996227 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.864295, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 674.515625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.46583724999800324, + "attributes": 1.9111905829922762, + "convert": 0.300713792006718, + "other": 0.024476584017975256, + "read": 0.08455208298983052 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.786770292004803 + }, + { + "backend": "prototype-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.786536, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 780.796875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.4699894580116961, + "attributes": 1.79674958299438, + "convert": 0.2683907500031637, + "other": 0.03129900099884253, + "read": 0.14077233299030922 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.7072011249983916 + }, + { + "backend": "prototype-pandas-c", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 3.438771, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 591.796875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.46626166701025795, + "attributes": 1.7850957499904325, + "convert": 0.2680569160002051, + "other": 0.032817291998071596, + "read": 0.9014286669989815 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 3.4536602919979487 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.541571, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 673.8125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5393599590024678, + "attributes": 1.8137287080025999, + "convert": 0.033973041994613595, + "other": 0.023252166007296182, + "read": 0.04739100000006147 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.457704875007039 + }, + { + "backend": "prototype-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.41204, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 769.015625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5309647920075804, + "attributes": 1.6771651250019204, + "convert": 7.529200229328126e-05, + "other": 0.027803540986496955, + "read": 0.08993375000136439 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.3259424999996554 + }, + { + "backend": "prototype-pandas-c", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.919864, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 558.890625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5306540840101661, + "attributes": 1.6857362910086522, + "convert": 7.120799273252487e-05, + "other": 0.025882959977025166, + "read": 0.690131666007801 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.932476208996377 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.569193, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 672.3125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5264518750045681, + "attributes": 1.827811124996515, + "convert": 0.03376533399568871, + "other": 0.02363874900038354, + "read": 0.08251587499398738 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.4941829579911428 + }, + { + "backend": "prototype-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.437506, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 740.40625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.528070457992726, + "attributes": 1.6777252500032773, + "convert": 7.500000356230885e-05, + "other": 0.02780137601075694, + "read": 0.12612445799459238 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.359796542004915 + }, + { + "backend": "prototype-pandas-c", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.93263, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 556.96875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5301182080002036, + "attributes": 1.6793515419994947, + "convert": 6.637499609496444e-05, + "other": 0.024951250001322478, + "read": 0.7157836249971297 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.9502709999942454 + }, + { + "backend": "prototype-pandas-c", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 3.450481, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 592.921875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.4708849580056267, + "attributes": 1.8007765840011416, + "convert": 0.2697622499981662, + "other": 0.033334749983623624, + "read": 0.8948662500042701 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 3.4696247919928282 + }, + { + "backend": "prototype-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.7703979999999997, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 777.296875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.4764765829895623, + "attributes": 1.792963999992935, + "convert": 0.2713034580083331, + "other": 0.03195225101080723, + "read": 0.11764949999633245 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.69034579199797 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.848519, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 676.09375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.4772016249917215, + "attributes": 1.9134580829995684, + "convert": 0.30064641700300854, + "other": 0.026075124987983145, + "read": 0.048311250007827766 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.7656924999901094 + }, + { + "backend": "prototype-pandas-c", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 3.423718, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 591.765625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.4689260829909472, + "attributes": 1.7730282919947058, + "convert": 0.26819329100544564, + "other": 0.032728042016969994, + "read": 0.8916124579991447 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 3.4344881660072133 + }, + { + "backend": "prototype-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.780826, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 809.765625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.46976066700881347, + "attributes": 1.777190792010515, + "convert": 0.2708022079896182, + "other": 0.032559540995862335, + "read": 0.14560699999856297 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.695920208003372 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.879623, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 676.734375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.4658856250025565, + "attributes": 1.9208032500027912, + "convert": 0.3009340420103399, + "other": 0.02472178997413721, + "read": 0.08686183400277514 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.7992065409926 + }, + { + "backend": "prototype-pandas-c", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.964733, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 559.03125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5499492499948246, + "attributes": 1.7188377499987837, + "convert": 7.56250083213672e-05, + "other": 0.027287625009194016, + "read": 0.6900477499875706 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.9861979999986943 + }, + { + "backend": "prototype-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.439682, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 743.84375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5474526670004707, + "attributes": 1.6997607499943115, + "convert": 7.208299939520657e-05, + "other": 0.028622834011912346, + "read": 0.08880654099630192 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.3647148750023916 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.6052470000000003, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 668.0625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5613138750049984, + "attributes": 1.85524758300744, + "convert": 0.033272499989834614, + "other": 0.023273083003005013, + "read": 0.04947570900549181 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.52258275001077 + }, + { + "backend": "prototype-pandas-c", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 3.162574, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 559.984375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.6414281659963308, + "attributes": 1.802537083000061, + "convert": 9.650000720284879e-05, + "other": 0.029298209003172815, + "read": 0.7471527500019874 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 3.220512708008755 + }, + { + "backend": "prototype-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.7121690000000003, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 743.296875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.6106707920116605, + "attributes": 1.8451438750053057, + "convert": 7.454201113432646e-05, + "other": 0.03369333196314983, + "read": 0.16351583400683012 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.6530983749980805 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.769798, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 669.984375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5872713329881663, + "attributes": 1.9444007080019219, + "convert": 0.0355948329961393, + "other": 0.02477325101790484, + "read": 0.10269424998841714 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.6947343749925494 + }, + { + "backend": "prototype-pandas-c", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 3.653487, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 573.21875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5052536250004778, + "attributes": 1.9766707090020645, + "convert": 0.20422075000533368, + "other": 0.08180174998415168, + "read": 0.9398529580066679 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 3.7077997919986956 + }, + { + "backend": "prototype-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 3.0227939999999998, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 588.71875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.48928570799762383, + "attributes": 2.150619459003792, + "convert": 0.19091441699129064, + "other": 0.07707174800452776, + "read": 0.14450733400008176 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 3.052398665997316 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.983625, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 575.375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5044198340037838, + "attributes": 2.0805143330071587, + "convert": 0.2552615419990616, + "other": 0.08160191598290112, + "read": 0.06480474999989383 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.986602374992799 + }, + { + "backend": "prototype-pandas-c", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 3.712797, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 577.890625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5160652500053402, + "attributes": 1.9573320420022355, + "convert": 0.2009856660006335, + "other": 0.10515724998549558, + "read": 1.036252792007872 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 3.8157930000015767 + }, + { + "backend": "prototype-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 3.035487, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 584.59375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.4505555829964578, + "attributes": 2.1312201660039136, + "convert": 0.19452533300500363, + "other": 0.070669917986379, + "read": 0.10452266701031476 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.951493667002069 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 3.164935, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 594.390625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.504354874996352, + "attributes": 2.173263583012158, + "convert": 0.24324787501245737, + "other": 0.08042750097229145, + "read": 0.10567258299852256 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 3.1069664169917814 + }, + { + "backend": "prototype-pandas-c", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 3.247476, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 548.09375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5568312499963213, + "attributes": 1.8750692089961376, + "convert": 0.00017508301243651658, + "other": 0.09723029199813027, + "read": 0.7859223330015084 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 3.315228167004534 + }, + { + "backend": "prototype-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.779331, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 601.65625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5544974590011407, + "attributes": 2.0483250000106636, + "convert": 0.00021449998894240707, + "other": 0.12855683300585952, + "read": 0.06929637498978991 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.800890166996396 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.8060419999999997, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 561.375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5087994999921648, + "attributes": 2.0308499579987256, + "convert": 0.05097054199723061, + "other": 0.08811262501694728, + "read": 0.16486545800580643 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.8435980830108747 + }, + { + "backend": "prototype-pandas-c", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 3.212746, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 550.40625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5337550830008695, + "attributes": 1.855332916995394, + "convert": 0.0001787919900380075, + "other": 0.09214462601812556, + "read": 0.7916211660049157 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 3.273032584009343 + }, + { + "backend": "prototype-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.780145, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 587.03125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.4799935000046389, + "attributes": 2.0522013750014594, + "convert": 0.00019366599735803902, + "other": 0.08677000099851284, + "read": 0.10052599999471568 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.719684541996685 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.914624, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 549.953125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5757185410038801, + "attributes": 2.138279499995406, + "convert": 0.05244833399774507, + "other": 0.08587958301359322, + "read": 0.1304697499872418 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.982795707997866 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 3.034187, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 599.09375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.49442504199396353, + "attributes": 2.108923749998212, + "convert": 0.24380533400108106, + "other": 0.07692641601897776, + "read": 0.07706845799111761 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 3.001149000003352 + }, + { + "backend": "prototype-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.95458, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 595.234375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5150626249960624, + "attributes": 2.1219689170102356, + "convert": 0.19252662500366569, + "other": 0.08086412498960271, + "read": 0.07791937500587665 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.988341667005443 + }, + { + "backend": "prototype-pandas-c", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 4.014492, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 506.640625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.7065421250008512, + "attributes": 2.411136124996119, + "convert": 0.20139558298978955, + "other": 0.10657258401624858, + "read": 0.9573015000059968 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 4.382947917009005 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 3.038281, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 573.109375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.46770612501131836, + "attributes": 2.0443969999905676, + "convert": 0.24624337498971727, + "other": 0.10026283400657121, + "read": 0.11229233299673069 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.970901666994905 + }, + { + "backend": "prototype-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 3.0221340000000003, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 594.6875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.4727939580043312, + "attributes": 2.1193705829937244, + "convert": 0.19004050000512507, + "other": 0.0816788340016501, + "read": 0.10701024999434594 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.9708941249991767 + }, + { + "backend": "prototype-pandas-c", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 3.6022719999999997, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 573.53125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5183190420066239, + "attributes": 1.881623875000514, + "convert": 0.19371162499010097, + "other": 0.09454695800377522, + "read": 0.9651943750068313 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 3.6533958750078455 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.60785, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 583.640625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.4587894580035936, + "attributes": 1.872884750002413, + "convert": 0.048764582999865524, + "other": 0.08184995998453815, + "read": 0.06602279099752195 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.5283115419879323 + }, + { + "backend": "prototype-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.689543, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 539.078125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5761831659910968, + "attributes": 1.9615897920011776, + "convert": 0.0004396660078782588, + "other": 0.0912805429979926, + "read": 0.05603566700301599 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.685528834001161 + }, + { + "backend": "prototype-pandas-c", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 3.109371, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 548.28125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5159829589974834, + "attributes": 1.859943834002479, + "convert": 0.00015491701196879148, + "other": 0.08927978998690378, + "read": 0.7600912500056438 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 3.2254527500044787 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.5754379999999997, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 599.359375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.4293577920034295, + "attributes": 1.8233913339936407, + "convert": 0.04654558400216047, + "other": 0.0765383319958346, + "read": 0.09350162500049919 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.4693346669955645 + }, + { + "backend": "prototype-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.536504, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 592.453125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.4545573340001283, + "attributes": 1.833834958000807, + "convert": 0.00017299999308306724, + "other": 0.07983425000566058, + "read": 0.08616129099391401 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.454560832993593 + }, + { + "backend": "prototype-pandas-c", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.971934, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 548.359375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 2, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.496833749988582, + "attributes": 1.690390292002121, + "convert": 0.0001576670038048178, + "other": 0.08136054100759793, + "read": 0.716718875002698 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.9854611250048038 + }, + { + "backend": "prototype-pandas-c", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 3.4492960000000004, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 573.3125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.48745625000447035, + "attributes": 1.8272852920053992, + "convert": 0.18470658399746753, + "other": 0.08260437400895171, + "read": 0.8886434579908382 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 3.470695958007127 + }, + { + "backend": "prototype-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.783836, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 574.140625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.4401411669969093, + "attributes": 1.955333709003753, + "convert": 0.18451154200010933, + "other": 0.07105208201392088, + "read": 0.05156754198833369 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.7026060420030262 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.850217, + "features": null, + "input_bytes": 111900013, + "path": "ensembl-250k.gtf", + "peak_rss_mib": 582.28125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.44407337499433197, + "attributes": 1.9655423340009293, + "convert": 0.23122204199898988, + "other": 0.07216670800698921, + "read": 0.05225033299939241 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.7652547920006327 + }, + { + "backend": "prototype-pandas-c", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 3.4855650000000002, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 573.640625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.49015199999848846, + "attributes": 1.7933508330024779, + "convert": 0.18660387500131037, + "other": 0.08318370800407138, + "read": 0.9474529169965535 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 3.5007433330029016 + }, + { + "backend": "prototype-arrow", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.884428, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 595.21875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.44234908401267603, + "attributes": 2.1156616249936633, + "convert": 0.18800262500008103, + "other": 0.07287595899833832, + "read": 0.100553290991229 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.9194425839959877 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "be944cfa699afc930317973a3ee1ca1dc6d309c10071bc32b63a9b54abbdcca8", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_version", + "gene_name", + "gene_source", + "gene_biotype", + "transcript_id", + "transcript_version", + "transcript_name", + "transcript_source", + "transcript_biotype", + "tag", + "transcript_support_level", + "exon_number", + "exon_id", + "exon_version", + "protein_id", + "protein_version", + "ccds_id" + ], + "cpu_count": 10, + "cpu_seconds": 2.94851, + "features": null, + "input_bytes": 3524624, + "path": "ensembl-250k.gtf.gz", + "peak_rss_mib": 569.03125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.47618904199043754, + "attributes": 2.0005342500080587, + "convert": 0.2390435409906786, + "other": 0.07696145800582599, + "read": 0.09301116700225975 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.8857394579972606 + }, + { + "backend": "prototype-pandas-c", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.968477, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 547.0625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.49261279198981356, + "attributes": 1.6903244589921087, + "convert": 0.00016987499839160591, + "other": 0.08133483301207889, + "read": 0.7162940410053125 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.980735999997705 + }, + { + "backend": "prototype-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.507308, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 584.21875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.4385673329961719, + "attributes": 1.840667124997708, + "convert": 0.00015625001105945557, + "other": 0.07820237497799098, + "read": 0.05613087500387337 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.4137239579868037 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.534469, + "features": null, + "input_bytes": 109586053, + "path": "gencode-250k.gtf", + "peak_rss_mib": 585.859375, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.444084707996808, + "attributes": 1.8347332919947803, + "convert": 0.047632415997213684, + "other": 0.07803937599237543, + "read": 0.04843470800551586 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.4529244999866933 + }, + { + "backend": "prototype-pandas-c", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.990229, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 549.453125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.5018430839991197, + "attributes": 1.703441040997859, + "convert": 0.0001814580027712509, + "other": 0.08546370899421163, + "read": 0.7119234160054475 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 3.002852707999409 + }, + { + "backend": "prototype-arrow", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.537875, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 592.140625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.4449467080121394, + "attributes": 1.8455196660070214, + "convert": 0.00017187499906867743, + "other": 0.07827754197933245, + "read": 0.09281091700540856 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.4617267080029706 + }, + { + "backend": "prototype-arrow-extension", + "checksum": "8d394118a91daefd2d5ee4f50c07ef5dee567e6ad373c052fa6cf3898c807641", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid" + ], + "cpu_count": 10, + "cpu_seconds": 2.574937, + "features": null, + "input_bytes": 3520115, + "path": "gencode-250k.gtf.gz", + "peak_rss_mib": 583.140625, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 3, + "result_type": "pandas", + "rows": 250000, + "stages": { + "assemble": 0.4434820000024047, + "attributes": 1.8369666249927832, + "convert": 0.04642216701176949, + "other": 0.07880983297945932, + "read": 0.08834333300183062 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "3.0.6", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 2.4940239579882473 + }, + { + "backend": "baseline-polars", + "checksum": "52d9ca5d36dd0795856c27637e70e93cff34511b12226af66a07b4eb114d3d49", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid", + "artif_dupl" + ], + "cpu_count": 10, + "cpu_seconds": 39.251256999999995, + "features": null, + "input_bytes": 59094311, + "path": "gencode.v48.primary_assembly.annotation.gtf.gz", + "peak_rss_mib": 6188.953125, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 4119244, + "stages": { + "attributes": 29.488969624988385, + "convert": 1.3856575840036385, + "other": 6.25970354101446, + "read": 1.7438400410028407 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "2.9.1", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 38.878170791009325 + }, + { + "backend": "production-arrow", + "checksum": "52d9ca5d36dd0795856c27637e70e93cff34511b12226af66a07b4eb114d3d49", + "columns": [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "gene_id", + "gene_type", + "gene_name", + "level", + "tag", + "transcript_id", + "transcript_type", + "transcript_name", + "exon_number", + "exon_id", + "transcript_support_level", + "havana_transcript", + "hgnc_id", + "havana_gene", + "ont", + "protein_id", + "ccdsid", + "artif_dupl" + ], + "cpu_count": 10, + "cpu_seconds": 45.59134400000001, + "features": null, + "input_bytes": 59094311, + "path": "gencode.v48.primary_assembly.annotation.gtf.gz", + "peak_rss_mib": 5347.96875, + "platform": "macOS-26.5-arm64-arm-64bit", + "repeat": 1, + "result_type": "pandas", + "rows": 4119244, + "stages": { + "attributes": 29.7058007500018, + "convert": 0.00020145899907220155, + "other": 10.916198416001862, + "read": 4.7776384169992525 + }, + "threads": 4, + "usecols": null, + "versions": { + "gtfparse": "3.0.0", + "pandas": "2.3.3", + "polars": "1.44.2", + "pyarrow": "25.0.1", + "python": "3.12.6" + }, + "wall_seconds": 45.399839042001986 + } + ] +} diff --git a/gtfparse/__init__.py b/gtfparse/__init__.py index b0b9c25..20c94a5 100644 --- a/gtfparse/__init__.py +++ b/gtfparse/__init__.py @@ -24,7 +24,7 @@ ) from .write_gtf import write_gtf -__version__ = "2.9.1" +__version__ = "3.0.0" __all__ = [ "GENCODE_BIOTYPE_ALIASES", diff --git a/gtfparse/_polars.py b/gtfparse/_polars.py new file mode 100644 index 0000000..953a8b6 --- /dev/null +++ b/gtfparse/_polars.py @@ -0,0 +1,16 @@ +"""Load the optional Polars conversion dependencies only when requested.""" + +import importlib + + +def require_polars(): + try: + polars = importlib.import_module("polars") + except ModuleNotFoundError as error: + if error.name != "polars": + raise + raise ImportError( + "Polars output requires the optional dependencies; " + "install them with pip install 'gtfparse[polars]'" + ) from error + return polars diff --git a/gtfparse/_read_csv.py b/gtfparse/_read_csv.py new file mode 100644 index 0000000..553ad05 --- /dev/null +++ b/gtfparse/_read_csv.py @@ -0,0 +1,138 @@ +"""Read GTF fixed columns without importing an optional dataframe library.""" + +import gzip +import io +from contextlib import contextmanager +from os import PathLike + +import pyarrow as pa +import pyarrow.compute as pc +import pyarrow.csv as pacsv + +from .parsing_error import ParsingError + +REQUIRED_COLUMNS = [ + "seqname", + "source", + "feature", + "start", + "end", + "score", + "strand", + "frame", + "attribute", +] +CATEGORICAL_COLUMNS = ("seqname", "source", "feature", "strand") + + +class _PrefixedReader: + def __init__(self, stream, prefix): + self.stream = stream + self.prefix = prefix + + def read(self, size=-1): + if size < 0: + prefix, self.prefix = self.prefix, self.prefix[:0] + return prefix + self.stream.read() + prefix, self.prefix = self.prefix[:size], self.prefix[size:] + return prefix + self.stream.read(size - len(prefix)) + + +@contextmanager +def _uncompressed(stream): + prefix = stream.read(2) + while prefix and len(prefix) < 2: + extra = stream.read(2 - len(prefix)) + if not extra: + break + prefix += extra + prefixed = _PrefixedReader(stream, prefix) + if prefix == b"\x1f\x8b": + with gzip.GzipFile(fileobj=prefixed) as uncompressed: + yield uncompressed + else: + yield prefixed + + +@contextmanager +def _open_input(source): + if isinstance(source, (str, PathLike)): + with open(source, "rb") as stream, _uncompressed(stream) as uncompressed: + yield uncompressed + else: + with _uncompressed(source) as uncompressed: + yield uncompressed + + +class _GtfReader(io.RawIOBase): + """Filter whole comments and validate fields in bounded input chunks. + + Filtering whole lines preserves literal # inside attributes and skips + comments even when they contain tabs. Validate fields before CSV parsing. + """ + + def __init__(self, stream): + super().__init__() + self.stream = stream + self.pending = b"" + self.buffer = b"" + self.first = True + self.finished = False + + def readable(self): + return True + + def read(self, size=-1): + while not self.finished and (size < 0 or len(self.buffer) < size): + chunk = self.stream.read(max(size, 64 * 1024)) + self.finished = not chunk + if isinstance(chunk, str): + chunk = chunk.encode("utf-8") + lines = (self.pending + chunk).split(b"\n") + self.pending = b"" if self.finished else lines.pop() + if self.first and lines: + lines[0] = lines[0].removeprefix(b"\xef\xbb\xbf") + self.first = False + valid = [] + for line in lines: + if not line.strip() or line.startswith(b"#"): + continue + if line.count(b"\t") != 8: + raise ParsingError("Wrong number of columns: expected nine GTF fields") + valid.append(line + b"\n") + self.buffer += b"".join(valid) + if size < 0: + result, self.buffer = self.buffer, b"" + else: + result, self.buffer = self.buffer[:size], self.buffer[size:] + return result + + +def read_fixed_columns(source, features=None): + types = dict.fromkeys(CATEGORICAL_COLUMNS, pa.dictionary(pa.int32(), pa.string())) + types.update( + start=pa.int64(), + end=pa.int64(), + score=pa.float32(), + frame=pa.uint32(), + attribute=pa.string(), + ) + try: + with _open_input(source) as stream, _GtfReader(stream) as cleaned: + table = pacsv.read_csv( + cleaned, + read_options=pacsv.ReadOptions(column_names=REQUIRED_COLUMNS), + parse_options=pacsv.ParseOptions(delimiter="\t", quote_char=False), + convert_options=pacsv.ConvertOptions( + column_types=types, null_values=[".", ""], strings_can_be_null=True + ), + ) + except pa.ArrowInvalid as error: + raise ParsingError("Invalid or empty GTF input: %s" % error) from error + if table["seqname"].null_count: + table = table.filter(pc.is_valid(table["seqname"])) + if features is not None: + values = pa.array(sorted(set(features)), type=pa.string()) + table = table.filter(pc.is_in(table["feature"], value_set=values)) + table = table.set_column(7, "frame", pc.fill_null(table["frame"], 0)) + return table.to_pandas() diff --git a/gtfparse/attribute_parsing.py b/gtfparse/attribute_parsing.py index ccea6fb..495156c 100644 --- a/gtfparse/attribute_parsing.py +++ b/gtfparse/attribute_parsing.py @@ -18,7 +18,7 @@ logger = logging.getLogger(__name__) # Quoted values may contain semicolons. Keep this compatible with both Python's -# re module and Polars' regex engine so the low-level split column agrees with +# re module so the low-level split column agrees with # attribute expansion. Unquoted values and single quotes are accepted as well. ATTRIBUTE_PATTERN = r"""[^\s;]+[ \t]+(?:"[^"]*"|'[^']*'|[^;]+)""" _ATTRIBUTE_PAIRS = re.compile(ATTRIBUTE_PATTERN) diff --git a/gtfparse/read_gtf.py b/gtfparse/read_gtf.py index eef49ac..42b1913 100644 --- a/gtfparse/read_gtf.py +++ b/gtfparse/read_gtf.py @@ -14,10 +14,11 @@ from os.path import exists import pandas as pd -import polars +from ._polars import require_polars +from ._read_csv import REQUIRED_COLUMNS as REQUIRED_COLUMNS +from ._read_csv import read_fixed_columns from .attribute_parsing import ATTRIBUTE_PATTERN, expand_attribute_strings -from .parsing_error import ParsingError logger = logging.getLogger(__name__) @@ -82,74 +83,19 @@ (from ftp://ftp.ensembl.org/pub/release-75/gtf/homo_sapiens/README) """ -REQUIRED_COLUMNS = [ - "seqname", - "source", - "feature", - "start", - "end", - "score", - "strand", - "frame", - "attribute", -] - - -DEFAULT_COLUMN_DTYPES = { - "seqname": polars.Categorical, - "source": polars.Categorical, - "start": polars.Int64, - "end": polars.Int64, - "score": polars.Float32, - "feature": polars.Categorical, - "strand": polars.Categorical, - "frame": polars.UInt32, -} - def parse_with_polars_lazy( filepath_or_buffer, split_attributes=True, features=None, fix_quotes_columns=None ): - # Categories shares categorical mappings on modern Polars. Older releases - # need the global string cache for categoricals from separate reads to match. - if not hasattr(polars, "Categories"): - polars.enable_string_cache() - kwargs = { - "has_header": False, - "separator": "\t", - "comment_prefix": "#", - "null_values": ".", - "schema_overrides": DEFAULT_COLUMN_DTYPES, - "quote_char": None, - } - try: - df = polars.read_csv(filepath_or_buffer, new_columns=REQUIRED_COLUMNS, **kwargs).lazy() - except polars.exceptions.ShapeError as err: - raise ParsingError("Wrong number of columns") from err - - # Drop empty lines that may appear as all-null rows - df = df.filter(polars.col("seqname").is_not_null()) - - df = df.with_columns(polars.col("frame").fill_null(0)) - - for fix_quotes_column in fix_quotes_columns or (): - # Catch mistaken semicolons by replacing "xyz;" with "xyz" - # Required to do this since the Ensembl GTF for Ensembl - # release 78 has mistakes such as: - # gene_name = "PRAMEF6;" transcript_name = "PRAMEF6;-201" - df = df.with_columns( - [polars.col(fix_quotes_column).str.replace(';"', '"').str.replace(";-", "-")] - ) - - if features is not None: - features = sorted(set(features)) - df = df.filter(polars.col("feature").is_in(features)) + """Read eagerly and return an optional Polars LazyFrame. - if split_attributes: - df = df.with_columns( - polars.col("attribute").str.extract_all(ATTRIBUTE_PATTERN).alias("attribute_split") - ) - return df + As in earlier releases, file I/O happens before this function returns. + Install ``gtfparse[polars]`` to use this compatibility adapter. + """ + polars = require_polars() + return polars.from_pandas( + parse_gtf(filepath_or_buffer, split_attributes, features, fix_quotes_columns) + ).lazy() def parse_gtf( @@ -169,13 +115,21 @@ def parse_gtf( """ if progress_callback is not None: progress_callback("read", 0, None) - df_lazy = parse_with_polars_lazy( - filepath_or_buffer=filepath_or_buffer, - split_attributes=split_attributes, - features=features, - fix_quotes_columns=fix_quotes_columns, - ) - df = df_lazy.collect() + # Apply the normal filter before conversion so discarded null coordinates + # do not change the retained columns' integer dtypes. Opt-in quote cleanup + # can change feature names, so preserve its order ahead of filtering. + read_features = None if fix_quotes_columns else features + df = read_fixed_columns(filepath_or_buffer, features=read_features) + for name in fix_quotes_columns or (): + df[name] = ( + df[name] + .str.replace(';"', '"', n=1, regex=False) + .str.replace(";-", "-", n=1, regex=False) + ) + if features is not None and fix_quotes_columns: + df = df.loc[df["feature"].isin(set(features))].reset_index(drop=True) + if split_attributes: + df["attribute_split"] = df["attribute"].str.findall(ATTRIBUTE_PATTERN) if progress_callback is not None: progress_callback("read", len(df), len(df)) return df @@ -187,7 +141,7 @@ def parse_gtf_pandas(*args, **kwargs): progress_callback = kwargs.get("progress_callback") if progress_callback is not None: progress_callback("convert", 0, None) - result = df.to_pandas() + result = df if progress_callback is not None: progress_callback("convert", len(result), len(result)) return result @@ -197,7 +151,7 @@ def parse_gtf_and_expand_attributes( filepath_or_buffer, restrict_attribute_columns=None, features=None, *, progress_callback=None ): """ - Parse a GTF into a Polars DataFrame and then expand + Parse a GTF into a pandas DataFrame and then expand the 'attribute' column into multiple columns. This expansion happens by replacing strings of semi-colon separated key-value values in the 'attribute' column with one column per distinct key, with a list of @@ -226,17 +180,18 @@ def parse_gtf_and_expand_attributes( restrict_attribute_columns = {restrict_attribute_columns} elif restrict_attribute_columns: restrict_attribute_columns = set(restrict_attribute_columns) - attributes = df.drop_in_place("attribute") - return df.with_columns( - [ - polars.Series(k, vs) - for (k, vs) in expand_attribute_strings( - attributes, - usecols=restrict_attribute_columns, - progress_callback=progress_callback, - ).items() - ] + attributes = df.pop("attribute") + attributes = attributes.astype(object).where(attributes.notna(), None) + expanded = expand_attribute_strings( + attributes, + usecols=restrict_attribute_columns, + progress_callback=progress_callback, ) + # Assigning a colliding attribute replaces its fixed column, matching the + # previous reader, while preserving the fixed columns' original positions. + for name, values in expanded.items(): + df[name] = values + return df def _apply_attribute_aliases(result_df, attribute_aliases): @@ -306,7 +261,7 @@ def read_gtf( column_cast_types={}, usecols=None, features=None, - result_type="polars", + result_type="pandas", attribute_aliases=None, cast_version_columns=True, *, @@ -347,9 +302,9 @@ def read_gtf( features : set of str or None Drop rows which aren't one of the features in the supplied set - result_type : One of 'polars', 'pandas', or 'dict' - Default behavior is to return a Polars DataFrame, but will convert to - Pandas DataFrame or dictionary if specified. + result_type : One of 'pandas', 'dict', or 'polars' (requires the optional extra) + Return a pandas DataFrame by default. Polars output requires + ``pip install 'gtfparse[polars]'``; dictionary output is also supported. attribute_aliases : dict of str -> str, optional Maps alias attribute names onto canonical ones. After attributes @@ -380,6 +335,8 @@ def read_gtf( """ if result_type not in ("polars", "pandas", "dict"): raise ValueError("result_type must be one of 'polars', 'pandas', or 'dict'") + if result_type == "polars": + require_polars() if type(filepath_or_buffer) is str and not exists(filepath_or_buffer): raise ValueError("GTF file does not exist: %s" % filepath_or_buffer) @@ -416,10 +373,6 @@ def read_gtf( if progress_callback is not None: progress_callback("convert", 0, None) - # converting back to pandas here because Polars bugs manifest - # as `pyo3_runtime.PanicException: assertion `left == right` failed: impl error` - # and are generally insane to chase down - result_df = result_df.to_pandas() if column_converters or column_cast_types: def wrap_to_always_accept_none(f): @@ -477,7 +430,7 @@ def wrapped_fn(x): if result_type == "pandas": result = result_df elif result_type == "polars": - result = polars.from_pandas(result_df) + result = require_polars().from_pandas(result_df) else: result = result_df.to_dict() if progress_callback is not None: diff --git a/gtfparse/write_gtf.py b/gtfparse/write_gtf.py index af7a62e..899cdf4 100644 --- a/gtfparse/write_gtf.py +++ b/gtfparse/write_gtf.py @@ -12,14 +12,16 @@ import gzip import logging +import sys from collections.abc import Iterable +from itertools import repeat from pathlib import Path from typing import TYPE_CHECKING, Optional, Union -import polars +import pandas as pd if TYPE_CHECKING: - import pandas + import polars logger = logging.getLogger(__name__) @@ -45,69 +47,32 @@ RAW_ATTRIBUTE_COLUMN = "attribute" -def _attribute_expr(attribute_columns: list[str]) -> polars.Expr: - """ - Build a polars expression that renders the GTF attribute field for each row - from a set of expanded attribute columns. - - Each column ``key`` becomes ``key "value";`` and the per-row pairs are - joined with a single space, matching the format emitted by Ensembl/GENCODE - and parsed by read_gtf. - - A pair is omitted for any row where the value is "absent". read_gtf marks an - absent key with null (numeric columns, e.g. the ``*_version`` fields) or the - empty string (string columns) and cannot distinguish absent from - present-but-empty, so we treat both null and "" as absent. Values that are - merely falsy but non-empty -- notably the string "0" -- are written and - survive a round trip. - """ - if not attribute_columns: - return polars.lit("") - pairs = [] - for name in attribute_columns: - value = polars.col(name).cast(polars.String) - pairs.append( - polars.when(value.is_null() | (value == "")) - .then(None) - .otherwise(polars.format('{} "{}";', polars.lit(name), value)) - ) - # ignore_nulls drops absent keys; fill_null covers the all-absent row so the - # surrounding line expression never collapses to null. - return polars.concat_str(pairs, separator=" ", ignore_nulls=True).fill_null("") - - -def _line_series(df: polars.DataFrame) -> polars.Series: - """ - Turn a DataFrame into a Series of fully-formatted GTF lines (without - trailing newlines), building the whole thing with vectorized polars - expressions rather than per-row Python. - """ - columns = df.columns - missing = [name for name in GTF_FIXED_COLUMNS if name not in columns] - if missing: - raise ValueError("DataFrame is missing required GTF column(s): %s" % ", ".join(missing)) - - # Fixed columns are always written in canonical order; nulls become '.'. - # Cast before fill_null so numeric columns accept the string sentinel. - fixed = [ - polars.col(name).cast(polars.String).fill_null(MISSING_VALUE) for name in GTF_FIXED_COLUMNS - ] - - if RAW_ATTRIBUTE_COLUMN in columns: - # Unexpanded read: the attribute column is already a formatted string. - attribute = polars.col(RAW_ATTRIBUTE_COLUMN).cast(polars.String).fill_null("") - else: - attribute_columns = [name for name in columns if name not in GTF_FIXED_COLUMNS] - attribute = _attribute_expr(attribute_columns) - - # Always keep the 9th (attribute) field, even when empty, so every line has - # the nine tab-separated columns read_gtf expects. - line = polars.concat_str([*fixed, attribute], separator="\t") - return df.select(line.alias("_gtf_line")).get_column("_gtf_line") +def _lines(df): + """Format bounded batches, preserving each column's string representation.""" + attribute_columns = [name for name in df.columns if name not in GTF_FIXED_COLUMNS] + for start in range(0, len(df), 10_000): + batch = df.iloc[start : start + 10_000] + fixed = batch[GTF_FIXED_COLUMNS].astype("string").fillna(MISSING_VALUE) + if RAW_ATTRIBUTE_COLUMN in df.columns: + attributes = batch[RAW_ATTRIBUTE_COLUMN].astype("string").fillna("") + elif not attribute_columns: + attributes = repeat("", len(batch)) + else: + expanded = batch[attribute_columns].astype("string").fillna("") + attributes = ( + " ".join( + '%s "%s";' % (name, value) + for name, value in zip(attribute_columns, row) + if value != "" + ) + for row in expanded.itertuples(index=False, name=None) + ) + for row, attribute in zip(fixed.itertuples(index=False, name=None), attributes): + yield "\t".join([*row, attribute]) + "\n" def write_gtf( - df: Union[polars.DataFrame, "pandas.DataFrame"], + df: Union[pd.DataFrame, "polars.DataFrame"], path: Union[str, Path], header_lines: Optional[Iterable[str]] = None, ) -> None: @@ -121,7 +86,7 @@ def write_gtf( Parameters ---------- - df : polars.DataFrame or pandas.DataFrame + df : pandas.DataFrame or polars.DataFrame Feature rows to write. Must contain the fixed GTF columns (seqname, source, feature, start, end, score, strand, frame). Any additional column is written as an attribute, except a column @@ -146,19 +111,20 @@ def write_gtf( quotes, tabs, or newlines; values containing those characters are outside its round-trip guarantees. Empty and missing attributes are both omitted. """ - # Accept a pandas DataFrame too, since read_gtf(result_type="pandas") - # returns one; convert to polars so the formatting below is uniform. - if not isinstance(df, polars.DataFrame): - df = polars.from_pandas(df) - - lines = _line_series(df) + if not isinstance(df, pd.DataFrame): + polars = sys.modules.get("polars") + if polars is None or not isinstance(df, polars.DataFrame): + raise TypeError("df must be a pandas or Polars DataFrame") + df = df.to_pandas() + missing = [name for name in GTF_FIXED_COLUMNS if name not in df.columns] + if missing: + raise ValueError("DataFrame is missing required GTF column(s): %s" % ", ".join(missing)) open_file = gzip.open if str(path).lower().endswith(".gz") else open with open_file(path, "wt", encoding="utf-8", newline="\n") as output_file: if header_lines is not None: for header_line in header_lines: output_file.write("%s\n" % header_line) - for line in lines: - output_file.write("%s\n" % line) + output_file.writelines(_lines(df)) - logger.info("Wrote %d GTF rows to %s", lines.len(), path) + logger.info("Wrote %d GTF rows to %s", len(df), path) diff --git a/lint.sh b/lint.sh index 214d41b..fc696c3 100755 --- a/lint.sh +++ b/lint.sh @@ -2,7 +2,7 @@ set -e -SOURCES="gtfparse tests" +SOURCES="gtfparse tests benchmarks" echo "Running ruff check..." ruff check $SOURCES diff --git a/pyproject.toml b/pyproject.toml index f9c5c1b..68b8baf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,7 @@ readme = "README.md" dynamic = ["version", "dependencies"] [project.optional-dependencies] +polars = ["polars>=0.20.31"] dev = [ "pytest", "pytest-cov", diff --git a/requirements.txt b/requirements.txt index 918ae96..6cfc405 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,2 @@ -polars>=0.20.2 pyarrow>=18.0.0 -pandas>=2.1.0 +pandas>=2.2.2 diff --git a/tasks/lessons.md b/tasks/lessons.md index 364d4bd..edde6e1 100644 --- a/tasks/lessons.md +++ b/tasks/lessons.md @@ -4,3 +4,6 @@ keep subsequent fixes, issues, and releases within the named repository. - Distinguish a shipped warning fix from an unimplemented progress feature; verify each requested behavior independently before describing release status. +- When asked to close an unreproduced historical report, record the evidence + and close it as unreproduced rather than leaving it open indefinitely or + implying that an unverified fix shipped. diff --git a/tasks/todo.md b/tasks/todo.md index 7737ed7..33a153d 100644 --- a/tasks/todo.md +++ b/tasks/todo.md @@ -192,3 +192,190 @@ and git ignores Hypothesis caches at both previously tracked paths. Release verification will be recorded on the PR after deployment, keeping the master checkout clean. + +# Polars compatibility and measured backend evaluation: #85 and #69 + +## Specification + +Close #19 as unreproduced with the normalized-example evidence and invite a +fresh reproducer. Fix the supported Polars contract: run the entire suite at +the candidate 0.20.31 API boundary, determine the actual minimum required by +reading and writing, update requirements, and exercise the declared minimum +in CI alongside latest and categorical-transition versions. Investigate and +file any additional current Polars failures encountered; fix reproducible +gtfparse defects within this scope. Preserve public output types, categorical +behavior, callbacks, and exceptions unless a separately documented defect +requires a change. Bump the release version for the PR. + +Evaluate #69 with reproducible fresh-process benchmarks on real Ensembl and +GENCODE GTF data, both plain and gzip where practical. Compare current Polars +with pandas C and direct PyArrow CSV prototypes using equivalent dtypes, +attribute expansion, filtering, and output. Measure stage wall/CPU time and +peak RSS, validate output equivalence outside timed work, and report versions, +input hashes/sizes, thread counts, repeated-run ranges, and limitations. +Separate parser time from Python attribute expansion and frame conversions; +do not infer end-to-end gains from CSV microbenchmarks. Include pandas 2.x and +3.x if available. Avoid a speculative backend migration: use measured results +to decide whether a migration is justified and document remaining compatibility +work if the prototype is not ready to replace the production parser. + +## Plan + +- [x] Read repository guidance, open Polars issues, implementation, and CI. +- [x] Create branch and check in with compatibility/benchmark scope. +- [x] Close #19 with an explicit unreproduced disposition. +- [x] Validate the minimum across the full suite, fix confirmed failures, and + update dependency metadata/CI/version. +- [ ] Build benchmark harness, validate prototypes, run repeated realistic + comparisons, and investigate the measured bottleneck. +- [ ] Record findings on #69, regression evidence on #85, and benchmark results. +- [ ] Run ./lint.sh and ./test.sh, verify packaging, and review final diff. +- [ ] Open PR, pass CI, merge, deploy with ./deploy.sh from clean master, and + verify the published package. +- [ ] Review remaining gtfparse issues for the next useful independent work. + +## Review + +Pending validation and measurements. + +The full suite passes at Polars 0.20.31 (142 passed, one modern-only skip). +Dependency and CI minimum now agree. The Arrow-extension benchmark prototype +needs an object bridge for nullable categoricals: pandas 2.3.3's direct cast +raises ArrowInvalid on StringTie's missing strands. This is a prototype +compatibility cost, not a failure in the production Polars reader. Stop the +initial timing sweep, validate that bridge on all fixtures, and restart the +sweep from scratch so all measurements use identical prototype code. + +All 80 fixture/backend/filter/version comparisons now pass, including pandas +2.3.3 and 3.0.6. The first 250,000 real rows from each source were tested plain +and gzip, with repeated fresh-process timings and matching content hashes. +Larger runs cover one million Ensembl rows and all 4,119,244 GENCODE rows. + +Also verified and closed historical Bioconda #43: the live recipe no longer +has its reported Polars <0.17 pin. The recipe still trails the upstream release; +the closure comment explicitly separates that from #85's current minimum fix. +Filed openvax/pyensembl#423 for its confirmed default-Polars output followed by +an immediate pandas conversion. No downstream source changes are included. + +# Remove the required Polars dependency: #69 and #85 + +## Revised specification + +The user asked to find a way to remove Polars. Supersede the earlier +compatibility-only release plan with a measured reader/writer migration. +Use PyArrow's typed TSV reader, with fresh-process measurements and the full +API audit to verify suitability. Keep attribute expansion, aliases, version casts, biotype +inference, column selection/converters, missing-value semantics, and progress +callbacks. Validate exactly nine fields without truncating literal # in quoted +attributes; ignore whole comment lines anywhere in paths, gzip and text/byte +streams. Keep caller-owned streams open and support non-seekable streams. +Malformed/empty inputs raise the package's ParsingError, with no false progress +completion. Preserve categorical fixed columns, float32 scores, uint32 frames, +row/column ordering and dict shape. Replace the Polars writer with pandas and +bounded row batches; preserve gzip, headers, nulls and raw attributes. + +Make ordinary imports, reads and writes work with pandas/PyArrow and no Polars. +Keep explicit result_type='polars' and parse_with_polars_lazy as optional +conversion adapters, loaded only when requested, with a useful installation +error. Put Polars in the 'polars' extra; PyArrow remains a core dependency. +The proposed pandas default and lower-level pandas return types warrant 3.0.0; +the user confirmed pandas by default with optional Polars output. +Document the migration explicitly, including the new package error for empty +input. Retain the legacy lazy helper as an eager-read/lazy-conversion adapter. + +Compare old production, the complete new production reader, and the prototypes +on real Ensembl/GENCODE subsets, plain and gzip, in fresh sequential processes; +validate all content outside timing, record repeated ranges/RSS/versions and +input hashes. Do not claim speedups from noisy single measurements. Run the +full suite in an environment without Polars, plus optional-extra +compatibility jobs and pandas minimum/current coverage. Verify both wheel and +source dependencies and run shipped lint/test scripts from the source archive. +File any newly discovered production defects as issues and link the PR. +Ship via PR and deploy.sh from clean master, then verify PyPI and review the +remaining issues without automatically starting unrelated work. + +## Plan + +- [x] Read the prior plan, source, public APIs and benchmark prototypes. +- [x] Create a new feature branch, preserve a baseline, and check in with scope. +- [x] Measure candidates and validate the default/output migration preference. +- [x] Replace reader/writer internals; make Polars an optional adapter. +- [x] Add API/stream/error/round-trip and no-Polars regression coverage. +- [x] Update dependency metadata, CI, migration docs and version. +- [x] Record repeatable benchmark evidence and review the implementation. +- [x] Run ./lint.sh and ./test.sh; validate minimal/optional environments and archives. +- [ ] Open PR, pass checks, merge, deploy and verify the released distributions. +- [ ] Review open issues for the next foundational candidate. + +## Review + +CI recovery replan: hosted runner assignment failures interrupted the first +workflow attempt. A rerun then reproduced Coveralls rejecting uploads because +the original attempt had already finalized the same GitHub run ID. File this +workflow defect, give every attempt a distinct Coveralls service number shared +by uploads and finalization, rerun the required scripts and validate both the +new workflow and a full rerun before merging. Preserve coverage aggregation. Tracked as #90; use the documented +COVERALLS_SERVICE_NUMBER override at workflow scope. + +Version 3 removes mandatory Polars imports and dependencies, uses typed Arrow +reading and pandas processing/writing, and preserves explicit Polars adapters. +The user confirmed the pandas default and optional Polars policy. Fixed-column +and expanded results match the 2.9.1 baseline in 100 API comparisons across +pandas 2.3.3/3.0.6; 60 prototype comparisons also pass. Core regressions cover +stream ownership/short reads/gzip/BOM/comments, field validation, exact int64s, +filtered nullable coordinates, quote cleanup order, callbacks/cancellation, +nullable attributes and writer batches. + +./lint.sh passes. ./test.sh with deprecations as errors passes 172 tests on +pandas 2.3.3/Polars 1.44.2 (97% coverage). Base environments without Polars pass +158 tests with 10 optional skips on pandas 3.0.6/PyArrow 25.0.1, pandas 3.0.6/ +PyArrow 18.0.0/Python 3.11, and the corrected pandas 2.2.2/PyArrow 18.0.0/ +NumPy 2.0.2/Python 3.9 minimum (96% coverage). Optional Polars 0.20.31 passes +171 tests with one modern-only skip; its separate categorical joins emit the +native remapping warning, without changing process-wide string-cache state. +The pandas/NumPy ABI minimum problem is tracked and fixed as #87. + +All 122 retained benchmark records have matching content hashes per input. +Three-run subset medians show 1.10–1.20x complete-load time and about 1.03–1.10x +peak RSS. The full 4,119,244-row GENCODE scaling pair matches all columns: +2.9.1 takes 38.88s / 6189 MiB, while 3.0 takes 45.40s / 5348 MiB. This single +pair demonstrates full-file correctness/scaling, not stable throughput. +Benchmark method, input hashes, medians/ranges and limitations are recorded +in benchmarks/README.md and benchmarks/results.json. In particular, read-stage +callbacks do different conversion work, so do not assert #69's raw-CSV 3x +criterion from them; the measured complete load meets its 1.5x threshold. +Packaging and release verification follow below and in the PR release record. + +Backend decision: the C prototype's first Ensembl run took 3.95s against +2.47s for the baseline, while Arrow took 2.91s (identical content checksum). +Use Arrow for the fixed-column reader and pandas for all subsequent operations; +keep PyArrow required, move only Polars to an extra. The initial C implementation +was an evaluation and is superseded before final benchmarking. + +Full API comparisons passed: 50 baseline/new pandas comparisons and 30 +prototype comparisons on each of pandas 2.3.3 and 3.0.6 (160 comparisons). +Regression coverage also confirms filtering before pandas conversion preserves +integer coordinate dtypes when discarded rows contain null coordinates. Optional +quote cleanup still precedes filtering when requested. Avoid copying an all-valid +seqname column mask; filter missing seqnames only when present. Restart the final +production comparison sweep after these changes; keep the prototype records, +whose implementation is unchanged. + +Dependency-floor replan: the pandas 2.1.0 minimum only imports with NumPy 1.x. +Reproduced its ABI import failure with NumPy 2.0.2 on Python 3.9.22. Raise the +pandas floor to 2.2.2, remove the CI-only NumPy<2 workaround, file the discovered +metadata problem, and validate the new minimum with NumPy 2 before shipping. + +Archive verification found test.sh probes xdist with one Python but executes +a different pytest binary from PATH. Reproduced shared-venv Python/xdist versus +Homebrew pytest without xdist, yielding unrecognized -n. Use python -m pytest +for the log/exec path, file the defect, rebuild and execute the shipped scripts. + +Packaging: wheel and source metadata agree on pandas>=2.2.2, PyArrow>=18.0.0 +and Polars>=0.20.31 only behind the polars extra. Both pass strict twine checks. +The wheel excludes tests/benchmarks; the sdist contains all source/test Python +files, fixtures, runner scripts and benchmark evidence. Installing the wheel +into a fresh base environment loads from site-packages, installs no Polars, +and round-trips all five real fixtures. Archive runner mismatch fixed as #88; +shipped lint/tests pass with python -m pytest. Release status and published +artifact verification will be recorded on the PR to keep clean master clean. diff --git a/test.sh b/test.sh index e40eb95..b41fbd0 100755 --- a/test.sh +++ b/test.sh @@ -99,10 +99,10 @@ XDIST_FLAGS=() if python -c "import xdist" 2>/dev/null; then XDIST_FLAGS=(-n "$WORKERS") log "platform=${OS} cpus=${CPUS} cpu_cap=${CPU_CAP} ${mem_note} per_worker=${PER_WORKER_GB}GB" - log "workers=${WORKERS} → exec pytest -n ${WORKERS} --cov=gtfparse/ --cov-report=term-missing tests $*" + log "workers=${WORKERS} → exec python -m pytest -n ${WORKERS} --cov=gtfparse/ --cov-report=term-missing tests $*" else log "platform=${OS} cpus=${CPUS} (pytest-xdist not installed; running serial)" - log "→ exec pytest --cov=gtfparse/ --cov-report=term-missing tests $*" + log "→ exec python -m pytest --cov=gtfparse/ --cov-report=term-missing tests $*" fi -exec pytest "${XDIST_FLAGS[@]}" --cov=gtfparse/ --cov-report=term-missing tests "$@" +exec python -m pytest "${XDIST_FLAGS[@]}" --cov=gtfparse/ --cov-report=term-missing tests "$@" diff --git a/tests/data.py b/tests/data.py index bca618e..8565a2a 100644 --- a/tests/data.py +++ b/tests/data.py @@ -1,4 +1,9 @@ import os +from importlib.util import find_spec + +import pytest + +optional_polars = pytest.mark.skipif(find_spec("polars") is None, reason="Requires polars extra") def data_path(name): diff --git a/tests/test_create_missing_features.py b/tests/test_create_missing_features.py index d2a697c..b659f38 100644 --- a/tests/test_create_missing_features.py +++ b/tests/test_create_missing_features.py @@ -28,7 +28,6 @@ GTF_DATAFRAME = parse_gtf_and_expand_attributes(StringIO(GTF_TEXT)) -GTF_DATAFRAME = GTF_DATAFRAME.to_pandas() def test_create_missing_features_identity(): diff --git a/tests/test_expand_attribute_column_false.py b/tests/test_expand_attribute_column_false.py index ab74485..1c72a70 100644 --- a/tests/test_expand_attribute_column_false.py +++ b/tests/test_expand_attribute_column_false.py @@ -4,7 +4,7 @@ from gtfparse import read_gtf -from .data import data_path +from .data import data_path, optional_polars GTF_PATH = data_path("ensembl_grch37.head.gtf") @@ -27,6 +27,7 @@ def test_expand_attribute_column_false_returns_raw_attribute_pandas(): assert any("gene_id" in val for val in df["attribute"].astype(str)) +@optional_polars def test_expand_attribute_column_false_returns_polars(): df = read_gtf(GTF_PATH, expand_attribute_column=False, result_type="polars") # polars dataframe — has columns attribute but no per-key columns diff --git a/tests/test_gencode_gtf.py b/tests/test_gencode_gtf.py index a344847..f69996b 100644 --- a/tests/test_gencode_gtf.py +++ b/tests/test_gencode_gtf.py @@ -7,7 +7,7 @@ from gtfparse import GENCODE_BIOTYPE_ALIASES, INTEGER_VERSION_COLUMNS, read_gtf -from .data import data_path +from .data import data_path, optional_polars GENCODE_GTF_PATH = data_path("gencode.head.gtf") GENCODE_REAL_GTF_PATH = data_path("gencode.real.head.gtf") @@ -45,6 +45,7 @@ def test_attribute_aliases_renames_gencode_to_ensembl(): } +@optional_polars def test_attribute_aliases_with_polars_result_type(): df = read_gtf( GENCODE_GTF_PATH, @@ -141,6 +142,7 @@ def test_cast_version_columns_false_keeps_strings(): assert gene_rows.loc[0, "gene_version"] == "5" +@optional_polars def test_version_columns_present_in_polars_result(): df = read_gtf(GENCODE_GTF_PATH, result_type="polars") for column_name in INTEGER_VERSION_COLUMNS: diff --git a/tests/test_parse_gtf_lines.py b/tests/test_parse_gtf_lines.py index b9bf3ed..c91cab8 100644 --- a/tests/test_parse_gtf_lines.py +++ b/tests/test_parse_gtf_lines.py @@ -33,7 +33,7 @@ def test_parse_gtf_lines_with_expand_attributes(): assert list(df["start"]) == [11869, 11869] assert list(df["end"]) == [14409, 14409] - assert df["score"].is_null().all(), "Unexpected scores: %s" % (df["score"],) + assert df["score"].isna().all(), "Unexpected scores: %s" % (df["score"],) assert list(df["gene_id"]) == ["ENSG00000223972", "ENSG00000223972"] assert list(df["transcript_id"]) == ["", "ENST00000456328"] @@ -47,7 +47,7 @@ def test_parse_gtf_lines_without_expand_attributes(): # convert to list for comparison since numerical columns may be NumPy arrays assert list(df["start"]) == [11869, 11869] assert list(df["end"]) == [14409, 14409] - assert df["score"].is_null().all(), "Unexpected scores: %s" % (df["score"],) + assert df["score"].isna().all(), "Unexpected scores: %s" % (df["score"],) assert len(df["attribute"]) == 2 diff --git a/tests/test_polars_compatibility.py b/tests/test_polars_compatibility.py index 3eb9062..4211bf7 100644 --- a/tests/test_polars_compatibility.py +++ b/tests/test_polars_compatibility.py @@ -1,11 +1,12 @@ from io import StringIO -import polars import pytest -from gtfparse import read_gtf +from gtfparse import read_gtf, write_gtf from gtfparse.read_gtf import parse_with_polars_lazy +polars = pytest.importorskip("polars") + GTF_TEXT = ( '1\tensembl\tgene\t10\t20\t.\t+\t.\tgene_id "g1";\n' '2\thavana\texon\t30\t40\t.\t-\t.\tgene_id "g2";\n' @@ -48,4 +49,14 @@ def fail_on_cache_toggle(): monkeypatch.setattr(polars, "enable_string_cache", fail_on_cache_toggle) monkeypatch.setattr(polars, "disable_string_cache", fail_on_cache_toggle) - assert read_gtf(StringIO(GTF_TEXT)).height == 2 + assert read_gtf(StringIO(GTF_TEXT), result_type="polars").height == 2 + + +def test_optional_polars_writer_round_trip(tmp_path): + original = read_gtf(StringIO(GTF_TEXT), result_type="polars") + path = tmp_path / "out.gtf.gz" + write_gtf(original, path) + recovered = read_gtf(path, result_type="polars") + from polars.testing import assert_frame_equal + + assert_frame_equal(original, recovered, categorical_as_str=True) diff --git a/tests/test_progress.py b/tests/test_progress.py index b47ec75..5730879 100644 --- a/tests/test_progress.py +++ b/tests/test_progress.py @@ -2,11 +2,10 @@ from io import BytesIO, StringIO import pandas as pd -import polars import pytest -from polars.testing import assert_frame_equal from gtfparse import ( + ParsingError, expand_attribute_strings, parse_gtf, parse_gtf_and_expand_attributes, @@ -14,13 +13,17 @@ read_gtf, ) +from .data import optional_polars + GTF = ( '1\ttest\tgene\t1\t100\t.\t+\t.\tgene_id "G1"; gene_version "2";\n' '1\ttest\texon\t1\t50\t.\t+\t0\tgene_id "G1"; tag "basic";\n' ) -@pytest.mark.parametrize("result_type", ["polars", "pandas", "dict"]) +@pytest.mark.parametrize( + "result_type", [pytest.param("polars", marks=optional_polars), "pandas", "dict"] +) @pytest.mark.parametrize("expand", [True, False]) @pytest.mark.parametrize("features,rows", [(None, 2), ({"gene"}, 1), ({"CDS"}, 0)]) def test_read_progress_preserves_results(result_type, expand, features, rows, capsys): @@ -37,6 +40,8 @@ def test_read_progress_preserves_results(result_type, expand, features, rows, ca StringIO(GTF), progress_callback=lambda *event: events.append(event), **kwargs ) if result_type == "polars": + from polars.testing import assert_frame_equal + assert_frame_equal(actual, expected) elif result_type == "pandas": pd.testing.assert_frame_equal(actual, expected) @@ -66,7 +71,7 @@ def test_progress_with_supported_inputs(kind, tmp_path): source = StringIO(GTF) events = [] result = read_gtf(source, progress_callback=lambda *event: events.append(event)) - assert result.height == 2 + assert len(result) == 2 assert events[-1] == ("convert", 2, 2) @@ -145,9 +150,9 @@ def callback(*event): assert not any(event[0] == "convert" for event in events) -def test_empty_file_keeps_existing_error_without_completion(): +def test_empty_file_raises_parsing_error_without_completion(): events = [] - with pytest.raises(polars.exceptions.NoDataError): + with pytest.raises(ParsingError): read_gtf(StringIO(""), progress_callback=lambda *event: events.append(event)) assert events == [("read", 0, None)] diff --git a/tests/test_reader.py b/tests/test_reader.py new file mode 100644 index 0000000..ebdc848 --- /dev/null +++ b/tests/test_reader.py @@ -0,0 +1,201 @@ +import gzip +import subprocess +import sys +from io import BytesIO, StringIO + +import pandas as pd +import pytest + +from gtfparse import ParsingError, parse_gtf, read_gtf, write_gtf +from gtfparse._read_csv import _GtfReader, _PrefixedReader + +GTF = 'NA\ttest\tgene\t1\t100\t.\t+\t.\tgene_id "G1"; note "café #1; ok";\n' + + +@pytest.mark.parametrize("size", [1, 7, 128, -1]) +def test_arrow_input_adapter_respects_byte_read_sizes(size): + payload = ("\ufeff#header\n" + GTF + "#comment\n" + GTF.rstrip("\n")).encode() + with _GtfReader(BytesIO(payload)) as reader: + assert reader.readable() + assert reader.read(0) == b"" + chunks = [] + while chunk := reader.read(size): + if size >= 0: + assert len(chunk) <= size + chunks.append(chunk) + assert b"".join(chunks) == (GTF * 2).encode() + + +def test_gzip_prefix_adapter_handles_partial_and_complete_reads(): + reader = _PrefixedReader(BytesIO(b"rest"), b"prefix") + assert reader.read(2) == b"pr" + assert reader.read(5) == b"efixr" + assert reader.read() == b"est" + + +def test_arrow_input_adapter_rejects_malformed_lines(): + with _GtfReader(StringIO(GTF + "bad\n")) as reader, pytest.raises(ParsingError): + reader.read() + + +@pytest.mark.parametrize("binary", [False, True]) +def test_comments_bom_crlf_and_literal_hash(binary): + text = "\ufeff##header\n" + GTF + "#\tcomment\twith\teight\ttabs\t.\t.\t.\t.\n" + GTF + text = text.replace("\n", "\r\n") + source = BytesIO(text.encode()) if binary else StringIO(text) + frame = read_gtf(source) + assert isinstance(frame, pd.DataFrame) + assert frame["seqname"].tolist() == ["NA", "NA"] + assert frame["note"].tolist() == ["café #1; ok", "café #1; ok"] + assert not source.closed + + +@pytest.mark.parametrize("compressed", [False, True]) +def test_nonseekable_short_reads_across_utf8_and_line_boundaries(compressed): + payload = ("\ufeff#header\n" + GTF.rstrip("\n")).encode() + if compressed: + payload = gzip.compress(payload) + + class Stream: + def __init__(self): + self.buffer = BytesIO(payload) + + def read(self, size=-1): + return self.buffer.read(min(size, 1) if size >= 0 else size) + + frame = read_gtf(Stream()) + assert frame["note"].tolist() == ["café #1; ok"] + + +def test_gzip_detected_from_contents_and_caller_stream_stays_open(tmp_path): + payload = gzip.compress(GTF.encode()) + path = tmp_path / "annotation.GZ" + path.write_bytes(payload) + stream = BytesIO(payload) + pd.testing.assert_frame_equal(read_gtf(path), read_gtf(stream)) + assert not stream.closed + + +@pytest.mark.parametrize("text", ["", "#header\n", " \n\n"]) +def test_empty_input_is_package_error(text): + events = [] + with pytest.raises(ParsingError): + read_gtf(StringIO(text), progress_callback=lambda *event: events.append(event)) + assert events == [("read", 0, None)] + + +@pytest.mark.parametrize("change", ["short", "extra", "bad_start", "negative_frame", "overflow"]) +def test_invalid_rows_raise_package_error_without_completion(change): + fields = GTF.rstrip("\n").split("\t") + if change == "short": + fields.pop() + elif change == "extra": + fields.append("extra") + elif change == "bad_start": + fields[3] = "abc" + elif change == "negative_frame": + fields[7] = "-1" + else: + fields[3] = "9223372036854775808" + events = [] + with pytest.raises(ParsingError): + read_gtf(StringIO("\t".join(fields)), progress_callback=lambda *e: events.append(e)) + assert events == [("read", 0, None)] + + +def test_fixed_column_types_missing_values_and_large_integers(): + text = ( + "1\ttest\tgene\t9007199254740993\t9007199254740995\t0.25\t+\t2\t.\n" + '1\ttest\tgene\t1\t10\t.\t.\t.\tgene_id "G1";\n' + ) + frame = read_gtf(StringIO(text)) + assert frame["start"].tolist() == [9007199254740993, 1] + assert frame["start"].dtype == "int64" + assert frame["score"].dtype == "float32" + assert pd.isna(frame["score"][1]) + assert frame["frame"].dtype == "uint32" + assert frame["frame"].tolist() == [2, 0] + assert frame["strand"].dtype == "category" + assert pd.isna(frame["strand"][1]) + assert frame["gene_id"].tolist() == ["", "G1"] + + +def test_split_attributes_keep_quoted_semicolons(): + frame = parse_gtf(StringIO(GTF)) + assert frame["attribute_split"][0] == ['gene_id "G1"', 'note "café #1; ok"'] + + +def test_filtered_out_null_coordinates_do_not_change_integer_types(): + text = '1\ttest\texon\t.\t20\t.\t+\t.\tgene_id "G2";\n' + GTF + frame = read_gtf(StringIO(text), features={"gene"}) + assert frame["start"].dtype == "int64" + assert frame["start"].tolist() == [1] + assert frame["end"].dtype == "int64" + + +def test_null_seqnames_are_dropped_before_attribute_expansion(): + frame = read_gtf(StringIO(GTF.replace("NA\t", ".\t") + GTF)) + assert frame["gene_id"].tolist() == ["G1"] + assert frame.index.tolist() == [0] + + +def test_opt_in_quote_cleanup_precedes_feature_filter(): + frame = parse_gtf( + StringIO(GTF.replace("\tgene\t", "\tgene;-x\t")), + features={"gene-x"}, + fix_quotes_columns=["feature"], + ) + assert frame["feature"].tolist() == ["gene-x"] + + +def test_invalid_writer_input_does_not_replace_destination(tmp_path): + path = tmp_path / "existing.gtf" + path.write_text("keep") + with pytest.raises(TypeError, match="DataFrame"): + write_gtf({}, path) + assert path.read_text() == "keep" + + +def test_base_api_does_not_import_polars(tmp_path): + code = """ +import importlib.abc +import sys +from io import StringIO + +class NoPolars(importlib.abc.MetaPathFinder): + def find_spec(self, fullname, path=None, target=None): + if fullname == "polars" or fullname.startswith("polars."): + raise AssertionError("Base API attempted to import Polars") + +sys.meta_path.insert(0, NoPolars()) +from gtfparse import read_gtf, write_gtf, parse_gtf, parse_gtf_and_expand_attributes +text = '1\\ttest\\tgene\\t1\\t100\\t.\\t+\\t.\\tgene_id "G1";\\n' +frame = read_gtf(StringIO(text)) +assert "polars" not in sys.modules +assert frame["gene_id"].tolist() == ["G1"] +parse_gtf(StringIO(text)) +parse_gtf_and_expand_attributes(StringIO(text)) +write_gtf(frame, sys.argv[1]) +assert read_gtf(sys.argv[1])["gene_id"].tolist() == ["G1"] +assert "polars" not in sys.modules +""" + subprocess.run([sys.executable, "-c", code, str(tmp_path / "out.gtf")], check=True) + + +def test_missing_polars_fails_before_reading(monkeypatch): + monkeypatch.setitem(sys.modules, "polars", None) + source = StringIO(GTF) + events = [] + with pytest.raises(ImportError, match=r"gtfparse\[polars\]"): + read_gtf(source, result_type="polars", progress_callback=lambda *e: events.append(e)) + assert source.tell() == 0 + assert events == [] + + +def test_writer_handles_multiple_batches_and_nullable_attributes(tmp_path): + frame = read_gtf(StringIO(GTF)) + frame = pd.concat([frame] * 10_003, ignore_index=True) + frame["gene_version"] = pd.Series([1] + [pd.NA] * (len(frame) - 1), dtype="Int64") + out = tmp_path / "out.gtf.gz" + write_gtf(frame, out) + pd.testing.assert_frame_equal(frame, read_gtf(out)) diff --git a/tests/test_write_gtf.py b/tests/test_write_gtf.py index 9b513b8..df38386 100644 --- a/tests/test_write_gtf.py +++ b/tests/test_write_gtf.py @@ -1,8 +1,8 @@ import gzip -import polars +import pandas as pd import pytest -from polars.testing import assert_frame_equal +from pandas.testing import assert_frame_equal from gtfparse import read_gtf, write_gtf @@ -37,7 +37,7 @@ def _minimal_df(**extra_columns): "frame": [None], } row.update(extra_columns) - return polars.DataFrame(row) + return pd.DataFrame(row) # --------------------------------------------------------------------------- @@ -54,7 +54,7 @@ def test_write_read_recovers_parsed_frame(fixture, expand, tmp_path): out_path = tmp_path / "out.gtf" write_gtf(original, out_path) recovered = read_gtf(str(out_path), expand_attribute_column=expand) - assert_frame_equal(original, recovered, categorical_as_str=True) + assert_frame_equal(original, recovered) @pytest.mark.parametrize("fixture", FIXTURES) @@ -85,7 +85,7 @@ def test_read_write_recovers_dataframe(tmp_path): # writing the recovered frame is itself a fixed point again = tmp_path / "df2.gtf" write_gtf(recovered, again) - assert_frame_equal(recovered, read_gtf(str(again)), categorical_as_str=True) + assert_frame_equal(recovered, read_gtf(str(again))) def test_round_trip_from_pandas(tmp_path): @@ -94,7 +94,7 @@ def test_round_trip_from_pandas(tmp_path): pandas_df = read_gtf(data_path("ensembl_grch37.head.gtf"), result_type="pandas") out_path = tmp_path / "from_pandas.gtf" write_gtf(pandas_df, out_path) - assert_frame_equal(polars_df, read_gtf(str(out_path)), categorical_as_str=True) + assert_frame_equal(polars_df, read_gtf(str(out_path))) def test_gzip_output_round_trips(tmp_path): @@ -106,7 +106,7 @@ def test_gzip_output_round_trips(tmp_path): assert out_path.read_bytes()[:2] == b"\x1f\x8b" with gzip.open(out_path, "rt") as handle: assert "\t" in handle.readline() - assert_frame_equal(df, read_gtf(str(out_path)), categorical_as_str=True) + assert_frame_equal(df, read_gtf(str(out_path))) def test_gzip_detection_is_case_insensitive(tmp_path): @@ -119,7 +119,7 @@ def test_gzip_detection_is_case_insensitive(tmp_path): def test_empty_dataframe_writes_no_rows(tmp_path): """A zero-row DataFrame produces a file with only its header lines.""" - empty = read_gtf(data_path("refseq.ucsc.small.gtf")).clear() + empty = read_gtf(data_path("refseq.ucsc.small.gtf")).iloc[:0] out_path = tmp_path / "empty.gtf" write_gtf(empty, out_path, header_lines=["##empty"]) assert out_path.read_text() == "##empty\n" @@ -128,7 +128,7 @@ def test_empty_dataframe_writes_no_rows(tmp_path): def test_fixed_columns_only(tmp_path): """A DataFrame with only the fixed columns writes a valid 9-field line (empty attribute field) and reads back.""" - fixed_only = polars.DataFrame( + fixed_only = pd.DataFrame( { "seqname": ["chr1"], "source": ["test"], @@ -209,10 +209,10 @@ def test_header_lines_are_written(tmp_path): assert lines[0] == "##description: test" assert lines[1] == "##provider: gtfparse" # comment lines are ignored by read_gtf, so the data still round-trips - assert_frame_equal(df, read_gtf(str(out_path)), categorical_as_str=True) + assert_frame_equal(df, read_gtf(str(out_path))) def test_missing_required_column_raises(tmp_path): - df = polars.DataFrame({"seqname": ["chr1"], "gene_id": ["G1"]}) + df = pd.DataFrame({"seqname": ["chr1"], "gene_id": ["G1"]}) with pytest.raises(ValueError, match="missing required GTF column"): write_gtf(df, tmp_path / "bad.gtf")