From 01050bc836cd9f416481d228119cf124a0a4a9ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Wieiw=C3=B3rka?= Date: Wed, 25 Dec 2024 08:49:54 +0100 Subject: [PATCH] Benchmark refactor --- .github/workflows/publish_documentation.yml | 4 +- .gitignore | 3 +- Cargo.lock | 2 +- benchmark/queries/0-1.sql | 18 - benchmark/queries/0-3.sql | 18 - benchmark/queries/0-8.sql | 18 - benchmark/queries/7-8.sql | 18 - benchmark/queries/complement/table_1.csv | 5 - benchmark/queries/complement/table_2.csv | 3 - benchmark/queries/complement/test.sql | 63 - benchmark/queries/nearest/table_1.csv | 2 - benchmark/queries/nearest/table_2.csv | 3 - benchmark/queries/nearest/test.sql | 58 - benchmark/run_bench.ipynb | 1532 ------------------- benchmark/src/bench_overlap.py | 101 ++ docs/performance.md | 43 + mkdocs.yml | 9 +- poetry.lock | 576 ++++--- polars_bio/__init__.py | 4 +- polars_bio/range_op.py | 5 +- pyproject.toml | 8 +- 21 files changed, 510 insertions(+), 1983 deletions(-) delete mode 100644 benchmark/queries/0-1.sql delete mode 100644 benchmark/queries/0-3.sql delete mode 100644 benchmark/queries/0-8.sql delete mode 100644 benchmark/queries/7-8.sql delete mode 100644 benchmark/queries/complement/table_1.csv delete mode 100644 benchmark/queries/complement/table_2.csv delete mode 100644 benchmark/queries/complement/test.sql delete mode 100644 benchmark/queries/nearest/table_1.csv delete mode 100644 benchmark/queries/nearest/table_2.csv delete mode 100644 benchmark/queries/nearest/test.sql delete mode 100644 benchmark/run_bench.ipynb create mode 100755 benchmark/src/bench_overlap.py diff --git a/.github/workflows/publish_documentation.yml b/.github/workflows/publish_documentation.yml index 2f0aea9..903e567 100644 --- a/.github/workflows/publish_documentation.yml +++ b/.github/workflows/publish_documentation.yml @@ -6,8 +6,10 @@ on: workflow_dispatch: jobs: build: + env: + JUPYTER_PLATFORM_DIRS: 1 name: Deploy docs - runs-on: ubuntu-latest + runs-on: [self-hosted, Linux, huge-c10m25] steps: - name: Checkout main uses: actions/checkout@v2 diff --git a/.gitignore b/.gitignore index 0d1e961..46cad3a 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ venv .idea sandbox/ .DS_Store -site/ \ No newline at end of file +site/ +benchmark/bin/env.sh \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 760ef6c..df7bcb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2734,7 +2734,7 @@ checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "polars_bio" -version = "0.2.12" +version = "0.3.0" dependencies = [ "arrow", "datafusion", diff --git a/benchmark/queries/0-1.sql b/benchmark/queries/0-1.sql deleted file mode 100644 index 1eb4146..0000000 --- a/benchmark/queries/0-1.sql +++ /dev/null @@ -1,18 +0,0 @@ -SET sequila.prefer_interval_join TO true; -SET datafusion.execution.target_partitions=1; -SET sequila.interval_join_algorithm TO coitrees; -SET datafusion.optimizer.repartition_joins TO false; -SET datafusion.execution.coalesce_batches TO false; - -CREATE EXTERNAL TABLE a -STORED AS PARQUET -LOCATION '/Users/mwiewior/research/git/openstack-bdg-runners/ansible/roles/gha_runner/files/databio/chainRn4/*parquet'; - -CREATE EXTERNAL TABLE b -STORED AS PARQUET -LOCATION '/Users/mwiewior/research/git/openstack-bdg-runners/ansible/roles/gha_runner/files/databio/fBrain-DS14718/*parquet'; - -select count(1) from a join b - on a.contig = b.contig - and a.pos_end > b.pos_start - and a.pos_start < b.pos_end; diff --git a/benchmark/queries/0-3.sql b/benchmark/queries/0-3.sql deleted file mode 100644 index 50d5b5c..0000000 --- a/benchmark/queries/0-3.sql +++ /dev/null @@ -1,18 +0,0 @@ -SET sequila.prefer_interval_join TO true; -SET datafusion.execution.target_partitions=8; -SET sequila.interval_join_algorithm TO coitrees; -SET datafusion.optimizer.repartition_joins TO false; -SET datafusion.execution.coalesce_batches TO false; - -CREATE EXTERNAL TABLE a -STORED AS PARQUET -LOCATION '/Users/mwiewior/research/git/openstack-bdg-runners/ansible/roles/gha_runner/files/databio-8p/chainRn4/*parquet'; - -CREATE EXTERNAL TABLE b -STORED AS PARQUET -LOCATION '/Users/mwiewior/research/git/openstack-bdg-runners/ansible/roles/gha_runner/files/databio-8p/chainOrnAna1/*parquet'; - -select count(1) from a join b - on a.contig = b.contig - and a.pos_end > b.pos_start - and a.pos_start < b.pos_end; diff --git a/benchmark/queries/0-8.sql b/benchmark/queries/0-8.sql deleted file mode 100644 index ae06168..0000000 --- a/benchmark/queries/0-8.sql +++ /dev/null @@ -1,18 +0,0 @@ -SET sequila.prefer_interval_join TO true; -SET datafusion.execution.target_partitions=1; -SET sequila.interval_join_algorithm TO coitrees; -SET datafusion.optimizer.repartition_joins TO false; -SET datafusion.execution.coalesce_batches TO false; - -CREATE EXTERNAL TABLE a -STORED AS PARQUET -LOCATION '/Users/mwiewior/research/git/openstack-bdg-runners/ansible/roles/gha_runner/files/databio/chainRn4/*parquet'; - -CREATE EXTERNAL TABLE b -STORED AS PARQUET -LOCATION '/Users/mwiewior/research/git/openstack-bdg-runners/ansible/roles/gha_runner/files/databio/ex-rna/*parquet'; - -select count(1) from a join b - on a.contig = b.contig - and a.pos_end > b.pos_start - and a.pos_start < b.pos_end; diff --git a/benchmark/queries/7-8.sql b/benchmark/queries/7-8.sql deleted file mode 100644 index 089c437..0000000 --- a/benchmark/queries/7-8.sql +++ /dev/null @@ -1,18 +0,0 @@ -SET sequila.prefer_interval_join TO true; -SET datafusion.execution.target_partitions=1; -SET sequila.interval_join_algorithm TO coitrees; -SET datafusion.optimizer.repartition_joins TO false; -SET datafusion.execution.coalesce_batches TO false; - -CREATE EXTERNAL TABLE a -STORED AS PARQUET -LOCATION '/Users/mwiewior/research/git/openstack-bdg-runners/ansible/roles/gha_runner/files/databio/ex-anno/*parquet'; - -CREATE EXTERNAL TABLE b -STORED AS PARQUET -LOCATION '/Users/mwiewior/research/git/openstack-bdg-runners/ansible/roles/gha_runner/files/databio/ex-rna/*parquet'; - -select count(1) from a join b - on a.contig = b.contig - and a.pos_end > b.pos_start - and a.pos_start < b.pos_end; diff --git a/benchmark/queries/complement/table_1.csv b/benchmark/queries/complement/table_1.csv deleted file mode 100644 index d1bbafe..0000000 --- a/benchmark/queries/complement/table_1.csv +++ /dev/null @@ -1,5 +0,0 @@ -chrom,start,end -chr1,1,5 -chr1,3,8 -chr1,8,10 -chr1,12,4 \ No newline at end of file diff --git a/benchmark/queries/complement/table_2.csv b/benchmark/queries/complement/table_2.csv deleted file mode 100644 index 1ef8d90..0000000 --- a/benchmark/queries/complement/table_2.csv +++ /dev/null @@ -1,3 +0,0 @@ -chrom,size -chr1,100 -chrX,100 \ No newline at end of file diff --git a/benchmark/queries/complement/test.sql b/benchmark/queries/complement/test.sql deleted file mode 100644 index 8cf5e76..0000000 --- a/benchmark/queries/complement/test.sql +++ /dev/null @@ -1,63 +0,0 @@ -CREATE EXTERNAL TABLE table_1 -STORED AS CSV -LOCATION '/Users/mwiewior/research/git/polars-bio/benchmark/queries/complement/table_1.csv' -OPTIONS ('has_header' 'true'); - -CREATE EXTERNAL TABLE chrom_sizes -STORED AS CSV -LOCATION '/Users/mwiewior/research/git/polars-bio/benchmark/queries/complement/table_2.csv' -OPTIONS ('has_header' 'true'); - - -WITH sorted_intervals AS ( - SELECT chrom, start, end -FROM table_1 -ORDER BY chrom, start - ), - gaps AS ( -SELECT - si1.chrom, - si1.end AS gap_start, - si2.start AS gap_end -FROM sorted_intervals si1 - JOIN sorted_intervals si2 -ON si1.chrom = si2.chrom AND si1.end < si2.start -WHERE NOT EXISTS ( - SELECT 1 - FROM sorted_intervals si3 - WHERE si3.chrom = si1.chrom - AND si3.start < si2.start - AND si3.start > si1.end - ) - ), - boundary_gaps AS ( -SELECT - cs.chrom, - 0 AS start, - MIN(si.start) AS end -FROM chrom_sizes cs - LEFT JOIN sorted_intervals si ON cs.chrom = si.chrom -GROUP BY cs.chrom - -UNION ALL - -SELECT - cs.chrom, - MAX(si.end) AS start, - cs.size AS end -FROM chrom_sizes cs - LEFT JOIN sorted_intervals si ON cs.chrom = si.chrom -GROUP BY cs.chrom, cs.size - ), - all_gaps AS ( -SELECT chrom, gap_start AS start, gap_end AS end -FROM gaps - -UNION ALL - -SELECT chrom, start, end -FROM boundary_gaps - ) -SELECT chrom, start, end, chrom AS view_region -FROM all_gaps -ORDER BY chrom, start; diff --git a/benchmark/queries/nearest/table_1.csv b/benchmark/queries/nearest/table_1.csv deleted file mode 100644 index f46d077..0000000 --- a/benchmark/queries/nearest/table_1.csv +++ /dev/null @@ -1,2 +0,0 @@ -chrom,start,end -chr1,1,5 diff --git a/benchmark/queries/nearest/table_2.csv b/benchmark/queries/nearest/table_2.csv deleted file mode 100644 index 0c6473e..0000000 --- a/benchmark/queries/nearest/table_2.csv +++ /dev/null @@ -1,3 +0,0 @@ -chrom,start,end -chr1,4,8 -chr1,10,11 diff --git a/benchmark/queries/nearest/test.sql b/benchmark/queries/nearest/test.sql deleted file mode 100644 index c6703dd..0000000 --- a/benchmark/queries/nearest/test.sql +++ /dev/null @@ -1,58 +0,0 @@ -SET sequila.prefer_interval_join TO false; - -CREATE EXTERNAL TABLE table_A -STORED AS CSV -LOCATION '/Users/mwiewior/research/git/polars-bio/benchmark/queries/nearest/table_1.csv' -OPTIONS ('has_header' 'true'); - -CREATE EXTERNAL TABLE table_B -STORED AS CSV -LOCATION '/Users/mwiewior/research/git/polars-bio/benchmark/queries/nearest/table_2.csv' -OPTIONS ('has_header' 'true'); - - -explain WITH Distances AS ( - SELECT - A.chrom AS chrom_A, - A.start AS start_A, - A.end AS end_A, - B.chrom AS chrom_B, - B.start AS start_B, - B.end AS end_B, - CASE - WHEN A.end < B.start THEN B.start - A.end - WHEN B.end < A.start THEN A.start - B.end - ELSE 0 -- Overlapping ranges - END AS distance - FROM - table_A A - JOIN - table_B B - ON - A.chrom = B.chrom -), - Nearest AS ( - SELECT - chrom_A, - start_A, - end_A, - chrom_B, - start_B, - end_B, - distance, - ROW_NUMBER() OVER (PARTITION BY chrom_A, start_A, end_A ORDER BY distance ASC) AS rank - FROM - Distances - ) -SELECT - chrom_A, - start_A, - end_A, - chrom_B, - start_B, - end_B, - distance -FROM - Nearest -WHERE - rank = 2; diff --git a/benchmark/run_bench.ipynb b/benchmark/run_bench.ipynb deleted file mode 100644 index ea1e40b..0000000 --- a/benchmark/run_bench.ipynb +++ /dev/null @@ -1,1532 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "eb072f632cedbed3", - "metadata": {}, - "source": "## Install dependencies" - }, - { - "cell_type": "code", - "execution_count": null, - "id": "initial_id", - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "!pip install --force-reinstall bioframe==0.7.2 pyarrow fastparquet pyranges==0.1.2 pybedtools==0.10.0 git+https://gitlab.com/gtamazian/pygenomics.git" - ] - }, - { - "cell_type": "markdown", - "id": "11ecf3f76791210", - "metadata": {}, - "source": "## Setup the environment\n" - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "bc154f4724028a04", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T06:43:35.806399Z", - "start_time": "2024-12-16T06:43:35.801676Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "env: BENCH_DATA_ROOT=/Users/mwiewior/research/git/openstack-bdg-runners/ansible/roles/gha_runner/files/databio\n", - "env: SEQUILA_CLI=/Users/mwiewior/CLionProjects/sequila-native/target/release/sequila-cli\n" - ] - } - ], - "source": [ - "%env BENCH_DATA_ROOT=/Users/mwiewior/research/git/openstack-bdg-runners/ansible/roles/gha_runner/files/databio\n", - "%env SEQUILA_CLI=/Users/mwiewior/CLionProjects/sequila-native/target/release/sequila-cli" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "ae490515180f0af4", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T06:43:37.130136Z", - "start_time": "2024-12-16T06:43:37.128323Z" - } - }, - "outputs": [], - "source": [ - "import os\n", - "\n", - "BENCH_DATA_ROOT = os.getenv(\"BENCH_DATA_ROOT\", \"/data/bench_data/databio/\")" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "4ade8155f7bea44b", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T06:43:38.724196Z", - "start_time": "2024-12-16T06:43:38.482490Z" - } - }, - "outputs": [], - "source": [ - "import pandas as pd" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "21bb288ddcb3bc12", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T06:52:36.306325Z", - "start_time": "2024-12-16T06:52:36.304523Z" - } - }, - "outputs": [], - "source": [ - "# 0-\n", - "df_path_0 = f\"{BENCH_DATA_ROOT}/chainRn4/*.parquet\"\n", - "df_path_1 = f\"{BENCH_DATA_ROOT}/fBrain-DS14718/*.parquet\"" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "id": "9d4b74fee7c23e1f", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T06:52:37.511959Z", - "start_time": "2024-12-16T06:52:37.510079Z" - } - }, - "outputs": [], - "source": [ - "# 0-3\n", - "df_path_0 = f\"{BENCH_DATA_ROOT}/chainRn4/*.parquet\"\n", - "df_path_3 = f\"{BENCH_DATA_ROOT}/chainOrnAna1/*.parquet\"" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "id": "696876ae1fc468b9", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T06:52:38.857019Z", - "start_time": "2024-12-16T06:52:38.855346Z" - } - }, - "outputs": [], - "source": [ - "# 0-8\n", - "df_path_0 = f\"{BENCH_DATA_ROOT}/chainRn4/*.parquet\"\n", - "df_path_8 = f\"{BENCH_DATA_ROOT}/ex-rna/*.parquet\"" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "fdd8e48c1393bc2b", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T06:52:41.350810Z", - "start_time": "2024-12-16T06:52:41.348934Z" - } - }, - "outputs": [], - "source": [ - "# 7-8\n", - "df_path_7 = f\"{BENCH_DATA_ROOT}/ex-anno/*.parquet\"\n", - "df_path_8 = f\"{BENCH_DATA_ROOT}/ex-rna/*.parquet\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "948c4a842a06030a", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "3621a226d6b36e61", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T06:52:58.499429Z", - "start_time": "2024-12-16T06:52:58.246305Z" - } - }, - "outputs": [], - "source": [ - "df_0 = pd.read_parquet(df_path_0.replace(\"*.parquet\", \"\"), engine=\"pyarrow\")\n", - "df_1 = pd.read_parquet(df_path_1.replace(\"*.parquet\", \"\"), engine=\"pyarrow\")\n", - "df_3 = pd.read_parquet(df_path_3.replace(\"*.parquet\", \"\"), engine=\"pyarrow\")\n", - "df_7 = pd.read_parquet(df_path_7.replace(\"*.parquet\", \"\"), engine=\"pyarrow\")\n", - "df_8 = pd.read_parquet(df_path_8.replace(\"*.parquet\", \"\"), engine=\"pyarrow\")" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "90831b206d78970a", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T06:53:03.084092Z", - "start_time": "2024-12-16T06:53:02.506476Z" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "contig 320955\n", - "pos_start 320955\n", - "pos_end 320955\n", - "contig_ 320955\n", - "pos_start_ 320955\n", - "pos_end_ 320955\n", - "dtype: int64" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import bioframe as bf\n", - "\n", - "bf.overlap(\n", - " df_0,\n", - " df_1,\n", - " cols1=(\"contig\", \"pos_start\", \"pos_end\"),\n", - " cols2=(\"contig\", \"pos_start\", \"pos_end\"),\n", - " how=\"inner\",\n", - ").count()" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "7a7e25a918672b12", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-11T23:03:38.690900Z", - "start_time": "2024-12-11T23:03:38.455518Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0 row(s) fetched. \n", - "Elapsed 0.018 seconds.\n", - "\n", - "0 row(s) fetched. \n", - "Elapsed 0.000 seconds.\n", - "\n", - "0 row(s) fetched. \n", - "Elapsed 0.000 seconds.\n", - "\n", - "0 row(s) fetched. \n", - "Elapsed 0.000 seconds.\n", - "\n", - "0 row(s) fetched. \n", - "Elapsed 0.000 seconds.\n", - "\n", - "0 row(s) fetched. \n", - "Elapsed 0.009 seconds.\n", - "\n", - "0 row(s) fetched. \n", - "Elapsed 0.000 seconds.\n", - "\n", - "+-----------------+\n", - "| count(Int64(1)) |\n", - "+-----------------+\n", - "| 320955 |\n", - "+-----------------+\n", - "1 row(s) fetched. \n", - "Elapsed 0.138 seconds.\n", - "\n" - ] - } - ], - "source": [ - "%%bash\n", - "$SEQUILA_CLI --file queries/0-1.sql" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fcb27a787b8b7c97", - "metadata": {}, - "outputs": [], - "source": [ - "bf.overlap(\n", - " df_0,\n", - " df_3,\n", - " cols1=(\"contig\", \"pos_start\", \"pos_end\"),\n", - " cols2=(\"contig\", \"pos_start\", \"pos_end\"),\n", - " how=\"inner\",\n", - ").count()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "186b1e6fca447dc7", - "metadata": {}, - "outputs": [], - "source": [ - "%%bash\n", - "$SEQUILA_CLI --file queries/0-3.sql" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "74d31db9ac48f44f", - "metadata": {}, - "outputs": [], - "source": [ - "bf.overlap(\n", - " df_0,\n", - " df_8,\n", - " cols1=(\"contig\", \"pos_start\", \"pos_end\"),\n", - " cols2=(\"contig\", \"pos_start\", \"pos_end\"),\n", - " how=\"inner\",\n", - ").count()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bd5a331edde24cb1", - "metadata": {}, - "outputs": [], - "source": [ - "%%bash\n", - "$SEQUILA_CLI --file queries/0-8.sql" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d35eb67e7a3a3822", - "metadata": {}, - "outputs": [], - "source": [ - "bf.overlap(\n", - " df_7,\n", - " df_8,\n", - " cols1=(\"contig\", \"pos_start\", \"pos_end\"),\n", - " cols2=(\"contig\", \"pos_start\", \"pos_end\"),\n", - " how=\"inner\",\n", - ").count()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d480fbb838b5a255", - "metadata": {}, - "outputs": [], - "source": [ - "%%bash\n", - "$SEQUILA_CLI --file queries/7-8.sql" - ] - }, - { - "cell_type": "markdown", - "id": "958f97c5c7016f52", - "metadata": {}, - "source": "### pyranges" - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "ab270537110baba2", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T06:44:07.792613Z", - "start_time": "2024-12-16T06:44:07.699735Z" - } - }, - "outputs": [], - "source": [ - "import pyranges as pr\n", - "\n", - "\n", - "def df2pr(df):\n", - " return pr.PyRanges(\n", - " chromosomes=df.contig,\n", - " starts=df.pos_start,\n", - " ends=df.pos_end,\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "920fc6c0e98b23d4", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T06:44:11.731196Z", - "start_time": "2024-12-16T06:44:10.496332Z" - } - }, - "outputs": [], - "source": [ - "df_0_pr = df2pr(df_0)\n", - "df_1_pr = df2pr(df_1)\n", - "df_3_pr = df2pr(df_3)\n", - "df_7_pr = df2pr(df_7)\n", - "df_8_pr = df2pr(df_8)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d5514b11e4315a18", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f57a68d0ca3e6894", - "metadata": {}, - "outputs": [], - "source": [ - "len(df_0_pr.join(df_1_pr))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "61d44780f5eed493", - "metadata": {}, - "outputs": [], - "source": [ - "len(df_0_pr.join(df_3_pr))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3bad2681af94f295", - "metadata": {}, - "outputs": [], - "source": [ - "len(df_0_pr.join(df_8_pr))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "673b2468c4418264", - "metadata": {}, - "outputs": [], - "source": [ - "len(df_7_pr.join(df_8_pr))" - ] - }, - { - "cell_type": "markdown", - "id": "1eb620562954f9c3", - "metadata": {}, - "source": "### pybedtools" - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8838e8e4ff90fc0f", - "metadata": {}, - "outputs": [], - "source": [ - "import pybedtools" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "998842945f3e529a", - "metadata": {}, - "outputs": [], - "source": [ - "df_0_bed = pybedtools.BedTool.from_dataframe(df_0)\n", - "df_1_bed = pybedtools.BedTool.from_dataframe(df_1)\n", - "df_3_bed = pybedtools.BedTool.from_dataframe(df_3)\n", - "df_7_bed = pybedtools.BedTool.from_dataframe(df_7)\n", - "df_8_bed = pybedtools.BedTool.from_dataframe(df_8)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "78ca9b3a2e476162", - "metadata": {}, - "outputs": [], - "source": [ - "df_0_bed.intersect(df_1_bed).count()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "45f3fa54c1ac185d", - "metadata": {}, - "outputs": [], - "source": [ - "df_0_bed.intersect(df_3_bed).count()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e04aee9aa177d52c", - "metadata": {}, - "outputs": [], - "source": [ - "df_0_bed.intersect(df_8_bed).count()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "af842070d00c48db", - "metadata": {}, - "outputs": [], - "source": [ - "df_7_bed.intersect(df_8_bed).count()" - ] - }, - { - "cell_type": "markdown", - "id": "7808a7e53de88910", - "metadata": {}, - "source": "### pygenomics" - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3438785aa2066da2", - "metadata": {}, - "outputs": [], - "source": [ - "from pygenomics.interval import GenomicBase\n", - "import itertools" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "23807573c7e55fc1", - "metadata": {}, - "outputs": [], - "source": [ - "df_0_pg = GenomicBase([(r.contig, r.pos_start, r.pos_end) for r in df_0.itertuples()])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d7fe544b1190fbd", - "metadata": {}, - "outputs": [], - "source": [ - "df_1_pg = GenomicBase([(r.contig, r.pos_start, r.pos_end) for r in df_1.itertuples()])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3401359170ce0752", - "metadata": {}, - "outputs": [], - "source": [ - "df_7_pg = GenomicBase([(r.contig, r.pos_start, r.pos_end) for r in df_7.itertuples()])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "787ca4a4c8162110", - "metadata": {}, - "outputs": [], - "source": [ - "df_1_a = df_1.values.tolist()\n", - "df_3_a = df_3.values.tolist()\n", - "df_8_a = df_8.values.tolist()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7dc826a7e22d234c", - "metadata": {}, - "outputs": [], - "source": [ - "df_1_a[1]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "22d742fe4f7a5581", - "metadata": {}, - "outputs": [], - "source": [ - "len(\n", - " list(\n", - " itertools.chain.from_iterable(\n", - " [df_0_pg.find_all((r[0], r[1], r[2])) for r in df_1_a]\n", - " )\n", - " )\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6b776729965815f2", - "metadata": {}, - "outputs": [], - "source": [ - "# slower than array\n", - "# len(list(itertools.chain.from_iterable([df_0_pg.find_all((r.contig, r.pos_start, r.pos_end)) for r in df_3.itertuples()])))\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2c1e2dd48f2406e1", - "metadata": {}, - "outputs": [], - "source": [ - "len(\n", - " list(\n", - " itertools.chain.from_iterable(\n", - " [df_0_pg.find_all((r[0], r[1], r[2])) for r in df_3_a]\n", - " )\n", - " )\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5f1194dc906f8944", - "metadata": {}, - "outputs": [], - "source": [ - "len(\n", - " list(\n", - " itertools.chain.from_iterable(\n", - " [df_0_pg.find_all((r[0], r[1], r[2])) for r in df_8_a]\n", - " )\n", - " )\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "79a036041cdbc3b3", - "metadata": {}, - "outputs": [], - "source": [ - "len(\n", - " list(\n", - " itertools.chain.from_iterable(\n", - " [\n", - " df_7_pg.find_all((r.contig, r.pos_start, r.pos_end))\n", - " for r in df_8.itertuples()\n", - " ]\n", - " )\n", - " )\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "37203b78de5f8e3b", - "metadata": {}, - "outputs": [], - "source": [ - "len(\n", - " list(\n", - " itertools.chain.from_iterable(\n", - " [df_7_pg.find_all((r[0], r[1], r[2])) for r in df_8_a]\n", - " )\n", - " )\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9d637ac58bcbc60e", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "id": "2d7c7ab26897912", - "metadata": {}, - "source": "" - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "f77062ce640cc526", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-15T13:21:32.204321Z", - "start_time": "2024-12-15T13:21:32.197916Z" - } - }, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "\n", - "\n", - "def plot_metrics(metrics, labels, title):\n", - " x = np.arange(len(labels)) # the label locations\n", - " width = 0.10 # the width of the bars\n", - " fig, ax = plt.subplots()\n", - " k = 0\n", - " for m in metrics:\n", - " ax.bar(\n", - " x + width * k,\n", - " [\n", - " metrics[m][\"0-1\"],\n", - " metrics[m][\"0-3\"],\n", - " metrics[m][\"0-8\"],\n", - " metrics[m][\"7-8\"],\n", - " ],\n", - " width,\n", - " label=m,\n", - " )\n", - " k += 1\n", - " ax.set_xticks(x)\n", - " ax.set_xticklabels(labels)\n", - " ax.set_ylabel(\"Time [s]\")\n", - " ax.set_title(title)\n", - " ax.legend(loc=\"upper center\", bbox_to_anchor=(0.5, -0.05), shadow=True, ncol=4)\n", - " ax.grid(True)\n", - " fig.set_size_inches(10, 5)\n", - " plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "75aba28753e4572c", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-15T13:21:33.478961Z", - "start_time": "2024-12-15T13:21:33.400773Z" - } - }, - "outputs": [ - { - "data": { - "image/png": "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Dipbtqz69++vl19+OVu/D3Xnwx7s7e3l7++v7t27a/r06XJycspZ8FlYuXKlnn766bu2OXfunMqVK2eV7cF6uLIF5KKiRYuqRIkSuR0GcN9s9YPojo6O8vX1LVRPrMqJCxcuKDk5WR06dJCfn59cXV1zO6R8o23btoqJiVFMTIx27typIkWKqGPHjpJuf1D29fXN0Q+wnj17Vn5+fmrcuHGW69rqfQLrSc+LM2fOaMyYMYqIiNCsWbOyvf6KFSsUExOjc+fO6e2339bq1av12muvWS2+Xr16mfM2JiZGISEhGjhwoMW8gIAAq20P1kOxhXznk08+UY0aNeTi4qISJUqodevWSkhIkCS99957qlq1qpydnfXQQw/p7bfftlj38OHDql27tpydnVWvXj1t3LjxnsM+0ofvbNu2TVWrVlXRokXNJ+V033zzjdq0aaOSJUvK09NTzZs313fffWdenv5N0+OPPy6TyWSevnMY4fbt2+Xs7Jzh2/MXXnhBjz76f9/gfvXVV2ratKlcXFwUEBCgESNGmPcfhUuLFi00bNgwDRs2TJ6enipZsqQmTpxoHqJx7do19e/fX8WLF5erq6vatWunM2fOZNnf2bNn1blzZ/n4+Kho0aKqX7++duzYYdGmXLlymjZtmvr37y8PDw8999xzunXrloYNGyY/Pz85OzsrMDBQ06dPv2f8P/74oxo3bixnZ2c9/PDD2rt3r3lZZsMIP/30U1WvXl1OTk4qV66c5syZk61jNGLECL344ovy8vKSr6+vIiIiLNrMnTtXNWrUkJubmwICAjRkyBDz/QR79uzR008/rRs3bshkMslkMmVY/04mk0lLlixRu3bt5OLiogoVKuiTTz65Z5z/tHLlSpUtW1aurq56/PHHdeXKFYtlNWrcvupaoUIFmUwmnT9/PsfbKKycnJzk6+srX19f1apVSy+99JJ+/fVX/fHHH5kOI9y7d68aNGggJycn+fn56aWXXlJKSoqk21dEhg8frgsXLlic29PfmyNHjlTJkiUVFhYm6e65Jv3f/zebN29WUFCQXF1d1b17dyUmJmrVqlUqV66cihcvrhEjRig1NdW8XlJSksaOHavSpUvLzc1NDRs21J49e2x+LAuS9LwIDAzU4MGD1bp1a3300Ufy8PDI8B7etGmT3NzcdPPmTfO8YsWKydfXVwEBAerYsaM6d+5s8TlAkj777DPVqVNHzs7OqlChgqZMmWLOJUk6c+aMmjVrJmdnZ1WrVk2RkZHmZS4uLua89fX1laOjo1xdXc3Tt27dUteuXVW0aFF5eHioZ8+eunTpksX2lyxZoooVK8rR0VFBQUFavXp1lsfjfs/ryIhiC/lKTEyM+vTpo2eeeUanTp3Snj171LVrVxmGoTVr1mjSpEl6/fXXderUKb3xxhuaOHGieWhAfHy8OnbsqGrVqunIkSOKiIjQ2LFjs7XdxMREzZ49W6tXr9a+fft04cIFi3Vv3ryp8PBwffXVVzp48KAqV66s9u3bm0/E33zzjaT/++YrffpOrVq1UrFixfTpp5+a56Wmpmr9+vXq27evpNsfhtu2batu3brp2LFjWr9+vb766isNGzbs/g4o8r1Vq1apSJEiOnz4sObPn6+5c+fqvffek3T7g+C3336rzz//XFFRUTIMQ+3bt8/yKVDx8fFq3769du7cqaNHj6pt27bq1KmTLly4YNFu9uzZqlmzpo4ePaqJEydqwYIF+vzzz/XRRx/p9OnTWrNmTbaGsowbN05jxozR0aNHFRISok6dOlkUFXc6cuSIevbsqd69e+v48eOKiIjQxIkTtXLlymwdIzc3Nx06dEgzZ87U1KlTLT7E2NnZacGCBTpx4oRWrVqlXbt26cUXX5R0ezjjW2+9JQ8PD/O3x/c6b0ycOFHdunXT999/r759+6p37946derUPeNMd+jQIQ0YMEDDhg1TdHS0WrZsafENea9evcxF8OHDh/lG+1+Ij4/Xhx9+qEqVKmU6yuD3339X+/btVb9+fX3//fdasmSJli9fbn495s+fr6lTp6pMmTIZzu2rVq2So6OjDhw4oHfeeUfS3XMtXWJiohYsWKB169Zp69at2rNnjx5//HFt2bJFW7Zs0erVq7V06VKLAmDYsGGKiorSunXrdOzYMfXo0UNt27a965cruDsXFxfZ2dmpd+/eWrFihcWyFStWqHv37nJ3d8903Z9++km7du1Sw4YNzfP279+v/v3764UXXtDJkye1dOlSrVy5Uq+//rqk2z/+27VrVzk6OurQoUN65513NH78+GzFmpaWps6dO+vq1avau3evIiMj9b///U+9evUyt9m4caNeeOEFjRkzRj/88IOef/55Pf3009q9e3emfd7veR0Zcc8W8pWYmBilpKSoa9eu5l8hT/+Gd/LkyZozZ466du0qSSpfvrz5hBYeHq61a9cqLS1Ny5cvl7Ozs6pXr67ffvtNgwcPvud2k5OT9c4776hixYqSbv/HNnXqVPPyO688SbdvXC9WrJj27t2rjh07qlSpUpL+75uvzNjb26t3795au3atBgwYIEnauXOnrl+/rm7dukmSpk+frr59+2rkyJGSpMqVK2vBggVq3ry5lixZImdn52wdRxQcAQEBmjdvnkwmk4KCgnT8+HHNmzdPLVq00Oeff64DBw6ocePGkqQ1a9YoICBAmzZtUo8ePTL0VbNmTdWsWdM8PW3aNG3cuFGff/65RUH/6KOPasyYMebpCxcuqHLlymrSpIlMJpP5vXkvw4YNM+f2kiVLtHXrVi1fvjzDh0/p9hWBVq1aaeLEiZKkKlWq6OTJk5o1a5aeeuqpu24nODhYkydPlnT7PbNo0SLt3LlTbdq0kSTz+0m6feXutdde06BBg/T222/L0dFRnp6eMplM2f4B+B49eujZZ5+VdPsYRkZGauHChRmutGdl/vz5atu2rfk4VKlSRV9//bW2bt0qSear+pJUqlQpfpg+hzZv3mz+zZ+EhAT5+flp8+bNmf4Uyttvv62AgAAtWrRIJpNJDz30kC5evKjx48dr0qRJ8vT0lLu7u3n44Z0qV66smTNnWsy7W66lS05ONl+BkKTu3btr9erVunTpkooWLapq1aqpZcuW2r17t3r16qULFy5oxYoVunDhgvz9/SXdvh9469atWrFihd544w2rHLfCwjAM7dy5U9u2bdPw4cPVo0cP8z2kfn5+unz5srZs2ZLhqn+fPn1kb2+vlJQUJSUlqWPHjpowYYJ5+ZQpU/TSSy8pPDxc0u2r0tOmTdOLL76oyZMna8eOHfrxxx+1bds28+v4xhtvqF27dveMeefOnTp+/LjOnTtn/uLlgw8+UPXq1fXNN9+ofv36mj17tp566ikNGTJEkjR69GgdPHhQs2fPVsuWLTP0eb/ndWTElS3kKzVr1lSrVq1Uo0YN9ejRQ++++66uXbumhIQEnT17VgMGDFDRokXNf6+99prOnj0rSTp16pSCg4MtCpKQkBCL/qtXr25e984TnKurq/k/PknmE266S5cuaeDAgapcubI8PT3l4eGh+Pj4DFcE7qVv377as2ePLl68KOn2h+MOHTqYn0L2/fffa+XKlRb7GBYWprS0NJ07dy5H20LB0KhRI4v7mkJCQnTmzBmdPHlSRYoUsfhmtUSJEgoKCsryKkt8fLzGjh2rqlWrqlixYipatKhOnTqVIY/r1atnMf3UU08pOjpaQUFBGjFihLZv325eNmjQIIt8vdOd778iRYqoXr16WcZ26tQpPfLIIxbzHnnkEZ05c0apqanav3+/xXbWrFljbhccHGyx3j/fvzt27FCrVq1UunRpubu7q1+/frpy5YoSExMzjUW6/SHozu3deYz+eV4JCQnJcr8yO+ecOnXK4nXLrE/cv5YtWyo6OlrR0dE6fPiwwsLC1K5dO/3yyy8Z2p46dUohISEW77FHHnlE8fHx+u233+66nbp162aYl51c++f/Nz4+PipXrpzF+8fHx8ecw8ePH1dqaqqqVKlikZN79+41//+He0svwp2dndWuXTv16tVLERERatCggapXr24eJfPhhx8qMDBQzZo1s1h/3rx5io6O1vfff6/Nmzfrp59+Ur9+/czLv//+e02dOtXiNUq/5yoxMVGnTp1SQECAudCSsv++T1/3zivc1apVU7FixcznnqzOoVmdm+52XkfOcGUL+Yq9vb0iIyP19ddfa/v27Vq4cKFeeeUV/fe//5Ukvfvuuxk+pNjb22e7/y1btpiHWLm4uJjnOzg4WLQzmUwWjy4NDw/XlStXNH/+fAUGBsrJyUkhISE5vim6fv36qlixotatW6fBgwdr48aNFsOk4uPj9fzzz2vEiBEZ1i1btmyOtgX809ixYxUZGanZs2erUqVKcnFxUffu3TPksZubm8V0nTp1dO7cOX355ZfasWOHevbsqdatW+uTTz7R1KlTsz1c99+oV6+exX02Pj4+5n9n9v5NS0uTdPtR3x07dtTgwYP1+uuvy8vLS1999ZUGDBigW7duZfngiUGDBqlnz57m6Ts/IOVEVucc2I6bm5sqVapknn7vvffk6empd99913xF0lrbuVN2cy2zfL1bDsfHx8ve3l5HjhzJ8P/dP7/gQNZatmypJUuWyNHRUf7+/hYPOnn22We1ePFivfTSS1qxYoWefvrpDA/v8fX1NedVUFCQbt68qT59+ui1115TpUqVFB8frylTpphH39wpL45Kudt5HTlDsYV8x2Qy6ZFHHtEjjzyiSZMmKTAwUAcOHJC/v7/+97//me9v+qeqVatq9erV+vvvv80ntoMHD1q0ud/L5AcOHNDbb7+t9u3bS5J+/fVX/fnnnxZtHBwcLG5ozkrfvn21Zs0alSlTRnZ2durQ4f8ej1+nTh2dPHnS4oMCCrdDhw5ZTKffM1itWjWlpKTo0KFD5mGEV65c0enTp1WtWrVM+zpw4ICeeuopPf7445Juf4jL7oMXPDw81KtXL/Xq1Uvdu3dX27ZtdfXqVXl7e8vb2zvTdQ4ePGj+djglJUVHjhzJ8v7DqlWr6sCBAxnirVKliuzt7eXi4nJf74sjR44oLS1Nc+bMMQ8j++ijjyzaODo6Znjvenl5ycvLK8v96t+/v8V07dq1M22b2TmnatWqmb6usA2TySQ7Ozv99ddfGZZVrVpVn376qQzDMH+4PnDggNzd3VWmTJkcbSc7uXY/ateurdTUVF2+fFlNm+bskef4P/8swu/05JNP6sUXX9SCBQt08uRJ81DAu0kvfNPzqk6dOjp9+nSW26hatap+/fVX83BFKfvv+/R1f/31V/PVrZMnT+r69evm8336OfTO2A8cOJDl/wdS1uf1rM59yBzFFvKVQ4cOaefOnQoNDZW3t7cOHTqkP/74Q1WrVtWUKVM0YsQIeXp6qm3btkpKStK3336ra9euafTo0XriiSf0yiuvaODAgZowYYLOnz+v2bNnWyWuypUra/Xq1apXr57i4uI0bty4DN9SlytXTjt37tQjjzwiJycnFS9ePNO++vbtq4iICL3++uvq3r27xW90jB8/Xo0aNdKwYcP07LPPys3NTSdPnlRkZKQWLVpklX1B/nLhwgWNHj1azz//vL777jstXLhQc+bMUeXKldW5c2cNHDhQS5culbu7u1566SWVLl1anTt3zrSvypUra8OGDerUqZNMJpMmTpxo/vb8bubOnSs/Pz/Vrl1bdnZ2+vjjj+Xr63vPH0xevHixKleurKpVq2revHm6du2annnmmUzbjhkzRvXr19e0adPUq1cvRUVFadGiRdm+DyorlSpVUnJyshYuXKhOnTpZPMwgXbly5RQfH6+dO3eqZs2acnV1veuj1j/++GPVq1dPTZo00Zo1a3T48GEtX7482zGNGDFCjzzyiGbPnq3OnTtr27Zt5vu18O8lJSUpNjZW0u0ndi5atEjx8fHq1KlThrZDhgzRW2+9peHDh2vYsGE6ffq0Jk+erNGjR2d6j9fdZCfX7keVKlXUt29f9e/fX3PmzFHt2rX1xx9/aOfOnQoODrb4wg73p3jx4uratavGjRun0NDQTAvt69evKzY2VmlpaTpz5oymTp2qKlWqqGrVqpKkSZMmqWPHjipbtqy6d+8uOzs7ff/99/rhhx/02muvqXXr1qpSpYrCw8M1a9YsxcXF6ZVXXslWfK1bt1aNGjXUt29fvfXWW0pJSdGQIUPUvHlz87DvcePGqWfPnqpdu7Zat26t//73v9qwYUOGe8/S3e95HRlxzxbyFQ8PD+3bt0/t27dXlSpV9Oqrr2rOnDlq166dnn32Wb333ntasWKFatSooebNm2vlypUqX768pNvDKf773//q+PHjql27tl555RW9+eabVolr+fLlunbtmurUqaN+/fppxIgRGb7NnzNnjiIjIxUQEJDlt9zS7f+QGzRooGPHjmW4ShccHKy9e/fqp59+UtOmTVW7dm1NmjTpvocwIf/r37+//vrrLzVo0EBDhw7VCy+8oOeee07S7Sdm1a1bVx07dlRISIgMw9CWLVsyDElKN3fuXBUvXlyNGzdWp06dFBYWpjp16twzBnd3d82cOVP16tVT/fr1df78eW3ZsuWeH0ZnzJihGTNmqGbNmvrqq6/0+eefZ/mDsHXq1NFHH32kdevW6eGHH9akSZM0derUez4c415q1qypuXPn6s0339TDDz+sNWvWZHi8cePGjTVo0CD16tVLpUqVyvDQg3+aMmWK1q1bp+DgYH3wwQf6z3/+c9dvj/+pUaNGevfddzV//nzVrFlT27dv16uvvnpf+4eMtm7dKj8/P/n5+alhw4b65ptv9PHHH6tFixYZ2pYuXVpbtmzR4cOHVbNmTQ0aNEgDBgy4r9cjO7l2v1asWKH+/ftrzJgxCgoKUpcuXfTNN98wvNyK0od7ZvWF0NNPPy0/Pz+VKVNGffr0UfXq1fXll1+ahyOGhYVp8+bN2r59u+rXr69GjRpp3rx55qvbdnZ22rhxo/l8/uyzz5qfVHgvJpNJn332mYoXL65mzZqpdevWqlChgtavX29u06VLF82fP1+zZ89W9erVtXTpUq1YsSLTvJfu/7yOjEzGnTeeoNBIvxmzatWqhfrHMM+fP6/y5cvr6NGj5t+7AvKLFi1aqFatWnrrrbdyOxT8fyaTSRs3blSXLl1yOxQAVrR69WqNGjVKFy9elKOjY26Hk++kf+48ffq0Ll++rPDw8CxH+BQ0DCMEAAAAMpGYmKiYmBjNmDFDzz//PIUWcoxrgQAAAEAmZs6cqYceeki+vr4Wv5sFZBfDCAsphhECAADgQSjMwwi5sgUAAAAANkCxBQAAAAA2QLEFAAAAADZAsQUAAAAANkCxBQAAAAA2QLEFAAAAADZAsYVCZ+XKlSpWrNgD3+758+dlMpkUHR2dZZs9e/bIZDLp+vXrDyyuByE7+57Z67Js2TIFBATIzs5Ob731lk1jLIx4L+QN2TkemeE9A8Ba7vc8hHsrktsBIA+K8HyA27rx4LaVDzRu3FgxMTHy9HyAr0EWVq5cqZEjR+bah924uDgNGzZMc+fOVbdu3XLlmJx6qOoD21bVH089sG3lB7wXci633zNzenV8oNsbs35zjtd56qmntGrVKkmSg4ODypYtq/79++vll19WkSL3/khkMpnM/3Z3d1dQUJBeffVVde7cOcexFCYRERF5env/Ni8kaffu3ZozZ44OHTqkmzdvqnTp0qpXr56GDh2qZs2a5XQXHriAgADFxMSoZMmSuR1KgcOVLeA+3Lp1yyb9Ojo6ytfX1+I/9MLqwoULSk5OVocOHeTn58ePb+dRvBfyDt4z2dO2bVvFxMTozJkzGjNmjCIiIjRr1qxsr79ixQrFxMTo22+/1SOPPKLu3bvr+PHjNowYD8K/yYu3335brVq1UokSJbR+/XqdPn1aGzduVOPGjTVq1CgbR24d9vb28vX1zXZxieyj2EK+06JFCw0bNkzDhg2Tp6enSpYsqYkTJ8owDEnStWvX1L9/fxUvXlyurq5q166dzpw5k2V/Z8+eVefOneXj46OiRYuqfv362rFjh0WbcuXKadq0aerfv788PDz03HPP6datWxo2bJj8/Pzk7OyswMBATZ8+/Z7x//jjj2rcuLGcnZ318MMPa+/eveZlmQ2d+vTTT1W9enU5OTmpXLlymjNnTraO0YgRI/Tiiy/Ky8tLvr6+Gb7pmzt3rmrUqCE3NzcFBARoyJAhio+PN8fx9NNP68aNGzKZTDKZTHf9ptBkMmnJkiVq166dXFxcVKFCBX3yySf3jDMrK1euVI0aNSRJFSpUkMlk0vnz5++7v4KK90L+fC8cPnxYtWvXlrOzs+rVq6ejR4/ecz+k2++LsmXLytXVVY8//riuXLlisYz3TPY4OTnJ19dXgYGBGjx4sFq3bq2PPvpIHh4eGV6rTZs2yc3NTTdv3jTPK1asmHx9fVWlShVNmzZNKSkp2r17t3n51q1b1aRJExUrVkwlSpRQx44ddfbsWfPy9OFaGzZsUMuWLeXq6qqaNWsqKirKYtvvvvuuAgICzK/33LlzMwwb/eyzz1SnTh05OzurQoUKmjJlilJSUiRJhmEoIiJCZcuWlZOTk/z9/TVixAhrHcYC537z4sKFCxo5cqRGjhypVatW6dFHH1VgYKCCg4P1wgsv6Ntvv7VY96uvvlLTpk3l4uKigIAAjRgxQgkJCebl5cqV0xtvvKFnnnlG7u7uKlu2rJYtW2bRx/Hjx/Xoo4/KxcVFJUqU0HPPPWc+Z0m3r9R16dJFb7zxhnx8fFSsWDFNnTpVKSkpGjdunLy8vFSmTBmtWLHCvE5mwwhPnDihjh07ysPDQ+7u7mratKk5l/fs2aMGDRrIzc1NxYoV0yOPPKJffvnlX78OBRHFFvKlVatWqUiRIjp8+LDmz5+vuXPn6r333pN0+yTz7bff6vPPP1dUVJQMw1D79u2VnJycaV/x8fFq3769du7cqaNHj6pt27bq1KmTLly4YNFu9uzZqlmzpo4ePaqJEydqwYIF+vzzz/XRRx/p9OnTWrNmjcqVK3fP2MeNG6cxY8bo6NGjCgkJUadOnSw+NN3pyJEj6tmzp3r37q3jx48rIiJCEydO1MqVK7N1jNzc3HTo0CHNnDlTU6dOVWRkpHm5nZ2dFixYoBMnTmjVqlXatWuXXnzxRUm3h3C99dZb8vDwUExMjGJiYjR27Ni7bm/ixInq1q2bvv/+e/Xt21e9e/fWqVP3NzSuV69e5g/5hw8fVkxMjAICAu6rr4KO98LKbB2jvPJeiI+PV8eOHVWtWjUdOXJEERER9+xPkg4dOqQBAwZo2LBhio6OVsuWLfXaa6+Zl/OeuX8uLi6ys7NT7969LT58SrevYnXv3l3u7u4Z1ktJSdHy5csl3b4Smy4hIUGjR4/Wt99+q507d8rOzk6PP/640tLSLNZ/5ZVXNHbsWEVHR6tKlSrq06ePuVA6cOCABg0apBdeeEHR0dFq06aNXn/9dYv19+/fr/79++uFF17QyZMntXTpUq1cudLc7tNPP9W8efO0dOlSnTlzRps2bTIX5Li37ObFp59+quTkZPM545/uvDp/9uxZtW3bVt26ddOxY8e0fv16ffXVVxo2bJjFOnPmzDF/ETNkyBANHjxYp0+flnQ7v8LCwlS8eHF98803+vjjj7Vjx44MfezatUsXL17Uvn37NHfuXE2ePFkdO3ZU8eLFdejQIQ0aNEjPP/+8fvvtt0zj/v3339WsWTM5OTlp165dOnLkiJ555hmlpKQoJSVFXbp0UfPmzXXs2DFFRUXpueeeYyRCFrhWiHwpICBA8+bNk8lkUlBQkI4fP6558+apRYsW+vzzz3XgwAE1btxYkrRmzRoFBARo06ZN6tGjR4a+atasqZo1a5qnp02bpo0bN+rzzz+3OHk9+uijGjNmjHn6woULqly5spo0aSKTyaTAwMBsxT5s2DB169ZNkrRkyRJt3bpVy5cvz/REPXfuXLVq1UoTJ06UJFWpUkUnT57UrFmz9NRTT911O8HBwZo8ebIkqXLlylq0aJF27typNm3aSJJGjhxpbluuXDm99tprGjRokN5++205OjrK09NTJpNJvr6+2dqvHj166Nlnn5V0+xhGRkZq4cKFevvtt7O1/p3Sv62TpFKlSmU7hsKI90L+ei+sXbtWaWlpWr58uZydnVW9enX99ttvGjx48F37nD9/vtq2bWs+NlWqVNHXX3+trVu3SuI9cz8Mw9DOnTu1bds2DR8+XD169DDfK+jn56fLly9ry5YtGa7u9unTR/b29vrrr7+UlpamcuXKqWfPnubl6Tmd7v3331epUqV08uRJPfzww+b5Y8eOVYcOHSRJU6ZMUfXq1fXzzz/roYce0sKFC9WuXTtzIZ7+em/e/H/3qU2ZMkUvvfSSwsPDJd2+ojlt2jS9+OKLmjx5si5cuCBfX1+1bt3afB9SgwYNrHsQC6Cc5sVPP/0kDw8Pi/fcp59+an5dJCkqKko1atTQ9OnT1bdvX/M5p3LlylqwYIGaN2+uJUuWyNnZWZLUvn17DRkyRJI0fvx4zZs3T7t371ZQUJDWrl2rv//+Wx988IHc3NwkSYsWLVKnTp305ptvysfHR5Lk5eWlBQsWyM7OTkFBQZo5c6YSExP18ssvS5ImTJigGTNm6KuvvlLv3r0zHIfFixfL09NT69atk4ODg6TbeShJV69e1Y0bN9SxY0dVrFhRklS16oO7xzm/4coW8qVGjRpZfIMSEhKiM2fO6OTJkypSpIgaNmxoXlaiRAkFBQVleZUlPj5eY8eOVdWqVVWsWDEVLVpUp06dyvBtfr169Symn3rqKUVHRysoKEgjRozQ9u3bzcsGDRqkokWLmv/uFBISYv53kSJFVK9evSxjO3XqlB555BGLeY888ojOnDmj1NRU7d+/32I7a9asMbcLDg62WC/9P4l0O3bsUKtWrVS6dGm5u7urX79+unLlihITEzONRZLeeOMNi+3deYzu3K/06az2q3r16uY+2rVrl+X2cG+8F/LXe+HUqVMKDg42f6jKrH1m749Tp05ZvJaZrYfs2bx5s4oWLSpnZ2e1a9dOvXr1UkREhBo0aKDq1aubH5Tw4YcfKjAwMMPDDebNm6fo6Gh9+eWXqlatmt577z15eXmZl585c0Z9+vRRhQoV5OHhYb7K+8/30Z156efnJ0nmvDx9+nSGwuif099//72mTp1qkYcDBw5UTEyMEhMT1aNHD/3111+qUKGCBg4cqI0bN5qvnCGjf5MX/7yiExYWpujoaH3xxRdKSEhQamqqpNuv2cqVKy1es7CwMKWlpencuXPm9e/MjfQvetJz49SpU6pZs6a50JJunwvT0tLMV7+k2+cRO7v/+5jv4+NjcWXT3t5eJUqUsDgX3ik6OlpNmzY1F1p38vLy0lNPPaWwsDB16tRJ8+fPV0xMzF2ObuHGlS0UemPHjlVkZKRmz56tSpUqycXFRd27d89w4/+dJzZJqlOnjs6dO6cvv/xSO3bsUM+ePdW6dWt98sknmjp1araGBv1b9erVsxhfnf6NlqQMJ0iTyWQexnL+/Hl17NhRgwcP1uuvvy4vLy999dVXGjBggG7dupXljfWDBg2y+AbX39//vuLesmWLeSibi4vLffUB6+O98ODfC5nh/WFbLVu21JIlS+To6Ch/f3+LBwI8++yzWrx4sV566SWtWLFCTz/9dIYP0r6+vqpUqZIqVaqkFStWqH379jp58qS8vb0lSZ06dVJgYKDeffdd+fv7Ky0tTQ8//HCG99GdeZm+jX8ONbyb+Ph4TZkyRV27ds2wzNnZWQEBATp9+rR27NihyMhIDRkyRLNmzdLevXsz/QBd2N1vXlSuXFk3btxQbGys+epW0aJFValSpQwPm4iPj9fzzz+f6b1zZcuWNf/7bues7Mqsj5z0e69zz4oVKzRixAht3bpV69ev16uvvqrIyEg1atQoR3EWBhRbyJcOHTpkMX3w4EFVrlxZ1apVU0pKig4dOmQeOnXlyhWdPn1a1apVy7SvAwcO6KmnntLjjz8u6fbJMLs3lnt4eKhXr17q1auXunfvrrZt2+rq1avy9vY2/8f7TwcPHjR/I5aSkqIjR45kGGudrmrVqjpw4ECGeKtUqSJ7e3u5uLioUqVK2Yr1TkeOHFFaWprmzJlj/ubro48+smjj6Oho/jYunZeXl8U3uP/cr/79+1tM165dO9O22R1mhnvjvZC/3gtVq1bV6tWr9ffff5uvbh08eNBi/czeH1WrVs30tUbOubm5ZZkrTz75pF588UUtWLBAJ0+etBgKlpkGDRqobt26ev311zV//nzze+zdd99V06ZNJd1+IEJOBQUF6ZtvvrGY98/pOnXq6PTp03fNexcXF3Xq1EmdOnXS0KFD9dBDD+n48eOqU6dOjmMq6O43L7p3766XXnpJb775pubNm3fXbdSpU0cnT568r3NVuqpVq2rlypVKSEgwf/F14MAB83BBawkODtaqVauUnJycZXFeu3Zt1a5dWxMmTFBISIjWrl1LsZUJhhEiX7pw4YJGjx6t06dP6z//+Y8WLlyoF154QZUrV1bnzp01cOBAffXVV/r+++/15JNPqnTp0ln+DkrlypW1YcMGRUdH6/vvv9cTTzyRrW+Q5s6dq//85z/68ccf9dNPP+njjz+Wr6/vPX8kdvHixdq4caN+/PFHDR06VNeuXdMzzzyTadsxY8Zo586dmjZtmn766SetWrVKixYt+tdXCipVqqTk5GQtXLhQ//vf/7R69Wq98847Fm3KlSun+Ph47dy5U3/++eddh1RJ0scff6z3339fP/30kyZPnqzDhw9n+cEZ1sN7IX+9F5544gmZTCYNHDhQJ0+e1JYtWzR79ux7xpn+DfLs2bN15swZLVq0yHy/FqynePHi6tq1q8aNG6fQ0FCVKVPmnuuMHDlSS5cu1e+//67ixYurRIkSWrZsmX7++Wft2rVLo0ePznEcw4cP15YtWzR37lydOXNGS5cu1ZdffmlxlW3SpEn64IMPNGXKFJ04cUKnTp3SunXr9Oqrr0q6/YTK5cuX64cfftD//vc/ffjhh3JxceHLrvtwt7woW7as5syZo/nz5ys8PFy7d+/W+fPn9d1332nBggWSbg/Zk27ff/X111+bH3Rz5swZffbZZzn6v7Jv375ydnZWeHi4fvjhB+3evVvDhw9Xv379LK7o/1vDhg1TXFycevfurW+//VZnzpzR6tWrdfr0aZ07d04TJkxQVFSUfvnlF23fvl1nzpzhvq2sGCiUEhISjG+//dZISEjI7VByrHnz5saQIUOMQYMGGR4eHkbx4sWNl19+2UhLSzMMwzCuXr1q9OvXz/D09DRcXFyMsLAw46effjKvv2LFCsPT09M8fe7cOaNly5aGi4uLERAQYCxatMho3ry58cILL5jbBAYGGvPmzbOIY9myZUatWrUMNzc3w8PDw2jVqpXx3XffZRn3uXPnDEnG2rVrjQYNGhiOjo5GtWrVjF27dpnb7N6925BkXLt2zTzvk08+MapVq2Y4ODgYZcuWNWbNmpWtY3Rn/IZhGJ07dzbCw8PN03PnzjX8/PzMx+iDDz7IsO1BgwYZJUqUMCQZkydPznJ7kozFixcbbdq0MZycnIxy5coZ69evz7DvR48ezbKPf74uR48eNSQZ586du+f+Fla8F/Lfe8EwDCMqKsqoWbOm4ejoaNSqVcv49NNP7/n+MAzDWL58uVGmTBnDxcXF6NSpkzF79mzeMzkUHh5udO7c+a5tdu7caUgyPvroowzLJBkbN260mJeWlmY89NBDxuDBgw3DMIzIyEijatWqhpOTkxEcHGzs2bPHYr3MzofXrl0zJBm7d+82z1u2bJlRunRpw8XFxejSpYvx2muvGb6+vhbb3rp1q9G4cWPDxcXF8PDwMBo0aGAsW7bMMAzD2Lhxo9GwYUPDw8PDcHNzMxo1amTs2LEjeweqkPm3eWEYt1/3du3aGV5eXkaRIkUMHx8fo0uXLsbWrVst2h0+fNho06aNUbRoUcPNzc0IDg42Xn/9dfPyzM6xNWvWtDjvHDt2zGjZsqXh7OxseHl5GQMHDjRu3rx51/3J7Fx457Yyy8vvv//eCA0NNVxdXQ13d3ejadOmxtmzZ43Y2FijS5cuhp+fn+Ho6GgEBgYakyZNMlJTU7M8fumfO9esWWPMmzfPuHr1apZtCxqTYfz/H2RBoZKYmKhTp06patWq+e6HL1u0aKFatWrprbfeyu1Q8P+ZTCZt3LhRXbp0ye1QChXeC3kP74X8b/Xq1Ro1apQuXrxo8Uj33DZw4ED9+OOP2r9/f26HUijl1bzIL9I/d54+fVqXL19WeHi4ihcvntthPRDcswUAAAq9xMRExcTEaMaMGXr++edz/QP17Nmz1aZNG7m5uenLL7/UqlWr7uunNPDv5LW8QP7DPVsAAKDQmzlzph566CH5+vpqwoQJuR2ODh8+rDZt2qhGjRp65513tGDBAvPvt+HByWt5gfyHYYSFVH4eRggAAID8ozAPI+TKFgAAAADYAMVWIZfTH8kDAAAAciL982ZhHFBHsVVIpd/gGR8fn8uRAAAAoCBL/7yZnJycy5E8eDyNsJAqUqSISpYsqd9//12SVLRoUdnZUXsDAADAOtLS0hQfH6/ff/9d169fV0pKSm6H9MBRbBViZcuWlSRzwQUAAABY2/Xr13Xp0iWlpqbK3t5eDg4OuR3SA0OxVYiZTCYFBgbq6tWrioqKkpubm9zc3GQymXI7NAAAABQAycnJSktLU3Jysq5cuaJKlSoVqidh8+h3KC0tTV9//bUOHz6spKQkii0AAABYjWEYMplMqlChgtq1ayd3d/fcDumBodiCpNsF18WLF3Xz5k2eUAgAAACrMZlMcnFxkY+PT6G6qiVRbAEAAACATfD4OQAAAACwAYotAAAAALABii0AAAAAsAGKLQAAAACwAYotAAAAALCB/wecw7pz/5tnEAAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# pygenomic uses ge/lte for comparison - results differ\n", - "\n", - "metrics = {\n", - " \"seq-native\": {\"0-1\": 0.144, \"0-3\": 9.425, \"0-8\": 3.374, \"7-8\": 4.756},\n", - " \"polars-bio-nat-pl-lf\": {\"0-1\": 0.164, \"0-3\": 9.248, \"0-8\": 3.470, \"7-8\": 5.090},\n", - " \"polars-bio-nat-pl-df\": {\"0-1\": 0.145, \"0-3\": 24.668, \"0-8\": 4.210, \"7-8\": 6.698},\n", - " \"polars-bio-nat-pd-df\": {\"0-1\": 0.150, \"0-3\": 41.995, \"0-8\": 6.392, \"7-8\": 10.639},\n", - " \"Bioframe\": {\"0-1\": 0.559, \"0-3\": 196.0, \"0-8\": 21.128, \"7-8\": 41.103},\n", - " \"PyRanges\": {\"0-1\": 0.135, \"0-3\": 92.0, \"0-8\": 10.629, \"7-8\": 19.461},\n", - " \"PyBedTools\": {\"0-1\": 1.512, \"0-3\": 2029.0, \"0-8\": 350.0, \"7-8\": 611.0},\n", - " \"PyGenomics\": {\"0-1\": 1.579, \"0-3\": 487.0, \"0-8\": 153.0, \"7-8\": 193},\n", - "}\n", - "plot_metrics(\n", - " metrics, [\"0-1\", \"0-3\", \"0-8\", \"7-8\"], \"Overlap operation performance comparison\"\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "657a85d9bf76f15c", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-15T13:21:43.351332Z", - "start_time": "2024-12-15T13:21:43.285502Z" - } - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAA2EAAAHeCAYAAAASDwO2AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/GU6VOAAAACXBIWXMAAA9hAAAPYQGoP6dpAABV+ElEQVR4nO3deZyN9f//8eeZ7cwwZhjbWMaMfWuiCCP7koSIUCpDWhRJQ33SJzFaRLbKWh8hJSK0WyKSkETqY82HlGVkGctgZjjv3x/95nwds8+cuc7MeNxvN7ebc53rvK/XdZ3rdc48z3Wd69iMMUYAAAAAAEt4eboAAAAAALiREMIAAAAAwEKEMAAAAACwECEMAAAAACxECAMAAAAACxHCAAAAAMBChDAAAAAAsBAhDAAAAAAsRAgDAAAAAAsRwgA3mjt3rmw2mw4dOuTpUgqN0aNHy2azeboMS2zdulVNmzZV0aJFZbPZtGPHDk+XhAJo3bp1stlsWrdunadLSeXQoUOy2WyaMGGCp0sBAI8ihKFA+u9//6sHH3xQFSpUkN1uV/ny5fXAAw/ov//9r6dLQw5cvHhRo0ePzpd/NFolOTlZPXv21OnTpzV58mTNnz9f4eHhni4LyPd27dql0aNHF+oPvyIiImSz2WSz2eTl5aXixYsrMjJSjz32mLZs2ZKrsV977TUtX748x49PCf1p/bvvvvtyVRtQmPl4ugAgu5YuXar7779fISEhGjBggCpXrqxDhw5p9uzZWrJkiRYuXKh77rnH02UiGy5evKjY2FhJUqtWrVzue/HFF/X88897oCprHThwQH/88YfeffddPfLII54uBwVYixYtdOnSJfn5+Xm6FEvs2rVLsbGxatWqlSIiIjxdTp6pX7++hg0bJkk6f/68du/ercWLF+vdd9/VM888o0mTJuVo3Ndee0333nuvunXrlqv6hgwZottuu81lWmF+PoDcIoShQDlw4IAeeughValSRd99951Kly7tvO/pp59W8+bN9dBDD2nnzp2qUqWKZXUlJCSoaNGili0vv7ty5YocDodb/gj08fGRj0/hfalK2XdOnDghSSpevLjbx8aN4fLly/Lz85OXl5f8/f09XQ7crEKFCnrwwQddpo0bN059+vTR5MmTVb16dT3xxBMeqk5q3ry57r333izN6873CKCg4nREFChvvPGGLl68qHfeecclgElSqVKlNGvWLCUkJGj8+PGSpCVLlshms2n9+vWpxpo1a5ZsNpt+++0357Q9e/bo3nvvVUhIiPz9/dWwYUN99tlnLo9L+d7X+vXr9eSTT6pMmTKqWLFiujV/+umn6tSpk8qXLy+73a6qVavq5Zdf1tWrV13ma9WqlW666SZt27ZNTZs2VUBAgCpXrqyZM2dmadtcuXJFL7/8sqpWrSq73a6IiAi98MILSkxMdJkvIiJCnTt31qpVq1S/fn35+/urTp06Wrp0aaox4+PjNXToUIWFhclut6tatWoaN26cHA6Hc55rv+MxZcoU5/J37dqlpKQkvfTSS2rQoIGCg4NVtGhRNW/eXN9++63L41Oey9jYWOdpLKNHj5aU9nfCsruu33//vRo1aiR/f39VqVJF77//fqbb89r1mjx5ssLDwxUQEKCWLVu67DMpcrPv9OvXTy1btpQk9ezZUzabzeWI4Nq1a9W8eXMVLVpUxYsXV9euXbV7926XsVO2065du9SnTx+VKFFCzZo1c9kO69atU8OGDRUQEKDIyEjn6Z9Lly5VZGSk/P391aBBA23fvt1l7J07d6pfv36qUqWK/P39FRoaqocfflinTp1Ks4bff/9d/fr1U/HixRUcHKz+/fvr4sWLqbbZBx98oEaNGqlIkSIqUaKEWrRooVWrVrnM8/XXXzvXvVixYurUqVOWTzuOj4/XM888o4iICNntdlWsWFF9+/bVyZMnnfOcOHFCAwYMUNmyZeXv76969epp3rx5LuNcuy9MmzZNVapUUZEiRXTHHXfozz//lDFGL7/8sipWrKiAgAB17dpVp0+fdhkjq313+vRpDR8+XJGRkQoMDFRQUJA6duyoX375xWW+lFPAFi5cqBdffFEVKlRQkSJFdO7cuTS/E7Z//3716NFDoaGh8vf3V8WKFXXffffp7Nmzznms6KtruaOv5s6dq549e0qSWrdu7Xz9WLdunWJiYlSyZEkZY5zzP/XUU7LZbHrrrbec0+Li4mSz2TRjxgzntMTERI0aNUrVqlWT3W5XWFiYnnvuuVTbQvpnP27QoIECAgIUEhKi++67T3/++afLPCmv77t27VLr1q1VpEgRVahQwflelVMBAQGaP3++QkJC9Oqrr7qs64QJE9S0aVOVLFlSAQEBatCggZYsWeLyeJvNpoSEBM2bN8+57fr16ydJ+uOPP/Tkk0+qZs2aCggIUMmSJdWzZ89sn/aZ2/eI68fIaQ9KWXs9OX78uPr376+KFSvKbrerXLly6tq1a6E+3RUeYoACpHz58iYiIiLDeSIiIkzFihWNMcZcvHjRBAYGmieffDLVfK1btzZ169Z13v7tt99McHCwqVOnjhk3bpyZOnWqadGihbHZbGbp0qXO+ebMmWMkmTp16piWLVuat99+27z++usu9x08eNA5f7du3UyvXr3MG2+8YWbMmGF69uxpJJnhw4e71NOyZUtTvnx5U6ZMGTN48GDz1ltvmWbNmhlJZvbs2Zlum+joaCPJ3HvvvWbatGmmb9++RpLp1q2by3zh4eGmRo0apnjx4ub55583kyZNMpGRkcbLy8usWrXKOV9CQoK5+eabTcmSJc0LL7xgZs6cafr27WtsNpt5+umnnfMdPHjQuT2qVKliXn/9dTN58mTzxx9/mL///tuUK1fOxMTEmBkzZpjx48ebmjVrGl9fX7N9+3ZjjDEXLlwwM2bMMJLMPffcY+bPn2/mz59vfvnlF2OMMaNGjTLXv1RlZ11r1qxpypYta1544QUzdepUc+uttxqbzWZ+++23DLdnynpFRkaaiIgIM27cOBMbG2tCQkJM6dKlzfHjx53z5nbf+eGHH8wLL7xgJJkhQ4aY+fPnO5+L1atXGx8fH1OjRg0zfvx4Exsba0qVKmVKlCjhsp+lbKc6deqYrl27munTp5tp06a5bIdy5cqZ0aNHm8mTJ5sKFSqYwMBA88EHH5hKlSqZ119/3bz++usmODjYVKtWzVy9etU59oQJE0zz5s3NmDFjzDvvvGOefvppExAQYBo1amQcDkeqGm655RbTvXt3M336dPPII48YSea5555z2b6jR482kkzTpk3NG2+8Yd58803Tp08f869//cs5z/vvv29sNpu58847zdtvv23GjRtnIiIiTPHixV3WPS3nz583N910k/H29jaPPvqomTFjhnn55ZfNbbfd5tz3Ll68aGrXrm18fX3NM888Y9566y3TvHlzI8lMmTIl1b5Qv359U6dOHTNp0iTz4osvGj8/P9OkSRPzwgsvmKZNm5q33nrLDBkyxNhsNtO/f3+XerLad1u3bjVVq1Y1zz//vJk1a5YZM2aMqVChggkODjZHjhxxzvftt986n+/69eubSZMmmbFjx5qEhATn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hCTJ29tboaGhstlsCg4OztH+OmrUKGdvzps3TxUrVtSyZcvUq1evbI8VHBysYsWKOetC+uif3PXPvn379PXXX+vHH3/UbbfdJkmaPXu2atfO+LtL9FThRU/dmD315ptv6s4773Ruqxo1auiHH37QihUrMhxzypQpGjFihLp37y5JmjlzplauXOm8Py96jyNhudSkSRPZbDbn7aioKO3fv1+7du2Sj4+PGjdu7LyvZMmSqlmzZrpHZS5cuKDhw4erdu3aKl68uAIDA7V79+5Un7Q0bNjQ5Xa/fv20Y8cO1axZU0OGDNGqVauc9w0cOFCBgYHOf9eKiopy/t/Hx0cNGzZMt7bdu3fr9ttvd5l2++23a//+/bp69ao2bNjgspxrD1nffPPNLo8rV66cyycp33zzjdq2basKFSqoWLFieuihh3Tq1KkML+v52muvuSzv2m107Xql3E5vverWresco2PHjukuD5mjFzLvhfS20dWrV1MtJ616d+/e7TwFI63a05LWOB07dnTerlu3brrbIiQkJN3n6fDhwy7jvvbaaxnWgYzRP7nrn927d8vHx0cNGjRw3l+rVi2XK6LRUzcWeurG7Kndu3e7PLfXz59Wn509e1bHjh1zeVzKds9LHAnLR4YPH67Vq1drwoQJqlatmgICAnTvvfcqKSnJZb6iRYu63L711lt18OBBff311/rmm2/Uq1cvtWvXTkuWLNGYMWMyPX3PHRo2bOhyqc6yZcs6/+/r6+syr81mk8PhkPTPucGdO3fWE088oVdffVUhISH6/vvvNWDAACUlJalIkSJpLm/gwIEunyKWL18+R3V/9dVXzkPYAQEBORoD7ldYeyE73FVvWuP85z//0aVLlySl7s+sKl++vMt6hoSE5LhGuBf9kzZ6CjlFT6Utv/dUWvJTnxHCcmnLli0utzdv3qzq1aurTp06unLlirZs2eI83H3q1Cnt3btXderUSXOsjRs3ql+/frrnnnsk/fPJS1YvAhEUFKTevXurd+/euvfee3XnnXfq9OnTKlOmjMqUKZPmYzZv3qwWLVpIkq5cuaJt27a5HFa/Vu3atbVx48ZU9daoUUPe3t4KCAhQtWrVslTrtbZt2yaHw6GJEyc6f2X8448/dpnHz88v1ZGCkJCQdBtn8+bN6tu3r8vtW265Jc15s3pqADJHL2TeC+ltI29v71TzplVv7dq1NX/+fF2+fNn5KePmzZvTXFZG41SoUCHd+Tdv3qxKlSpJ+ufL6/v27Uvz9BMfH58c9TzSRv/krn9q1arlXHbKqVN79+51uXgBPXVjoaduzJ6qXbt2muuVIr0+K1eunLZs2ZJqu996660Z1p4bnI6YS4cPH1ZMTIz27t2rjz76SG+//baefvppVa9eXV27dtWjjz6q77//Xr/88osefPBBVahQQV27dk1zrOrVq2vp0qXasWOHfvnlF/Xp08d5xCgjkyZN0kcffaQ9e/Zo3759Wrx4sUJDQzP9Ybpp06Zp2bJl2rNnjwYNGqQzZ87o4YcfTnPeYcOGac2aNXr55Ze1b98+zZs3T1OnTs31JyDVqlVTcnKy3n77bf3vf//T/PnzNXPmTJd5IiIidOHCBa1Zs0YnT57M8DRFSVq8eLHee+897du3T6NGjdKPP/6Y7osX3IdeyLwX0ttGWdWnTx/ZbDY9+uij2rVrl7766itNmDAhy4/PijFjxmjNmjX67bff1K9fP5UqVSrPf0gT9E9u+6dmzZq688479fjjj2vLli3atm2bHnnkkUzPcKCnCi966sbsqSFDhmjFihWaMGGC9u/fr6lTp2b6fTBJevrpp/X6669r+fLl2rNnj5588sm8/31akw8kJCSYn376ySQkJHi6lGxp2bKlefLJJ83AgQNNUFCQKVGihHnhhReMw+Ewxhhz+vRp89BDD5ng4GATEBBgOnToYPbt2+d8/Jw5c0xwcLDz9sGDB03r1q1NQECACQsLM1OnTjUtW7Y0Tz/9tHOe8PBwM3nyZJc63nnnHVO/fn1TtGhRExQUZNq2bWt+/vnndOs+ePCgkWQWLFhgGjVqZPz8/EydOnXM2rVrnfN8++23RpI5c+aMc9qSJUtMnTp1jK+vr6lUqZJ54403srSNrq3fGGO6du1qoqOjnbcnTZpkypUr59xG77//fqplDxw40JQsWdJIMqNGjUp3eZLMtGnTTPv27Y3dbjcRERFm0aJFqdZ9+/bt6Y5x/fOyfft2I8kcPHgw0/W9UdELWeuFjLZReut0vU2bNpl69eoZPz8/U79+ffPJJ5+k2qeDg4PNnDlzMq3pWinr+fnnn5u6desaPz8/06hRI/PLL78457n+eUpLdHS06dq1q/P25MmTTXh4eLZqudHQP+7pn2PHjplOnToZu91uKlWqZN5//3166gZFT924PWWMMbNnzzYVK1Y0AQEBpkuXLmbChAmZ9llycrJ5+umnTVBQkClevLiJiYkxffv2zXbvpWSaJUuWmLFjx5qdO3emO6/NmGz+SE0euHjxonbv3q3atWun+x2g/KhVq1aqX7++pkyZ4ulS8P/ZbDYtW7aMTxktRi9kLr9vo3Xr1ql169Y6c+ZMpp/Swr3y+76RHxTEbURPeU5B3F+sVhC3UUHoqZRMc+jQIe3fv1+dOnVy/t7s9TgdEQAAAAAsRAgDAAAAAAtxOiIAAAAA5BKnIwIAAABAPpWvQlhWLvcJAAAAAPlNdrJMvghhfn5+kv758TsAAAAAKGhSskxycnKm8/rkdTFZ4ePjo1KlSunIkSOSpMDAQHl55Yt8CAAAAADpcjgcunDhgo4cOaL4+PgsHRHLFyFMkipVqqSrV686gxgAAAAAFBTx8fGKi4uTMUbGGPn6+qY7b74JYTabTZUrV9bOnTv1559/qnTp0hkWDgAAAAD5QXJyshwOhxwOh44ePaoSJUqoVKlS6c6fLy5Rf62EhAStWLFCv//+u/JZaQAAAACQLmOMSpQooY4dOyo8PDzd+fJdCJOkS5cu6fjx47p06RJBDAAAAECB4Ofnp5CQEJUsWTLD+fJlCAMAAACAwopLEAIAAACAhQhhAAAAAGAhQhgAAAAAWIgQBgAAAAAWIoQBAAAAgIX+H6r/mOkC97ucAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "metrics = {\n", - " \"polars-bio-nat-pl-lf\": {\"0-1\": 0.164, \"0-3\": 9.248, \"0-8\": 3.470, \"7-8\": 5.090},\n", - " \"polars-bio-pl-df--pl-lf\": {\n", - " \"0-1\": 0.147,\n", - " \"0-3\": 44.942,\n", - " \"0-8\": 6.096,\n", - " \"7-8\": 9.522,\n", - " },\n", - " \"polars-bio-pd-df--pl-lf\": {\n", - " \"0-1\": 0.177,\n", - " \"0-3\": 43.369,\n", - " \"0-8\": 6.241,\n", - " \"7-8\": 9.688,\n", - " },\n", - " \"polars-bio-pd-df--pd-df\": {\n", - " \"0-1\": 0.175,\n", - " \"0-3\": 51.226,\n", - " \"0-8\": 7.435,\n", - " \"7-8\": 11.756,\n", - " },\n", - "}\n", - "plot_metrics(\n", - " metrics,\n", - " [\"0-1\", \"0-3\", \"0-8\", \"7-8\"],\n", - " \"Overlap operation performance comparison between DataFrames\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "caccc329ea316f05", - "metadata": {}, - "source": "## Nearest" - }, - { - "cell_type": "code", - "execution_count": 43, - "id": "7307580054aa7d4e", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T06:54:58.562728Z", - "start_time": "2024-12-16T06:54:58.560945Z" - } - }, - "outputs": [], - "source": [ - "from polars_bio import FilterOp\n", - "import polars_bio as pb\n", - "\n", - "pb.ctx.set_option(\"datafusion.execution.target_partitions\", \"1\")\n", - "pb.ctx.set_option(\"datafusion.optimizer.repartition_joins\", \"false\")" - ] - }, - { - "cell_type": "markdown", - "id": "d808c04c9f99c6b6", - "metadata": {}, - "source": "### 0-1" - }, - { - "cell_type": "code", - "execution_count": 71, - "id": "821e3151e6a6e1f", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T07:10:27.983325Z", - "start_time": "2024-12-16T07:10:27.258575Z" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "2350965" - ] - }, - "execution_count": 71, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(df_0_pr.nearest(df_1_pr))" - ] - }, - { - "cell_type": "code", - "execution_count": 72, - "id": "44f3329dc936f096", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T07:10:29.672109Z", - "start_time": "2024-12-16T07:10:29.438203Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO:polars_bio:Running nearest: algorithm CoitreesNearest with 1 threads\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "shape: (1, 7)
contig_1pos_start_1pos_end_1contig_2pos_start_2pos_end_2distance
u32u32u32u32u32u32u32
2350965235096523509652350965235096523509652350965
" - ], - "text/plain": [ - "shape: (1, 7)\n", - "┌──────────┬─────────────┬───────────┬──────────┬─────────────┬───────────┬──────────┐\n", - "│ contig_1 ┆ pos_start_1 ┆ pos_end_1 ┆ contig_2 ┆ pos_start_2 ┆ pos_end_2 ┆ distance │\n", - "│ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │\n", - "│ u32 ┆ u32 ┆ u32 ┆ u32 ┆ u32 ┆ u32 ┆ u32 │\n", - "╞══════════╪═════════════╪═══════════╪══════════╪═════════════╪═══════════╪══════════╡\n", - "│ 2350965 ┆ 2350965 ┆ 2350965 ┆ 2350965 ┆ 2350965 ┆ 2350965 ┆ 2350965 │\n", - "└──────────┴─────────────┴───────────┴──────────┴─────────────┴───────────┴──────────┘" - ] - }, - "execution_count": 72, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pb.nearest(df_path_0, df_path_1, overlap_filter=FilterOp.Strict).collect().count()" - ] - }, - { - "cell_type": "code", - "execution_count": 83, - "id": "48a0121f4a018d32", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T07:30:54.883707Z", - "start_time": "2024-12-16T07:30:54.556121Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO:polars_bio:Running nearest: algorithm CoitreesNearest with 1 threads\n" - ] - }, - { - "data": { - "text/plain": [ - "2350965" - ] - }, - "execution_count": 83, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(\n", - " pb.nearest(\n", - " df_0, df_1, overlap_filter=FilterOp.Strict, output_type=\"pandas.DataFrame\"\n", - " )\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 76, - "id": "851b2aac4c2007c1", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T07:22:37.785612Z", - "start_time": "2024-12-16T07:22:36.286072Z" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "2350965" - ] - }, - "execution_count": 76, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(\n", - " bf.closest(\n", - " df_0,\n", - " df_1,\n", - " suffixes=(\"_1\", \"_2\"),\n", - " cols1=(\"contig\", \"pos_start\", \"pos_end\"),\n", - " cols2=(\"contig\", \"pos_start\", \"pos_end\"),\n", - " )\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "id": "1635e076c58e372f", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T06:55:36.059294Z", - "start_time": "2024-12-16T06:55:36.057562Z" - } - }, - "outputs": [], - "source": [ - "### 0-3" - ] - }, - { - "cell_type": "code", - "execution_count": 65, - "id": "742a4f3e4e829068", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T07:09:51.687014Z", - "start_time": "2024-12-16T07:09:50.966193Z" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "2350965" - ] - }, - "execution_count": 65, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(df_0_pr.nearest(df_3_pr))" - ] - }, - { - "cell_type": "code", - "execution_count": 77, - "id": "3c1d8f23eea97c63", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T07:22:46.856131Z", - "start_time": "2024-12-16T07:22:44.911028Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO:polars_bio:Running nearest: algorithm CoitreesNearest with 1 threads\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "shape: (1, 7)
contig_1pos_start_1pos_end_1contig_2pos_start_2pos_end_2distance
u32u32u32u32u32u32u32
2350965235096523509652350965235096523509652350965
" - ], - "text/plain": [ - "shape: (1, 7)\n", - "┌──────────┬─────────────┬───────────┬──────────┬─────────────┬───────────┬──────────┐\n", - "│ contig_1 ┆ pos_start_1 ┆ pos_end_1 ┆ contig_2 ┆ pos_start_2 ┆ pos_end_2 ┆ distance │\n", - "│ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │\n", - "│ u32 ┆ u32 ┆ u32 ┆ u32 ┆ u32 ┆ u32 ┆ u32 │\n", - "╞══════════╪═════════════╪═══════════╪══════════╪═════════════╪═══════════╪══════════╡\n", - "│ 2350965 ┆ 2350965 ┆ 2350965 ┆ 2350965 ┆ 2350965 ┆ 2350965 ┆ 2350965 │\n", - "└──────────┴─────────────┴───────────┴──────────┴─────────────┴───────────┴──────────┘" - ] - }, - "execution_count": 77, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pb.nearest(df_path_0, df_path_3, overlap_filter=FilterOp.Strict).collect().count()" - ] - }, - { - "cell_type": "code", - "execution_count": 82, - "id": "9511200a4747c7ac", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T07:30:35.059914Z", - "start_time": "2024-12-16T07:30:33.120323Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO:polars_bio:Running nearest: algorithm CoitreesNearest with 1 threads\n" - ] - }, - { - "data": { - "text/plain": [ - "2350965" - ] - }, - "execution_count": 82, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(\n", - " pb.nearest(\n", - " df_0, df_3, overlap_filter=FilterOp.Strict, output_type=\"pandas.DataFrame\"\n", - " )\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 78, - "id": "45b5c52d86addda1", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T07:24:33.106378Z", - "start_time": "2024-12-16T07:22:49.056273Z" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "2350965" - ] - }, - "execution_count": 78, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(\n", - " bf.closest(\n", - " df_0,\n", - " df_3,\n", - " suffixes=(\"_1\", \"_2\"),\n", - " cols1=(\"contig\", \"pos_start\", \"pos_end\"),\n", - " cols2=(\"contig\", \"pos_start\", \"pos_end\"),\n", - " )\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "d24b8def21308bb0", - "metadata": {}, - "source": "### 0-8" - }, - { - "cell_type": "code", - "execution_count": 67, - "id": "c656968bfe2fb445", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T07:10:03.959021Z", - "start_time": "2024-12-16T07:10:00.992170Z" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "2350965" - ] - }, - "execution_count": 67, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(df_0_pr.nearest(df_8_pr))" - ] - }, - { - "cell_type": "code", - "execution_count": 68, - "id": "9b0a3f17d49d1a8b", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T07:10:06.694111Z", - "start_time": "2024-12-16T07:10:05.578835Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO:polars_bio:Running nearest: algorithm CoitreesNearest with 1 threads\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "shape: (1, 7)
contig_1pos_start_1pos_end_1contig_2pos_start_2pos_end_2distance
u32u32u32u32u32u32u32
2350965235096523509652350965235096523509652350965
" - ], - "text/plain": [ - "shape: (1, 7)\n", - "┌──────────┬─────────────┬───────────┬──────────┬─────────────┬───────────┬──────────┐\n", - "│ contig_1 ┆ pos_start_1 ┆ pos_end_1 ┆ contig_2 ┆ pos_start_2 ┆ pos_end_2 ┆ distance │\n", - "│ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │\n", - "│ u32 ┆ u32 ┆ u32 ┆ u32 ┆ u32 ┆ u32 ┆ u32 │\n", - "╞══════════╪═════════════╪═══════════╪══════════╪═════════════╪═══════════╪══════════╡\n", - "│ 2350965 ┆ 2350965 ┆ 2350965 ┆ 2350965 ┆ 2350965 ┆ 2350965 ┆ 2350965 │\n", - "└──────────┴─────────────┴───────────┴──────────┴─────────────┴───────────┴──────────┘" - ] - }, - "execution_count": 68, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pb.nearest(df_path_0, df_path_8, overlap_filter=FilterOp.Strict).collect().count()" - ] - }, - { - "cell_type": "code", - "execution_count": 81, - "id": "e8d72e412223bcfd", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T07:30:15.829254Z", - "start_time": "2024-12-16T07:30:14.600179Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO:polars_bio:Running nearest: algorithm CoitreesNearest with 1 threads\n" - ] - }, - { - "data": { - "text/plain": [ - "2350965" - ] - }, - "execution_count": 81, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(\n", - " pb.nearest(\n", - " df_0, df_8, overlap_filter=FilterOp.Strict, output_type=\"pandas.DataFrame\"\n", - " )\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 75, - "id": "778737f01bb55519", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T07:22:25.865473Z", - "start_time": "2024-12-16T07:21:51.411229Z" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "2350965" - ] - }, - "execution_count": 75, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(\n", - " bf.closest(\n", - " df_0,\n", - " df_8,\n", - " suffixes=(\"_1\", \"_2\"),\n", - " cols1=(\"contig\", \"pos_start\", \"pos_end\"),\n", - " cols2=(\"contig\", \"pos_start\", \"pos_end\"),\n", - " )\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "88d308f61a234402", - "metadata": {}, - "source": "### 7-8" - }, - { - "cell_type": "code", - "execution_count": 69, - "id": "778bed8b6ecbeac2", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T07:10:12.566070Z", - "start_time": "2024-12-16T07:10:09.679856Z" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "1194262" - ] - }, - "execution_count": 69, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(df_7_pr.nearest(df_8_pr))" - ] - }, - { - "cell_type": "code", - "execution_count": 70, - "id": "4c63620db4a80cb2", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T07:10:15.674024Z", - "start_time": "2024-12-16T07:10:14.648745Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO:polars_bio:Running nearest: algorithm CoitreesNearest with 1 threads\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "shape: (1, 7)
contig_1pos_start_1pos_end_1contig_2pos_start_2pos_end_2distance
u32u32u32u32u32u32u32
1194285119428511942851194262119426211942621194285
" - ], - "text/plain": [ - "shape: (1, 7)\n", - "┌──────────┬─────────────┬───────────┬──────────┬─────────────┬───────────┬──────────┐\n", - "│ contig_1 ┆ pos_start_1 ┆ pos_end_1 ┆ contig_2 ┆ pos_start_2 ┆ pos_end_2 ┆ distance │\n", - "│ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │\n", - "│ u32 ┆ u32 ┆ u32 ┆ u32 ┆ u32 ┆ u32 ┆ u32 │\n", - "╞══════════╪═════════════╪═══════════╪══════════╪═════════════╪═══════════╪══════════╡\n", - "│ 1194285 ┆ 1194285 ┆ 1194285 ┆ 1194262 ┆ 1194262 ┆ 1194262 ┆ 1194285 │\n", - "└──────────┴─────────────┴───────────┴──────────┴─────────────┴───────────┴──────────┘" - ] - }, - "execution_count": 70, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pb.nearest(df_path_7, df_path_8, overlap_filter=FilterOp.Strict).collect().count()" - ] - }, - { - "cell_type": "code", - "execution_count": 80, - "id": "f34aac1ff1ec9ac4", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T07:29:35.817730Z", - "start_time": "2024-12-16T07:29:34.625710Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO:polars_bio:Running nearest: algorithm CoitreesNearest with 1 threads\n" - ] - }, - { - "data": { - "text/plain": [ - "1194285" - ] - }, - "execution_count": 80, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(\n", - " pb.nearest(\n", - " df_7, df_8, overlap_filter=FilterOp.Strict, output_type=\"pandas.DataFrame\"\n", - " )\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 74, - "id": "d232e39d53502d3f", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T07:21:43.770509Z", - "start_time": "2024-12-16T07:20:35.225095Z" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "1194285" - ] - }, - "execution_count": 74, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(\n", - " bf.closest(\n", - " df_7,\n", - " df_8,\n", - " suffixes=(\"_1\", \"_2\"),\n", - " cols1=(\"contig\", \"pos_start\", \"pos_end\"),\n", - " cols2=(\"contig\", \"pos_start\", \"pos_end\"),\n", - " )\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 84, - "id": "d712e9a31b24a645", - "metadata": { - "ExecuteTime": { - "end_time": "2024-12-16T07:33:16.548733Z", - "start_time": "2024-12-16T07:33:16.483366Z" - } - }, - "outputs": [ - { - "data": { - "image/png": "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71f7ypXP0eWV/9Pc6Wc3vw7c3d1VvHhxdenSRW+++aby5r3zx+Cb72bn5+enhx56SG+//bZatWplrnDclzgiBdwj9+oHjPPly6eQkBBuVSrp6NGjSk1NVfPmzRUaGipvb29nl4QMMBbgLE899ZROnDihEydOaM2aNcqbN69atGghScqTJ49CQkKy9GE6zaFDhxQaGqo6depk+lx+vN71pL0ODh48qNdee00jR47UBx98kOXnx8bG6sSJE9q2bZvq1q2r9u3ba/duc8Ee9yeCFO5LTzzxhPr27au+ffsqICBAhQoV0vDhw5V2t//z58+rS5cuKlCggLy9vdW0aVMdPHgw0/4OHTqkVq1aKTg4WL6+vqpRo4ZWr15t1yY8PFzvvvuuunTpIn9/f/Xs2VNXr15V3759FRoaKk9PT5UoUUJjx469Y/1//vmn6tSpI09PTz388MP68ccfbfMyOp1p0aJFqlixojw8PBQeHq6PPvooS9uof//+GjJkiAIDAxUSEqKRI0fatZkwYYIqVaokHx8fhYWFqXfv3kpMTLTV0a1bN128eFEWi0UWiyXd829msVg0bdo0NW3aVF5eXipZsqQWLlx4xzozM3v2bFWqdOMb8ZIlS8pisejw4cPZ7u9+xVjI2li43TaSpC+//FLVq1eXn5+fQkJC9Nxzz9nd4SqtljVr1qh69ery9vZWnTp1tH//frtljRs3TsHBwfLz81P37t115coVu/lbt25Vo0aNVKhQIQUEBKh+/fr67bffbPMNw9DIkSNVvHhxeXh4qEiRIurfv/8d1/FB5eHhoZCQEIWEhKhq1aoaOnSojh07pn/++SfDU/t+/PFH1axZUx4eHgoNDdXQoUN17do1STeObPTr109Hjx6VxWJReHi4pP97/QwcOFCFChVSkyZNJN1+/yn932mzy5Yt00MPPSRvb2+1b99eycnJmjNnjsLDw1WgQAH1799f169ftz0vJSVFgwcPVtGiReXj46NatWpp/fr193xb5mZpr4MSJUrolVdeUVRUlObPny9/f/9070NLliyRj4+PLl26ZJuWP39+hYSEqGzZsnr33Xd17do1rVu3zjZ/xYoVqlevnvLnz6+CBQuqRYsWOnTokG1+2mvtu+++U4MGDeTt7a0qVapo48aNdsueNWuWwsLC5O3trTZt2mjChAnpTq3+97//rUcffVSenp4qWbKkYmJibK9R9g85jyCF+9acOXOUN29ebdmyRR9//LEmTJigzz77TNKNN8Rt27Zp6dKl2rhxowzDULNmzZSampphX4mJiWrWrJnWrFmjHTt26KmnnlLLli119OhRu3YffvihqlSpoh07dmj48OGaPHmyli5dqvnz52v//v2aO3eu7c33dl5//XW99tpr2rFjhyIjI9WyZUudPXs2w7bbt29Xx44d1alTJ+3evVsjR47U8OHDNXv27CxtIx8fH23evFnjx4/XqFGjFBcXZ5vv5uamyZMna8+ePZozZ47Wrl2rIUOGSLpxWtWkSZPk7+9v+8Z38ODBt13e8OHD1a5dO+3atUudO3dWp06dsn2XoGeeecb2AX7Lli06ceKEwsLCstXX/Y6xMPuutpEkpaam6t1339WuXbu0ZMkSHT58WF27dk3Xz1tvvaWPPvpI27ZtU968efXiiy/a5s2fP18jR47Ue++9p23btik0NFSffvqp3fMvXbqk6Oho/fLLL9q0aZPKlCmjZs2a2T7ULVq0SBMnTtSMGTN08OBBLVmyxPaFAm4vMTFRX331lUqXLq2CBQumm//333+rWbNmqlGjhnbt2qVp06bp888/1+jRoyVJH3/8sUaNGqVixYrpxIkT2rp1q+25c+bMUb58+bRhwwZNnz5d0u33n2mSk5M1efJkffPNN1qxYoXWr1+vNm3aaPny5Vq+fLm+/PJLzZgxw+7Dft++fbVx40Z98803+v3339WhQwc99dRTt/0CBPa8vLzk5uamTp06KTY21m5ebGys2rdvLz8/v3TPu3btmj7//HNJN46Ip0lKStKgQYO0bds2rVmzRm5ubmrTpk26a47eeustDR48WDt37lTZsmX17LPP2kLQhg0b1KtXLw0YMEA7d+5Uo0aNNGbMGLvn//zzz+rSpYsGDBigvXv3asaMGZo9e7atHfuHnMcP8iJTycnJ2rdvn8qXL5/ulClXv0bqiSee0OnTp7Vnzx7baT9Dhw7V0qVL9e9//1tly5bVhg0bVKdOHUnS2bNnFRYWpjlz5qhDhw5Zuvbn4YcfVq9evdS3b19JN76Ff+SRR7R48WJbm/79+2vPnj1avXp1lk4/Onz4sCIiIjRu3Di98cYbkm7suCMiItSvXz8NGTJE69evV4MGDXT+/Hnlz59fnTt31j///KNVq1bZ+hkyZIj+85//aM+ePbfdRtevX9fPP/9sm1azZk09+eSTGjduXIbPWbhwoXr16qUzZ85IMneNlMViUa9evTRt2jTbtNq1a+vRRx/Vp59+alv3HTt2ZHrx/a3L27lzpx555BHFx8dn6UO5w+WCa6QYC1kbC5lto71792b4nG3btqlGjRq6dOmSfH19bbWsXr1aDRs2lCQtX75czZs31+XLl+Xp6ak6derokUce0dSpU2391K5dW1euXMn0pgVWq1X58+fXvHnz1KJFC02YMEEzZszQH3/8IXd39ztux3spN1wj9dVXX8nT01PSjQ+7oaGhWrZsmR599NF0+5y33npLixYt0r59+2yvg08//VRvvPGGLl68aLuhzaRJk+yOfj/xxBNKSEiwO3KYkYz2n926ddNff/2lUqVKSZJ69eqlL7/8UqdOnbL9huNTTz2l8PBwTZ8+XUePHlXJkiV19OhRFSlSxNZ3VFSUatasqffee8/UNnKE3HCN1IULF7RkyRIZhqE1a9aoRYsW6tevnzp06KA6dero2LFjCg0N1enTp1W0aFGtXr1a9evXl3TjvcvT01N58uTR5cuXZbVaFR4eru3btyswMDDDZZ45c0aFCxfW7t279fDDD9tea5999pm6d+8uSdq7d68qVqyoffv2qVy5curUqZMSExO1bNkyWz/PP/+8li1bZtv/RkVFqWHDhho2bJitzVdffaUhQ4bo+PHjpvcPaZ/zDh8+rPj4eJUuXVqtW7c2tX0fdByRwn2rdu3adh/YIiMjdfDgQe3du1d58+ZVrVq1bPMKFiyohx56KNOjI4mJiRo8eLDKly+v/Pnzy9fXV/v27Uv3LXz16tXtHnft2lU7d+7UQw89pP79+9t9wOvVq5d8fX1t/24WGRlp+3/evHlVvXr1TGvbt2+f6tatazetbt26OnjwoC0o3bycuXPn2tpVrlzZ7nlpbyRp0j4UFi1aVH5+fnrhhRd09uxZJScnZ1iLJL333nt2y7t5G928XmmPM1uvihUr2vpo2rRppsvDnTEW7jwWMttGaadUbd++XS1btlTx4sXl5+dn+5B163rfPKZCQ0MlyTam9u3bZ7etb10/STp16pR69OihMmXKKCAgQP7+/kpMTLQtp0OHDrp8+bJKliypHj16aPHixbZvtJFegwYNtHPnTu3cuVNbtmxRkyZN1LRpUx05ciRd2337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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "metrics = {\n", - " \"polars-bio-nat-pl-lf\": {\"0-1\": 0.233, \"0-3\": 1.945, \"0-8\": 1.115, \"7-8\": 1.025},\n", - " \"polars-bio-pandas\": {\"0-1\": 0.327, \"0-3\": 1.939, \"0-8\": 1.229, \"7-8\": 1.192},\n", - " \"Bioframe\": {\"0-1\": 1.499, \"0-3\": 104.0, \"0-8\": 34.454, \"7-8\": 68.00},\n", - " \"PyRanges\": {\"0-1\": 0.724, \"0-3\": 0.720, \"0-8\": 2.966, \"7-8\": 2.866},\n", - "}\n", - "plot_metrics(\n", - " metrics, [\"0-1\", \"0-3\", \"0-8\", \"7-8\"], \"Nearest operation performance comparison\"\n", - ")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/benchmark/src/bench_overlap.py b/benchmark/src/bench_overlap.py new file mode 100755 index 0000000..0ffba54 --- /dev/null +++ b/benchmark/src/bench_overlap.py @@ -0,0 +1,101 @@ +import timeit + +import bioframe as bf +import numpy as np +import pandas as pd +import pyranges as pr +from rich import print +from rich.table import Table + +import polars_bio as pb + +BENCH_DATA_ROOT = "/Users/mwiewior/research/git/openstack-bdg-runners/ansible/roles/gha_runner/files/databio" +# BENCH_DATA_ROOT = os.getenv("BENCH_DATA_ROOT") + +# polars_bio +# df_path_1 = f"{BENCH_DATA_ROOT}/chainRn4/*.parquet" +# df_path_2 = f"{BENCH_DATA_ROOT}/fBrain-DS14718/*.parquet" +df_path_1 = f"{BENCH_DATA_ROOT}/chainRn4/*.parquet" +df_path_2 = f"{BENCH_DATA_ROOT}/ex-rna/*.parquet" + +# df_path_1 = f"{BENCH_DATA_ROOT}/ex-anno/*.parquet" +# df_path_2 = f"{BENCH_DATA_ROOT}/ex-rna/*.parquet" +pb.ctx.set_option("datafusion.optimizer.repartition_joins", "false") + +columns = ("contig", "pos_start", "pos_end") + + +# bioframe +df_1 = pd.read_parquet(df_path_1.replace("*.parquet", ""), engine="pyarrow") +df_2 = pd.read_parquet(df_path_2.replace("*.parquet", ""), engine="pyarrow") + + +# pyranges +def df2pr(df): + return pr.PyRanges( + chromosomes=df.contig, + starts=df.pos_start, + ends=df.pos_end, + ) + + +df_1_pr = df2pr(df_1) +df_2_pr = df2pr(df_2) + + +def bioframe(): + bf.overlap(df_1, df_2, cols1=columns, cols2=columns, how="inner").count() + + +def polars_bio(): + pb.overlap(df_path_1, df_path_2, col1=columns, col2=columns).collect().count() + + +def pyranges(): + df_1_pr.join(df_2_pr) + + +functions = [bioframe, polars_bio, pyranges] + +num_repeats = 3 +num_executions = 5 + +results = [] +for func in functions: + times = timeit.repeat(func, repeat=num_repeats, number=num_executions) + per_run_times = [ + time / num_executions for time in times + ] # Convert to per-run times + results.append( + { + "name": func.__name__, + "min": min(per_run_times), + "max": max(per_run_times), + "mean": np.mean(per_run_times), + } + ) + +fastest_mean = min(result["mean"] for result in results) +for result in results: + result["speedup"] = fastest_mean / result["mean"] + +# Create Rich table +table = Table(title="Benchmark Results") +table.add_column("Function", justify="left", style="cyan", no_wrap=True) +table.add_column("Min (s)", justify="right", style="green") +table.add_column("Max (s)", justify="right", style="green") +table.add_column("Mean (s)", justify="right", style="green") +table.add_column("Speedup", justify="right", style="magenta") + +# Add rows to the table +for result in results: + table.add_row( + result["name"], + f"{result['min']:.6f}", + f"{result['max']:.6f}", + f"{result['mean']:.6f}", + f"{result['speedup']:.2f}x", + ) + +# Display the table +print(table) diff --git a/docs/performance.md b/docs/performance.md index f16473a..219ee51 100644 --- a/docs/performance.md +++ b/docs/performance.md @@ -1,3 +1,46 @@ +## Test environment + +```python exec="on" session="benchmark" +import os +import platform +from textwrap import dedent +import polars_bio +import cpuinfo +import psutil +import numpy as np +BENCH_DATA_ROOT = os.getenv("BENCH_DATA_ROOT") +BENCH_SRC_ROOT = os.getenv("BENCH_SRC_ROOT") +OUTPUT_MD = "test.md" + +print( + dedent( + f""" + - cpu architecture: `{platform.machine()}` + - cpu name: `{cpuinfo.get_cpu_info()['brand_raw']}` + - cpu cores: `{psutil.cpu_count(logical=False)}` + - memory: `{int(np.round(psutil.virtual_memory().total / (1024. **3)))} GB` + - kernel: `{platform.version()}` + - system: `{platform.system()}` + - os-release: `{platform.platform()}` + - python: `{platform.python_version()}` + - polars-bio: `{polars_bio.__version__}` + """ + ) +) +``` + +### Overlap operation +```python exec="on" session="benchmark" +import os +import subprocess + +subprocess.run(["hyperfine", "python benchmark/src/overlap/test-polars-bio.py", "--export-markdown", OUTPUT_MD, "-u", "millisecond", "--show-output"]) +markdown = open("test.md").read() +print(markdown) +os.remove(OUTPUT_MD) +``` + + ## Benchmarking polars-bio significantly outperforms other libraries in terms of speed and memory usage. It was benchmarked against following libraries: diff --git a/mkdocs.yml b/mkdocs.yml index 8c79567..be6e3fd 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -23,10 +23,11 @@ plugins: execute: true allow_errors: false - mkdocstrings: - default_handler: - python: - options: - docstring_style: google + default_handler: python + handlers: + options: + docstring_style: google + - markdown-exec theme: name: material logo: assets/logo.png diff --git a/poetry.lock b/poetry.lock index 7add96e..dc81908 100644 --- a/poetry.lock +++ b/poetry.lock @@ -335,127 +335,114 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.4.0" +version = "3.4.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false -python-versions = ">=3.7.0" +python-versions = ">=3.7" files = [ - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, - {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, - {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-win32.whl", hash = "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-win32.whl", hash = "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-win32.whl", hash = "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765"}, + {file = "charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85"}, + {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, ] [[package]] name = "click" -version = "8.1.7" +version = "8.1.8" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, ] [package.dependencies] @@ -665,6 +652,25 @@ files = [ docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] tests = ["pytest", "pytest-cov", "pytest-xdist"] +[[package]] +name = "datafusion" +version = "42.0.0" +description = "Build and run queries against data" +optional = false +python-versions = ">=3.6" +files = [ + {file = "datafusion-42.0.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:e9506356ad5d5f7b0f2d636cea24c5fc72518305aacf81207ecb4d59d0ea6866"}, + {file = "datafusion-42.0.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:63a07e3779d3bdca0ecafd2eedf6948feff3ecd496a1fcf93baac122a48c6f4f"}, + {file = "datafusion-42.0.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4f04adbef61e70a3f56c6fcf6b615f75bbc42610947092870acff03171a456b"}, + {file = "datafusion-42.0.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:1fb4a7f34225948d7a5db2ee3b3a578dd6b95c2bae39fd940dfd2de90a34088d"}, + {file = "datafusion-42.0.0-cp38-abi3-win_amd64.whl", hash = "sha256:71d9af5a9a6852f8121e4811a913cfec596f4c36240149edea57d27af7318749"}, + {file = "datafusion-42.0.0.tar.gz", hash = "sha256:c88955a9ac59504d9d302be03158e692b9f99c3bf53dca0e84252d81f8c5ca91"}, +] + +[package.dependencies] +pyarrow = ">=11.0.0" +typing-extensions = {version = "*", markers = "python_version < \"3.13\""} + [[package]] name = "debugpy" version = "1.8.11" @@ -1172,13 +1178,13 @@ testing = ["Django", "attrs", "colorama", "docopt", "pytest (<9.0.0)"] [[package]] name = "jinja2" -version = "3.1.4" +version = "3.1.5" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" files = [ - {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, - {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, + {file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"}, + {file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"}, ] [package.dependencies] @@ -1343,13 +1349,13 @@ test = ["ipykernel", "pre-commit", "pytest (<8)", "pytest-cov", "pytest-timeout" [[package]] name = "jupyter-events" -version = "0.10.0" +version = "0.11.0" description = "Jupyter Event System library" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "jupyter_events-0.10.0-py3-none-any.whl", hash = "sha256:4b72130875e59d57716d327ea70d3ebc3af1944d3717e5a498b8a06c6c159960"}, - {file = "jupyter_events-0.10.0.tar.gz", hash = "sha256:670b8229d3cc882ec782144ed22e0d29e1c2d639263f92ca8383e66682845e22"}, + {file = "jupyter_events-0.11.0-py3-none-any.whl", hash = "sha256:36399b41ce1ca45fe8b8271067d6a140ffa54cec4028e95491c93b78a855cacf"}, + {file = "jupyter_events-0.11.0.tar.gz", hash = "sha256:c0bc56a37aac29c1fbc3bcfbddb8c8c49533f9cf11f1c4e6adadba936574ab90"}, ] [package.dependencies] @@ -1363,7 +1369,7 @@ traitlets = ">=5.3" [package.extras] cli = ["click", "rich"] -docs = ["jupyterlite-sphinx", "myst-parser", "pydata-sphinx-theme", "sphinxcontrib-spelling"] +docs = ["jupyterlite-sphinx", "myst-parser", "pydata-sphinx-theme (>=0.16)", "sphinx (>=8)", "sphinxcontrib-spelling"] test = ["click", "pre-commit", "pytest (>=7.0)", "pytest-asyncio (>=0.19.0)", "pytest-console-scripts", "rich"] [[package]] @@ -1383,13 +1389,13 @@ jupyter-server = ">=1.1.2" [[package]] name = "jupyter-server" -version = "2.14.2" +version = "2.15.0" description = "The backend—i.e. core services, APIs, and REST endpoints—to Jupyter web applications." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "jupyter_server-2.14.2-py3-none-any.whl", hash = "sha256:47ff506127c2f7851a17bf4713434208fc490955d0e8632e95014a9a9afbeefd"}, - {file = "jupyter_server-2.14.2.tar.gz", hash = "sha256:66095021aa9638ced276c248b1d81862e4c50f292d575920bbe960de1c56b12b"}, + {file = "jupyter_server-2.15.0-py3-none-any.whl", hash = "sha256:872d989becf83517012ee669f09604aa4a28097c0bd90b2f424310156c2cdae3"}, + {file = "jupyter_server-2.15.0.tar.gz", hash = "sha256:9d446b8697b4f7337a1b7cdcac40778babdd93ba614b6d68ab1c0c918f1c4084"}, ] [package.dependencies] @@ -1398,7 +1404,7 @@ argon2-cffi = ">=21.1" jinja2 = ">=3.0.3" jupyter-client = ">=7.4.4" jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" -jupyter-events = ">=0.9.0" +jupyter-events = ">=0.11.0" jupyter-server-terminals = ">=0.4.4" nbconvert = ">=6.4.4" nbformat = ">=5.3.0" @@ -1438,13 +1444,13 @@ test = ["jupyter-server (>=2.0.0)", "pytest (>=7.0)", "pytest-jupyter[server] (> [[package]] name = "jupyterlab" -version = "4.3.3" +version = "4.3.4" description = "JupyterLab computational environment" optional = false python-versions = ">=3.8" files = [ - {file = "jupyterlab-4.3.3-py3-none-any.whl", hash = "sha256:32a8fd30677e734ffcc3916a4758b9dab21b02015b668c60eb36f84357b7d4b1"}, - {file = "jupyterlab-4.3.3.tar.gz", hash = "sha256:76fa39e548fdac94dc1204af5956c556f54c785f70ee26aa47ea08eda4d5bbcd"}, + {file = "jupyterlab-4.3.4-py3-none-any.whl", hash = "sha256:b754c2601c5be6adf87cb5a1d8495d653ffb945f021939f77776acaa94dae952"}, + {file = "jupyterlab-4.3.4.tar.gz", hash = "sha256:f0bb9b09a04766e3423cccc2fc23169aa2ffedcdf8713e9e0fb33cac0b6859d0"}, ] [package.dependencies] @@ -1521,13 +1527,13 @@ files = [ [[package]] name = "jupytext" -version = "1.16.5" +version = "1.16.6" description = "Jupyter notebooks as Markdown documents, Julia, Python or R scripts" optional = false python-versions = ">=3.8" files = [ - {file = "jupytext-1.16.5-py3-none-any.whl", hash = "sha256:0c96841e364b0ac401e7f45ee67ee523d69eb7bee59476b8ee96ba39fc964491"}, - {file = "jupytext-1.16.5.tar.gz", hash = "sha256:2d5f896f11ebee8342f0f5f9c4818a336e12db164bcaec009ea612cd5dc2caa8"}, + {file = "jupytext-1.16.6-py3-none-any.whl", hash = "sha256:900132031f73fee15a1c9ebd862e05eb5f51e1ad6ab3a2c6fdd97ce2f9c913b4"}, + {file = "jupytext-1.16.6.tar.gz", hash = "sha256:dbd03f9263c34b737003f388fc069e9030834fb7136879c4c32c32473557baa0"}, ] [package.dependencies] @@ -1689,6 +1695,23 @@ importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.5)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"] testing = ["coverage", "pyyaml"] +[[package]] +name = "markdown-exec" +version = "1.10.0" +description = "Utilities to execute code blocks in Markdown files." +optional = false +python-versions = ">=3.9" +files = [ + {file = "markdown_exec-1.10.0-py3-none-any.whl", hash = "sha256:dea4e8b78a3fe7d8e664088ebaccbd4de51b65c45b9e0db9509a9bb4fce33192"}, + {file = "markdown_exec-1.10.0.tar.gz", hash = "sha256:d1fa017995ef337ec59e7ce49fbf3e051145a62c3124ae687c17e987f1392cd0"}, +] + +[package.dependencies] +pymdown-extensions = ">=9" + +[package.extras] +ansi = ["pygments-ansi-color"] + [[package]] name = "markdown-it-py" version = "3.0.0" @@ -2151,49 +2174,49 @@ mkdocstrings = ">=0.26" [[package]] name = "mypy" -version = "1.13.0" +version = "1.14.0" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"}, - {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"}, - {file = "mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7"}, - {file = "mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f"}, - {file = "mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372"}, - {file = "mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d"}, - {file = "mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d"}, - {file = "mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b"}, - {file = "mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73"}, - {file = "mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca"}, - {file = "mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5"}, - {file = "mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e"}, - {file = "mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2"}, - {file = "mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0"}, - {file = "mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2"}, - {file = "mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7"}, - {file = "mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62"}, - {file = "mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8"}, - {file = "mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7"}, - {file = "mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc"}, - {file = "mypy-1.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:100fac22ce82925f676a734af0db922ecfea991e1d7ec0ceb1e115ebe501301a"}, - {file = "mypy-1.13.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bcb0bb7f42a978bb323a7c88f1081d1b5dee77ca86f4100735a6f541299d8fb"}, - {file = "mypy-1.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bde31fc887c213e223bbfc34328070996061b0833b0a4cfec53745ed61f3519b"}, - {file = "mypy-1.13.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07de989f89786f62b937851295ed62e51774722e5444a27cecca993fc3f9cd74"}, - {file = "mypy-1.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:4bde84334fbe19bad704b3f5b78c4abd35ff1026f8ba72b29de70dda0916beb6"}, - {file = "mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc"}, - {file = "mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732"}, - {file = "mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc"}, - {file = "mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d"}, - {file = "mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24"}, - {file = "mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a"}, - {file = "mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e"}, -] - -[package.dependencies] -mypy-extensions = ">=1.0.0" + {file = "mypy-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e971c1c667007f9f2b397ffa80fa8e1e0adccff336e5e77e74cb5f22868bee87"}, + {file = "mypy-1.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e86aaeaa3221a278c66d3d673b297232947d873773d61ca3ee0e28b2ff027179"}, + {file = "mypy-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1628c5c3ce823d296e41e2984ff88c5861499041cb416a8809615d0c1f41740e"}, + {file = "mypy-1.14.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7fadb29b77fc14a0dd81304ed73c828c3e5cde0016c7e668a86a3e0dfc9f3af3"}, + {file = "mypy-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:3fa76988dc760da377c1e5069200a50d9eaaccf34f4ea18428a3337034ab5a44"}, + {file = "mypy-1.14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6e73c8a154eed31db3445fe28f63ad2d97b674b911c00191416cf7f6459fd49a"}, + {file = "mypy-1.14.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:273e70fcb2e38c5405a188425aa60b984ffdcef65d6c746ea5813024b68c73dc"}, + {file = "mypy-1.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1daca283d732943731a6a9f20fdbcaa927f160bc51602b1d4ef880a6fb252015"}, + {file = "mypy-1.14.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7e68047bedb04c1c25bba9901ea46ff60d5eaac2d71b1f2161f33107e2b368eb"}, + {file = "mypy-1.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:7a52f26b9c9b1664a60d87675f3bae00b5c7f2806e0c2800545a32c325920bcc"}, + {file = "mypy-1.14.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d5326ab70a6db8e856d59ad4cb72741124950cbbf32e7b70e30166ba7bbf61dd"}, + {file = "mypy-1.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bf4ec4980bec1e0e24e5075f449d014011527ae0055884c7e3abc6a99cd2c7f1"}, + {file = "mypy-1.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:390dfb898239c25289495500f12fa73aa7f24a4c6d90ccdc165762462b998d63"}, + {file = "mypy-1.14.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7e026d55ddcd76e29e87865c08cbe2d0104e2b3153a523c529de584759379d3d"}, + {file = "mypy-1.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:585ed36031d0b3ee362e5107ef449a8b5dfd4e9c90ccbe36414ee405ee6b32ba"}, + {file = "mypy-1.14.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9f6f4c0b27401d14c483c622bc5105eff3911634d576bbdf6695b9a7c1ba741"}, + {file = "mypy-1.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56b2280cedcb312c7a79f5001ae5325582d0d339bce684e4a529069d0e7ca1e7"}, + {file = "mypy-1.14.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:342de51c48bab326bfc77ce056ba08c076d82ce4f5a86621f972ed39970f94d8"}, + {file = "mypy-1.14.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:00df23b42e533e02a6f0055e54de9a6ed491cd8b7ea738647364fd3a39ea7efc"}, + {file = "mypy-1.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:e8c8387e5d9dff80e7daf961df357c80e694e942d9755f3ad77d69b0957b8e3f"}, + {file = "mypy-1.14.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b16738b1d80ec4334654e89e798eb705ac0c36c8a5c4798496cd3623aa02286"}, + {file = "mypy-1.14.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:10065fcebb7c66df04b05fc799a854b1ae24d9963c8bb27e9064a9bdb43aa8ad"}, + {file = "mypy-1.14.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fbb7d683fa6bdecaa106e8368aa973ecc0ddb79a9eaeb4b821591ecd07e9e03c"}, + {file = "mypy-1.14.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:3498cb55448dc5533e438cd13d6ddd28654559c8c4d1fd4b5ca57a31b81bac01"}, + {file = "mypy-1.14.0-cp38-cp38-win_amd64.whl", hash = "sha256:c7b243408ea43755f3a21a0a08e5c5ae30eddb4c58a80f415ca6b118816e60aa"}, + {file = "mypy-1.14.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:14117b9da3305b39860d0aa34b8f1ff74d209a368829a584eb77524389a9c13e"}, + {file = "mypy-1.14.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af98c5a958f9c37404bd4eef2f920b94874507e146ed6ee559f185b8809c44cc"}, + {file = "mypy-1.14.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f0b343a1d3989547024377c2ba0dca9c74a2428ad6ed24283c213af8dbb0710b"}, + {file = "mypy-1.14.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cdb5563c1726c85fb201be383168f8c866032db95e1095600806625b3a648cb7"}, + {file = "mypy-1.14.0-cp39-cp39-win_amd64.whl", hash = "sha256:74e925649c1ee0a79aa7448baf2668d81cc287dc5782cff6a04ee93f40fb8d3f"}, + {file = "mypy-1.14.0-py3-none-any.whl", hash = "sha256:2238d7f93fc4027ed1efc944507683df3ba406445a2b6c96e79666a045aadfab"}, + {file = "mypy-1.14.0.tar.gz", hash = "sha256:822dbd184d4a9804df5a7d5335a68cf7662930e70b8c1bc976645d1509f9a9d6"}, +] + +[package.dependencies] +mypy_extensions = ">=1.0.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = ">=4.6.0" +typing_extensions = ">=4.6.0" [package.extras] dmypy = ["psutil (>=4.0)"] @@ -2215,13 +2238,13 @@ files = [ [[package]] name = "nbclient" -version = "0.10.1" +version = "0.10.2" description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." optional = false -python-versions = ">=3.8.0" +python-versions = ">=3.9.0" files = [ - {file = "nbclient-0.10.1-py3-none-any.whl", hash = "sha256:949019b9240d66897e442888cfb618f69ef23dc71c01cb5fced8499c2cfc084d"}, - {file = "nbclient-0.10.1.tar.gz", hash = "sha256:3e93e348ab27e712acd46fccd809139e356eb9a31aab641d1a7991a6eb4e6f68"}, + {file = "nbclient-0.10.2-py3-none-any.whl", hash = "sha256:4ffee11e788b4a27fabeb7955547e4318a5298f34342a4bfd01f2e1faaeadc3d"}, + {file = "nbclient-0.10.2.tar.gz", hash = "sha256:90b7fc6b810630db87a6d0c2250b1f0ab4cf4d3c27a299b0cde78a4ed3fd9193"}, ] [package.dependencies] @@ -2232,8 +2255,8 @@ traitlets = ">=5.4" [package.extras] dev = ["pre-commit"] -docs = ["autodoc-traits", "flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "mock", "moto", "myst-parser", "nbconvert (>=7.0.0)", "pytest (>=7.0,<8)", "pytest-asyncio", "pytest-cov (>=4.0)", "sphinx (>=1.7)", "sphinx-book-theme", "sphinxcontrib-spelling", "testpath", "xmltodict"] -test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>=7.0.0)", "pytest (>=7.0,<8)", "pytest-asyncio", "pytest-cov (>=4.0)", "testpath", "xmltodict"] +docs = ["autodoc-traits", "flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "mock", "moto", "myst-parser", "nbconvert (>=7.1.0)", "pytest (>=7.0,<8)", "pytest-asyncio", "pytest-cov (>=4.0)", "sphinx (>=1.7)", "sphinx-book-theme", "sphinxcontrib-spelling", "testpath", "xmltodict"] +test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>=7.1.0)", "pytest (>=7.0,<8)", "pytest-asyncio", "pytest-cov (>=4.0)", "testpath", "xmltodict"] [[package]] name = "nbconvert" @@ -2318,18 +2341,18 @@ files = [ [[package]] name = "notebook" -version = "7.3.1" +version = "7.3.2" description = "Jupyter Notebook - A web-based notebook environment for interactive computing" optional = false python-versions = ">=3.8" files = [ - {file = "notebook-7.3.1-py3-none-any.whl", hash = "sha256:212e1486b2230fe22279043f33c7db5cf9a01d29feb063a85cb139747b7c9483"}, - {file = "notebook-7.3.1.tar.gz", hash = "sha256:84381c2a82d867517fd25b86e986dae1fe113a70b98f03edff9b94e499fec8fa"}, + {file = "notebook-7.3.2-py3-none-any.whl", hash = "sha256:e5f85fc59b69d3618d73cf27544418193ff8e8058d5bf61d315ce4f473556288"}, + {file = "notebook-7.3.2.tar.gz", hash = "sha256:705e83a1785f45b383bf3ee13cb76680b92d24f56fb0c7d2136fe1d850cd3ca8"}, ] [package.dependencies] jupyter-server = ">=2.4.0,<3" -jupyterlab = ">=4.3.2,<4.4" +jupyterlab = ">=4.3.4,<4.4" jupyterlab-server = ">=2.27.1,<3" notebook-shim = ">=0.2,<0.3" tornado = ">=6.2.0" @@ -2700,17 +2723,18 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "polars" -version = "1.17.1" +version = "1.18.0" description = "Blazingly fast DataFrame library" optional = false python-versions = ">=3.9" files = [ - {file = "polars-1.17.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:d3a2172f7cf332010f0b034345111e9c86d59b5a5b0fc5aa0509121f40d9e43c"}, - {file = "polars-1.17.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:82e98c69197df0d8ddc341a6175008508ceaea88f723f32044027810bcdb43fa"}, - {file = "polars-1.17.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59abdab015ed2ecfa0c63862b960816c35096e1f4df057dde3c44cd973af5029"}, - {file = "polars-1.17.1-cp39-abi3-manylinux_2_24_aarch64.whl", hash = "sha256:6d2f922c403b8900b3ae3c23a27b2cae3a2db40ad790cc4fc368402b92629b11"}, - {file = "polars-1.17.1-cp39-abi3-win_amd64.whl", hash = "sha256:d38156c8259554cbcb17874d91e6dfa9c404335f08a3307496aadfdee46baa31"}, - {file = "polars-1.17.1.tar.gz", hash = "sha256:5a3dac3cb7cbe174d1fa898cba9afbede0c08e8728feeeab515554d762127019"}, + {file = "polars-1.18.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:27a6c7e5d2d15afb5f06291433019411c9a28e59e49741442d11a6a945f21daa"}, + {file = "polars-1.18.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:6431563aee2dfa6787b0debbed3f565ebb4322da32317d95c8eac3e48330bc28"}, + {file = "polars-1.18.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a333ff578373e29e0cacc79c35afe42c0620813c9b0c832009ab8b330e421093"}, + {file = "polars-1.18.0-cp39-abi3-manylinux_2_24_aarch64.whl", hash = "sha256:3a3a65a3ad6b6b0bd61a33f215856cfdd3e3abc9942e69526b2b88c0ef8683a4"}, + {file = "polars-1.18.0-cp39-abi3-win_amd64.whl", hash = "sha256:a79ef2542454d9cace63e8fa528cf808b6377077173be522df9b8c0e792ce96a"}, + {file = "polars-1.18.0-cp39-abi3-win_arm64.whl", hash = "sha256:52b543da52f4f6a661a2fa3cdd4b499938bdb34eeae538ec3bcef6c8c41bfc33"}, + {file = "polars-1.18.0.tar.gz", hash = "sha256:5c2f119555ae8d822a5322509c6abd91601a8931115d2e4c3fff13fadf39e877"}, ] [package.extras] @@ -2735,7 +2759,7 @@ pyarrow = ["pyarrow (>=7.0.0)"] pydantic = ["pydantic"] sqlalchemy = ["polars[pandas]", "sqlalchemy"] style = ["great-tables (>=0.8.0)"] -timezone = ["backports-zoneinfo", "tzdata"] +timezone = ["tzdata"] xlsx2csv = ["xlsx2csv (>=0.8.0)"] xlsxwriter = ["xlsxwriter"] @@ -2787,32 +2811,32 @@ wcwidth = "*" [[package]] name = "psutil" -version = "6.1.0" +version = "6.1.1" description = "Cross-platform lib for process and system monitoring in Python." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "psutil-6.1.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ff34df86226c0227c52f38b919213157588a678d049688eded74c76c8ba4a5d0"}, - {file = "psutil-6.1.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:c0e0c00aa18ca2d3b2b991643b799a15fc8f0563d2ebb6040f64ce8dc027b942"}, - {file = "psutil-6.1.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:000d1d1ebd634b4efb383f4034437384e44a6d455260aaee2eca1e9c1b55f047"}, - {file = "psutil-6.1.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5cd2bcdc75b452ba2e10f0e8ecc0b57b827dd5d7aaffbc6821b2a9a242823a76"}, - {file = "psutil-6.1.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:045f00a43c737f960d273a83973b2511430d61f283a44c96bf13a6e829ba8fdc"}, - {file = "psutil-6.1.0-cp27-none-win32.whl", hash = "sha256:9118f27452b70bb1d9ab3198c1f626c2499384935aaf55388211ad982611407e"}, - {file = "psutil-6.1.0-cp27-none-win_amd64.whl", hash = "sha256:a8506f6119cff7015678e2bce904a4da21025cc70ad283a53b099e7620061d85"}, - {file = "psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688"}, - {file = "psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e"}, - {file = "psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38"}, - {file = "psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b"}, - {file = "psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a"}, - {file = "psutil-6.1.0-cp36-cp36m-win32.whl", hash = "sha256:6d3fbbc8d23fcdcb500d2c9f94e07b1342df8ed71b948a2649b5cb060a7c94ca"}, - {file = "psutil-6.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:1209036fbd0421afde505a4879dee3b2fd7b1e14fee81c0069807adcbbcca747"}, - {file = "psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e"}, - {file = "psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be"}, - {file = "psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a"}, -] - -[package.extras] -dev = ["black", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pytest-cov", "requests", "rstcheck", "ruff", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "wheel"] + {file = "psutil-6.1.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9ccc4316f24409159897799b83004cb1e24f9819b0dcf9c0b68bdcb6cefee6a8"}, + {file = "psutil-6.1.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ca9609c77ea3b8481ab005da74ed894035936223422dc591d6772b147421f777"}, + {file = "psutil-6.1.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:8df0178ba8a9e5bc84fed9cfa61d54601b371fbec5c8eebad27575f1e105c0d4"}, + {file = "psutil-6.1.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:1924e659d6c19c647e763e78670a05dbb7feaf44a0e9c94bf9e14dfc6ba50468"}, + {file = "psutil-6.1.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:018aeae2af92d943fdf1da6b58665124897cfc94faa2ca92098838f83e1b1bca"}, + {file = "psutil-6.1.1-cp27-none-win32.whl", hash = "sha256:6d4281f5bbca041e2292be3380ec56a9413b790579b8e593b1784499d0005dac"}, + {file = "psutil-6.1.1-cp27-none-win_amd64.whl", hash = "sha256:c777eb75bb33c47377c9af68f30e9f11bc78e0f07fbf907be4a5d70b2fe5f030"}, + {file = "psutil-6.1.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:fc0ed7fe2231a444fc219b9c42d0376e0a9a1a72f16c5cfa0f68d19f1a0663e8"}, + {file = "psutil-6.1.1-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0bdd4eab935276290ad3cb718e9809412895ca6b5b334f5a9111ee6d9aff9377"}, + {file = "psutil-6.1.1-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6e06c20c05fe95a3d7302d74e7097756d4ba1247975ad6905441ae1b5b66003"}, + {file = "psutil-6.1.1-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97f7cb9921fbec4904f522d972f0c0e1f4fabbdd4e0287813b21215074a0f160"}, + {file = "psutil-6.1.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33431e84fee02bc84ea36d9e2c4a6d395d479c9dd9bba2376c1f6ee8f3a4e0b3"}, + {file = "psutil-6.1.1-cp36-cp36m-win32.whl", hash = "sha256:384636b1a64b47814437d1173be1427a7c83681b17a450bfc309a1953e329603"}, + {file = "psutil-6.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8be07491f6ebe1a693f17d4f11e69d0dc1811fa082736500f649f79df7735303"}, + {file = "psutil-6.1.1-cp37-abi3-win32.whl", hash = "sha256:eaa912e0b11848c4d9279a93d7e2783df352b082f40111e078388701fd479e53"}, + {file = "psutil-6.1.1-cp37-abi3-win_amd64.whl", hash = "sha256:f35cfccb065fff93529d2afb4a2e89e363fe63ca1e4a5da22b603a85833c2649"}, + {file = "psutil-6.1.1.tar.gz", hash = "sha256:cf8496728c18f2d0b45198f06895be52f36611711746b7f30c464b422b50e2f5"}, +] + +[package.extras] +dev = ["abi3audit", "black", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pytest-cov", "requests", "rstcheck", "ruff", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "vulture", "wheel"] test = ["pytest", "pytest-xdist", "setuptools"] [[package]] @@ -2840,6 +2864,71 @@ files = [ [package.extras] tests = ["pytest"] +[[package]] +name = "py-cpuinfo" +version = "9.0.0" +description = "Get CPU info with pure Python" +optional = false +python-versions = "*" +files = [ + {file = "py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690"}, + {file = "py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5"}, +] + +[[package]] +name = "pyarrow" +version = "18.1.0" +description = "Python library for Apache Arrow" +optional = false +python-versions = ">=3.9" +files = [ + {file = "pyarrow-18.1.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:e21488d5cfd3d8b500b3238a6c4b075efabc18f0f6d80b29239737ebd69caa6c"}, + {file = "pyarrow-18.1.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:b516dad76f258a702f7ca0250885fc93d1fa5ac13ad51258e39d402bd9e2e1e4"}, + {file = "pyarrow-18.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f443122c8e31f4c9199cb23dca29ab9427cef990f283f80fe15b8e124bcc49b"}, + {file = "pyarrow-18.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0a03da7f2758645d17b7b4f83c8bffeae5bbb7f974523fe901f36288d2eab71"}, + {file = "pyarrow-18.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ba17845efe3aa358ec266cf9cc2800fa73038211fb27968bfa88acd09261a470"}, + {file = "pyarrow-18.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:3c35813c11a059056a22a3bef520461310f2f7eea5c8a11ef9de7062a23f8d56"}, + {file = "pyarrow-18.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:9736ba3c85129d72aefa21b4f3bd715bc4190fe4426715abfff90481e7d00812"}, + {file = "pyarrow-18.1.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:eaeabf638408de2772ce3d7793b2668d4bb93807deed1725413b70e3156a7854"}, + {file = "pyarrow-18.1.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:3b2e2239339c538f3464308fd345113f886ad031ef8266c6f004d49769bb074c"}, + {file = "pyarrow-18.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f39a2e0ed32a0970e4e46c262753417a60c43a3246972cfc2d3eb85aedd01b21"}, + {file = "pyarrow-18.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e31e9417ba9c42627574bdbfeada7217ad8a4cbbe45b9d6bdd4b62abbca4c6f6"}, + {file = "pyarrow-18.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:01c034b576ce0eef554f7c3d8c341714954be9b3f5d5bc7117006b85fcf302fe"}, + {file = "pyarrow-18.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:f266a2c0fc31995a06ebd30bcfdb7f615d7278035ec5b1cd71c48d56daaf30b0"}, + {file = "pyarrow-18.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:d4f13eee18433f99adefaeb7e01d83b59f73360c231d4782d9ddfaf1c3fbde0a"}, + {file = "pyarrow-18.1.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:9f3a76670b263dc41d0ae877f09124ab96ce10e4e48f3e3e4257273cee61ad0d"}, + {file = "pyarrow-18.1.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:da31fbca07c435be88a0c321402c4e31a2ba61593ec7473630769de8346b54ee"}, + {file = "pyarrow-18.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:543ad8459bc438efc46d29a759e1079436290bd583141384c6f7a1068ed6f992"}, + {file = "pyarrow-18.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0743e503c55be0fdb5c08e7d44853da27f19dc854531c0570f9f394ec9671d54"}, + {file = "pyarrow-18.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:d4b3d2a34780645bed6414e22dda55a92e0fcd1b8a637fba86800ad737057e33"}, + {file = "pyarrow-18.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:c52f81aa6f6575058d8e2c782bf79d4f9fdc89887f16825ec3a66607a5dd8e30"}, + {file = "pyarrow-18.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:0ad4892617e1a6c7a551cfc827e072a633eaff758fa09f21c4ee548c30bcaf99"}, + {file = "pyarrow-18.1.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:84e314d22231357d473eabec709d0ba285fa706a72377f9cc8e1cb3c8013813b"}, + {file = "pyarrow-18.1.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:f591704ac05dfd0477bb8f8e0bd4b5dc52c1cadf50503858dce3a15db6e46ff2"}, + {file = "pyarrow-18.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:acb7564204d3c40babf93a05624fc6a8ec1ab1def295c363afc40b0c9e66c191"}, + {file = "pyarrow-18.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74de649d1d2ccb778f7c3afff6085bd5092aed4c23df9feeb45dd6b16f3811aa"}, + {file = "pyarrow-18.1.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:f96bd502cb11abb08efea6dab09c003305161cb6c9eafd432e35e76e7fa9b90c"}, + {file = "pyarrow-18.1.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:36ac22d7782554754a3b50201b607d553a8d71b78cdf03b33c1125be4b52397c"}, + {file = "pyarrow-18.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:25dbacab8c5952df0ca6ca0af28f50d45bd31c1ff6fcf79e2d120b4a65ee7181"}, + {file = "pyarrow-18.1.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6a276190309aba7bc9d5bd2933230458b3521a4317acfefe69a354f2fe59f2bc"}, + {file = "pyarrow-18.1.0-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:ad514dbfcffe30124ce655d72771ae070f30bf850b48bc4d9d3b25993ee0e386"}, + {file = "pyarrow-18.1.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aebc13a11ed3032d8dd6e7171eb6e86d40d67a5639d96c35142bd568b9299324"}, + {file = "pyarrow-18.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6cf5c05f3cee251d80e98726b5c7cc9f21bab9e9783673bac58e6dfab57ecc8"}, + {file = "pyarrow-18.1.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:11b676cd410cf162d3f6a70b43fb9e1e40affbc542a1e9ed3681895f2962d3d9"}, + {file = "pyarrow-18.1.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:b76130d835261b38f14fc41fdfb39ad8d672afb84c447126b84d5472244cfaba"}, + {file = "pyarrow-18.1.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:0b331e477e40f07238adc7ba7469c36b908f07c89b95dd4bd3a0ec84a3d1e21e"}, + {file = "pyarrow-18.1.0-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:2c4dd0c9010a25ba03e198fe743b1cc03cd33c08190afff371749c52ccbbaf76"}, + {file = "pyarrow-18.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f97b31b4c4e21ff58c6f330235ff893cc81e23da081b1a4b1c982075e0ed4e9"}, + {file = "pyarrow-18.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a4813cb8ecf1809871fd2d64a8eff740a1bd3691bbe55f01a3cf6c5ec869754"}, + {file = "pyarrow-18.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:05a5636ec3eb5cc2a36c6edb534a38ef57b2ab127292a716d00eabb887835f1e"}, + {file = "pyarrow-18.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:73eeed32e724ea3568bb06161cad5fa7751e45bc2228e33dcb10c614044165c7"}, + {file = "pyarrow-18.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:a1880dd6772b685e803011a6b43a230c23b566859a6e0c9a276c1e0faf4f4052"}, + {file = "pyarrow-18.1.0.tar.gz", hash = "sha256:9386d3ca9c145b5539a1cfc75df07757dff870168c959b473a0bccbc3abc8c73"}, +] + +[package.extras] +test = ["cffi", "hypothesis", "pandas", "pytest", "pytz"] + [[package]] name = "pycparser" version = "2.22" @@ -2867,13 +2956,13 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pymdown-extensions" -version = "10.12" +version = "10.13" description = "Extension pack for Python Markdown." optional = false python-versions = ">=3.8" files = [ - {file = "pymdown_extensions-10.12-py3-none-any.whl", hash = "sha256:49f81412242d3527b8b4967b990df395c89563043bc51a3d2d7d500e52123b77"}, - {file = "pymdown_extensions-10.12.tar.gz", hash = "sha256:b0ee1e0b2bef1071a47891ab17003bfe5bf824a398e13f49f8ed653b699369a7"}, + {file = "pymdown_extensions-10.13-py3-none-any.whl", hash = "sha256:80bc33d715eec68e683e04298946d47d78c7739e79d808203df278ee8ef89428"}, + {file = "pymdown_extensions-10.13.tar.gz", hash = "sha256:e0b351494dc0d8d14a1f52b39b1499a00ef1566b4ba23dc74f1eba75c736f5dd"}, ] [package.dependencies] @@ -3382,6 +3471,25 @@ files = [ {file = "rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055"}, ] +[[package]] +name = "rich" +version = "13.9.4" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"}, + {file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" +typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.11\""} + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + [[package]] name = "rpds-py" version = "0.22.3" @@ -3496,29 +3604,29 @@ files = [ [[package]] name = "ruff" -version = "0.8.3" +version = "0.8.4" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.8.3-py3-none-linux_armv6l.whl", hash = "sha256:8d5d273ffffff0acd3db5bf626d4b131aa5a5ada1276126231c4174543ce20d6"}, - {file = "ruff-0.8.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e4d66a21de39f15c9757d00c50c8cdd20ac84f55684ca56def7891a025d7e939"}, - {file = "ruff-0.8.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c356e770811858bd20832af696ff6c7e884701115094f427b64b25093d6d932d"}, - {file = "ruff-0.8.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c0a60a825e3e177116c84009d5ebaa90cf40dfab56e1358d1df4e29a9a14b13"}, - {file = "ruff-0.8.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:75fb782f4db39501210ac093c79c3de581d306624575eddd7e4e13747e61ba18"}, - {file = "ruff-0.8.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f26bc76a133ecb09a38b7868737eded6941b70a6d34ef53a4027e83913b6502"}, - {file = "ruff-0.8.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:01b14b2f72a37390c1b13477c1c02d53184f728be2f3ffc3ace5b44e9e87b90d"}, - {file = "ruff-0.8.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:53babd6e63e31f4e96ec95ea0d962298f9f0d9cc5990a1bbb023a6baf2503a82"}, - {file = "ruff-0.8.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ae441ce4cf925b7f363d33cd6570c51435972d697e3e58928973994e56e1452"}, - {file = "ruff-0.8.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7c65bc0cadce32255e93c57d57ecc2cca23149edd52714c0c5d6fa11ec328cd"}, - {file = "ruff-0.8.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:5be450bb18f23f0edc5a4e5585c17a56ba88920d598f04a06bd9fd76d324cb20"}, - {file = "ruff-0.8.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8faeae3827eaa77f5721f09b9472a18c749139c891dbc17f45e72d8f2ca1f8fc"}, - {file = "ruff-0.8.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:db503486e1cf074b9808403991663e4277f5c664d3fe237ee0d994d1305bb060"}, - {file = "ruff-0.8.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6567be9fb62fbd7a099209257fef4ad2c3153b60579818b31a23c886ed4147ea"}, - {file = "ruff-0.8.3-py3-none-win32.whl", hash = "sha256:19048f2f878f3ee4583fc6cb23fb636e48c2635e30fb2022b3a1cd293402f964"}, - {file = "ruff-0.8.3-py3-none-win_amd64.whl", hash = "sha256:f7df94f57d7418fa7c3ffb650757e0c2b96cf2501a0b192c18e4fb5571dfada9"}, - {file = "ruff-0.8.3-py3-none-win_arm64.whl", hash = "sha256:fe2756edf68ea79707c8d68b78ca9a58ed9af22e430430491ee03e718b5e4936"}, - {file = "ruff-0.8.3.tar.gz", hash = "sha256:5e7558304353b84279042fc584a4f4cb8a07ae79b2bf3da1a7551d960b5626d3"}, + {file = "ruff-0.8.4-py3-none-linux_armv6l.whl", hash = "sha256:58072f0c06080276804c6a4e21a9045a706584a958e644353603d36ca1eb8a60"}, + {file = "ruff-0.8.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ffb60904651c00a1e0b8df594591770018a0f04587f7deeb3838344fe3adabac"}, + {file = "ruff-0.8.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:6ddf5d654ac0d44389f6bf05cee4caeefc3132a64b58ea46738111d687352296"}, + {file = "ruff-0.8.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e248b1f0fa2749edd3350a2a342b67b43a2627434c059a063418e3d375cfe643"}, + {file = "ruff-0.8.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bf197b98ed86e417412ee3b6c893f44c8864f816451441483253d5ff22c0e81e"}, + {file = "ruff-0.8.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c41319b85faa3aadd4d30cb1cffdd9ac6b89704ff79f7664b853785b48eccdf3"}, + {file = "ruff-0.8.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:9f8402b7c4f96463f135e936d9ab77b65711fcd5d72e5d67597b543bbb43cf3f"}, + {file = "ruff-0.8.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4e56b3baa9c23d324ead112a4fdf20db9a3f8f29eeabff1355114dd96014604"}, + {file = "ruff-0.8.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:736272574e97157f7edbbb43b1d046125fce9e7d8d583d5d65d0c9bf2c15addf"}, + {file = "ruff-0.8.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fe710ab6061592521f902fca7ebcb9fabd27bc7c57c764298b1c1f15fff720"}, + {file = "ruff-0.8.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:13e9ec6d6b55f6da412d59953d65d66e760d583dd3c1c72bf1f26435b5bfdbae"}, + {file = "ruff-0.8.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:97d9aefef725348ad77d6db98b726cfdb075a40b936c7984088804dfd38268a7"}, + {file = "ruff-0.8.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ab78e33325a6f5374e04c2ab924a3367d69a0da36f8c9cb6b894a62017506111"}, + {file = "ruff-0.8.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:8ef06f66f4a05c3ddbc9121a8b0cecccd92c5bf3dd43b5472ffe40b8ca10f0f8"}, + {file = "ruff-0.8.4-py3-none-win32.whl", hash = "sha256:552fb6d861320958ca5e15f28b20a3d071aa83b93caee33a87b471f99a6c0835"}, + {file = "ruff-0.8.4-py3-none-win_amd64.whl", hash = "sha256:f21a1143776f8656d7f364bd264a9d60f01b7f52243fbe90e7670c0dfe0cf65d"}, + {file = "ruff-0.8.4-py3-none-win_arm64.whl", hash = "sha256:9183dd615d8df50defa8b1d9a074053891ba39025cf5ae88e8bcb52edcc4bf08"}, + {file = "ruff-0.8.4.tar.gz", hash = "sha256:0d5f89f254836799af1615798caa5f80b7f935d7a670fad66c5007928e57ace8"}, ] [[package]] @@ -3773,13 +3881,13 @@ dev = ["flake8", "flake8-annotations", "flake8-bandit", "flake8-bugbear", "flake [[package]] name = "urllib3" -version = "2.2.3" +version = "2.3.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, - {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, + {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, + {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, ] [package.extras] @@ -3946,4 +4054,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.13" -content-hash = "ad226a6075f3e40c05fff94d70cec8a021163d36f911467191bf3d56af3d422c" +content-hash = "eb25ba6f585d0cfdf5a194baa84598e978630993e8f39b25ced25bec00f67aea" diff --git a/polars_bio/__init__.py b/polars_bio/__init__.py index 4dd35a7..3708fd0 100644 --- a/polars_bio/__init__.py +++ b/polars_bio/__init__.py @@ -1,11 +1,11 @@ import logging -from .range_op import ctx, nearest, overlap +from .range_op import FilterOp, ctx, nearest, overlap logging.basicConfig() logging.getLogger().setLevel(logging.WARN) logger = logging.getLogger("polars_bio") logger.setLevel(logging.INFO) - +__version__ = "0.3.1" __all__ = ["overlap", "nearest", "ctx", "FilterOp", "vizualize_intervals"] diff --git a/polars_bio/range_op.py b/polars_bio/range_op.py index 20ad5af..6bc7565 100644 --- a/polars_bio/range_op.py +++ b/polars_bio/range_op.py @@ -21,9 +21,10 @@ def overlap( how: str = "inner", overlap_filter: FilterOp = FilterOp.Strict, suffixes: tuple[str, str] = ("_1", "_2"), - on_cols=None, + on_cols: Union[list[str], None] = None, col1: Union[list[str], None] = None, col2: Union[list[str], None] = None, + algorithm: str = "Coitrees", output_type: str = "polars.LazyFrame", ) -> Union[pl.LazyFrame, pl.DataFrame, pd.DataFrame]: """ @@ -43,6 +44,7 @@ def overlap( values are 'chrom', 'start', 'end'. suffixes: Suffixes for the columns of the two overlapped sets. on_cols: List of additional column names to join on. default is None. + algorithm: The algorithm to use for the overlap operation. default is "Coitrees". output_type: Type of the output. default is "polars.LazyFrame", "polars.DataFrame", or "pandas.DataFrame" are also supported. Returns: @@ -93,6 +95,7 @@ def overlap( suffixes=suffixes, columns_1=col1, columns_2=col2, + overlap_alg=algorithm, ) return range_operation(df1, df2, range_options, output_type, ctx) diff --git a/pyproject.toml b/pyproject.toml index e02e19a..cf4cf1f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,4 +56,10 @@ mkdocs-jupyter = "^0.25.1" mkdocs-material = "^9.5.48" mike = "^2.1.3" mkdocstrings-python = "^1.12.2" -mypy = "^1.13.0" \ No newline at end of file +markdown-exec = "^1.10.0" +mypy = "^1.13.0" +py-cpuinfo = "^9.0.0" +jupyter_client = "^8.6.3" +psutil = "^6.1.1" +rich = "^13.9.4" +pyranges = "^0.0.1" \ No newline at end of file