diff --git a/README.md b/README.md index f194d79..65bd864 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,160 @@ +![GitHub Latest Tag](https://badgen.net/github/tag/RusselWebber/arrowsqlbcpy) ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/RusselWebber/arrowsqlbcpy/ci.yml) ![PyPI Python Versions](https://img.shields.io/pypi/pyversions/arrowsqlbcpy) + # arrowsqlbcpy -A tiny library that uses .Net SqlBulkCopy to enable fast data loading to SQL Server. Apache Arrow is used to serialise data between Python and the native DLL. .Net AOT compilation is used to generate the native DLL. +A tiny library that uses .Net SqlBulkCopy to enable fast data loading to Microsoft SQL Server. Apache Arrow is used to serialise data between Python and the native DLL. .Net Native Library AOT compilation is used to generate the native DLL. + +This library is _much_ faster than any other Python solution, including bcpandas, pyodbc and pymssql. See the benchmark results below. + +![Performance plot](performance.png) + +## Installation + +Binary wheels are available from PyPi and can be installed using your preferred package manager: + +> pip install arrowsqlbcpy + +or + +> uv add arrowsqlbcpy + +## Usage + +Connection strings for .Net are documented [here](https://www.connectionstrings.com/microsoft-data-sqlclient/) + +```python + +import pandas as pd +from arrowsqlbcpy import bulkcopy_from_pandas + +# Create a connection string +cn = r"Server=myServerAddress;Database=myDataBase;Trusted_Connection=True;" +# The table to load into must exist and have the same column names and types as the pandas df +tablename = "test" + +df = pd.DataFrame({"a":[1]*10000, "b":[2]*10000, "c":[3]*10000}) + +bulkcopy_from_pandas(df, cn, tablename) + +``` + +When testing it can be useful to have pandas create the table for you, see [tests/test_load.py](https://github.com/RusselWebber/arrowsqlbcpy/blob/main/tests/test_load.py) for an example. + +## Requirements + +Wheels are available for the latest versions of Windows 64 bit, MacOS ARM 64bit and Ubuntu 64 bit. + +Wheels are available for Python 3.9-3.13. + +### Linux support + +The Ubuntu wheels _may_ work on other Linux distros. Building C# native libaries and then packaging appropriately for multiple Linux distros is not straightforward. The simplest solution for most Linux distros is to simply pull the source from Github and build locally. These are the high-level steps: + +1. Install .net + https://learn.microsoft.com/en-us/dotnet/core/install/linux +2. Clone the source + > git clone https://github.com/RusselWebber/arrowsqlbcpy +3. Install uv + https://docs.astral.sh/uv/getting-started/installation/ +4. Build the wheel locally + > uv build --wheel +5. Install the wheel + > pip install dist/wheel_file.whl + +## Benchmarks + +The benchmarks were run using the [richbench](https://github.com/tonybaloney/rich-bench) package. Tests were run repeatedly to get stable benchmarks. + +> richbench ./benchmarks + +The benchmarks load a 3m row parquet file of New York taxi data. Times are recorded for loading 1000 rows, 10 000 rows, 100 000 rows, 1 000 000 rows and finally all 3 000 000 rows. + +The benchmarks have a baseline of using pandas `to_sql()` and SQLAlchemy with pyodbc and pymssql. This is a common solution for loading pandas dataframes into SQL Server. A batch size of 10 000 rows was used in the benchmarks. + +The benchmarks show the time taken to load using various alternative strategies: + +| Label | Description | +| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| fast_executemany=True | Use pandas `to_sql()`, SQLAlchemy, pyodbc, pymssql with the fast_executemany=True option as discussed [here](https://stackoverflow.com/questions/48006551/speeding-up-pandas-dataframe-to-sql-with-fast-executemany-of-pyodbc) | +| bcpandas | Use the [bcpandas](https://github.com/yehoshuadimarsky/bcpandas) package to load the dataframes. The package writes temp files and spawns bcp processes to load them | +| arrowsqlbcpy | This package using .Net SqlBulkCopy | + +The richbench tables show the min, max and mean time in seconds for the baseline in the left three columns; then the min, max, mean time in seconds for the alternative strategy. + +For example this row: + +| Benchmark | Min | Max | Mean | Min (+) | Max (+) | Mean (+) | +| ---------------------------------- | --- | --- | ---- | -------- | -------- | -------- | +| 1 000 rows - fast_executemany=True | 1.0 | 1.0 | 1.0 | 0.5 (2x) | 0.5 (2x) | 0.5 (2x) | + +should be interpreted as: the strategy of setting fast_executemany=True resulted in a 2x speedup over the baseline when loading 1000 rows, so fast_executemany=True reduced the average time in seconds to load 1000 rows from 1.0 to 0.5, a 2x speedup. + +### Windows 11 (local db) + +**Summary results** + +| | 1000 | 10000 | 10000 | 1000000 | 3000000 | +| --------------------- | ---------------- | ---------------- | ---------------- | ---------------- | ----------------- | +| df.to_sql() | 0.055 | 0.495 | 4.601 | 46.648 | 198.57 | +| arrowsqlbcpy | 0.106 (-1.9x) | **0.101 (4.9x)** | **0.933 (4.9x)** | **8.864 (5.3x)** | **26.048 (7.6x)** | +| bcpandas | 0.156 (-3.0x) | 0.336 (1.5x) | 2.567 (1.8x) | 24.627 (1.9x) | 72.353 (2.7x) | +| fast_executemany=True | **0.035 (2.4x)** | 0.235 (2.3x) | 2.246 (2.3x) | 22.044 (2.1x) | 65.344 (3.0x) | + +**Detailed richbench results** + +| Benchmark | Min | Max | Mean | Min (+) | Max (+) | Mean (+) | +| -------------------------------------- | ------- | ------- | ------- | ------------- | ------------- | ------------- | +| 1 000 - arrowsqlbcp | 0.053 | 0.056 | 0.055 | 0.015 (3.6x) | 0.198 (-3.5x) | 0.106 (-1.9x) | +| 10 000 rows - arrowsqlbcp | 0.489 | 0.502 | 0.495 | 0.099 (4.9x) | 0.103 (4.9x) | 0.101 (4.9x) | +| 100 000 rows - arrowsqlbcp | 4.587 | 4.616 | 4.601 | 0.922 (5.0x) | 0.944 (4.9x) | 0.933 (4.9x) | +| 1 000 000 rows - arrowsqlbcp | 46.558 | 46.738 | 46.648 | 8.842 (5.3x) | 8.886 (5.3x) | 8.864 (5.3x) | +| 3 000 000 rows - arrowsqlbcp | 198.464 | 198.676 | 198.570 | 26.016 (7.6x) | 26.079 (7.6x) | 26.048 (7.6x) | +| 1 000 - bcpandas | 0.051 | 0.052 | 0.052 | 0.121 (-2.4x) | 0.190 (-3.6x) | 0.156 (-3.0x) | +| 10 000 rows - bcpandas | 0.499 | 0.500 | 0.500 | 0.333 (1.5x) | 0.339 (1.5x) | 0.336 (1.5x) | +| 100 000 rows - bcpandas | 4.543 | 4.547 | 4.545 | 2.565 (1.8x) | 2.570 (1.8x) | 2.567 (1.8x) | +| 1 000 000 rows - bcpandas | 45.298 | 46.443 | 45.871 | 24.581 (1.8x) | 24.674 (1.9x) | 24.627 (1.9x) | +| 3 000 000 rows - bcpandas | 197.292 | 197.699 | 197.496 | 72.301 (2.7x) | 72.405 (2.7x) | 72.353 (2.7x) | +| 1 000 - fast_executemany=True | 0.052 | 0.116 | 0.084 | 0.030 (1.7x) | 0.041 (2.9x) | 0.035 (2.4x) | +| 10 000 rows - fast_executemany=True | 0.513 | 0.550 | 0.531 | 0.233 (2.2x) | 0.237 (2.3x) | 0.235 (2.3x) | +| 100 000 rows - fast_executemany=True | 5.018 | 5.374 | 5.196 | 2.239 (2.2x) | 2.253 (2.4x) | 2.246 (2.3x) | +| 1 000 000 rows - fast_executemany=True | 45.470 | 45.582 | 45.526 | 22.036 (2.1x) | 22.051 (2.1x) | 22.044 (2.1x) | +| 3 000 000 rows - fast_executemany=True | 194.152 | 194.523 | 194.337 | 65.153 (3.0x) | 65.534 (3.0x) | 65.344 (3.0x) | + +### Ubuntu (WSL2) (local db in docker container) + +**Summary results** + +| | 1000 | 10000 | 10000 | 1000000 | 3000000 | +| --------------------- | ---------------- | ---------------- | ---------------- | ----------------- | ----------------- | +| df.to_sql() | 0.070 | 0.506 | 5.074 | 50.089 | 208.811 | +| arrowsqlbcpy | 0.154 (-2.2x) | **0.120 (4.2x)** | **1.070 (4.7x)** | **10.572 (4.7x)** | **30.673 (6.8x)** | +| bcpandas | 0.158 (-2.4x) | 0.438 (1.2x) | 3.383 (1.5x) | 32.774 (1.5x) | 95.200 (2.2x) | +| fast_executemany=True | **0.059 (1.6x)** | 0.323 (1.7x) | 3.039 (1.6x) | 29.810 (1.7x) | 87.419 (2.4x) | + +**Detailed richbench results** + +| Benchmark | Min | Max | Mean | Min (+) | Max (+) | Mean (+) | +| -------------------------------------- | ------- | ------- | ------- | ------------- | ------------- | ------------- | +| 1 000 - arrowsqlbcp | 0.069 | 0.071 | 0.070 | 0.028 (2.4x) | 0.280 (-3.9x) | 0.154 (-2.2x) | +| 10 000 rows - arrowsqlbcp | 0.503 | 0.510 | 0.506 | 0.115 (4.4x) | 0.126 (4.0x) | 0.120 (4.2x) | +| 100 000 rows - arrowsqlbcp | 5.062 | 5.085 | 5.074 | 1.064 (4.8x) | 1.076 (4.7x) | 1.070 (4.7x) | +| 1 000 000 rows - arrowsqlbcp | 49.746 | 50.433 | 50.089 | 10.566 (4.7x) | 10.578 (4.8x) | 10.572 (4.7x) | +| 3 000 000 rows - arrowsqlbcp | 208.669 | 208.953 | 208.811 | 30.364 (6.9x) | 30.982 (6.7x) | 30.673 (6.8x) | +| 1 000 - bcpandas | 0.066 | 0.068 | 0.067 | 0.149 (-2.2x) | 0.167 (-2.5x) | 0.158 (-2.4x) | +| 10 000 rows - bcpandas | 0.500 | 0.508 | 0.504 | 0.431 (1.2x) | 0.444 (1.1x) | 0.438 (1.2x) | +| 100 000 rows - bcpandas | 5.016 | 5.028 | 5.022 | 3.369 (1.5x) | 3.397 (1.5x) | 3.383 (1.5x) | +| 1 000 000 rows - bcpandas | 49.771 | 50.535 | 50.153 | 32.603 (1.5x) | 32.945 (1.5x) | 32.774 (1.5x) | +| 3 000 000 rows - bcpandas | 208.104 | 208.350 | 208.227 | 95.057 (2.2x) | 95.343 (2.2x) | 95.200 (2.2x) | +| 1 000 - fast_executemany=True | 0.068 | 0.116 | 0.092 | 0.049 (1.4x) | 0.069 (1.7x) | 0.059 (1.6x) | +| 10 000 rows - fast_executemany=True | 0.514 | 0.557 | 0.535 | 0.322 (1.6x) | 0.324 (1.7x) | 0.323 (1.7x) | +| 100 000 rows - fast_executemany=True | 4.934 | 4.961 | 4.948 | 3.023 (1.6x) | 3.056 (1.6x) | 3.039 (1.6x) | +| 1 000 000 rows - fast_executemany=True | 49.298 | 50.658 | 49.978 | 29.783 (1.7x) | 29.836 (1.7x) | 29.810 (1.7x) | +| 3 000 000 rows - fast_executemany=True | 207.245 | 213.096 | 210.171 | 87.219 (2.4x) | 87.620 (2.4x) | 87.419 (2.4x) | + +Benchmarks for the typical case of a remote DB still need to be added. + +## Limitations + +`bulkcopy_from_pandas()` will establish its own database connection to load the data, reusing existing connections and transactions are not supported. + +Only basic MacOS testing has been done. diff --git a/benchmarks/bench_loadperf.py b/benchmarks/bench_loadperf.py new file mode 100644 index 0000000..27a96cf --- /dev/null +++ b/benchmarks/bench_loadperf.py @@ -0,0 +1,89 @@ +import pandas as pd +from arrowsqlbcpy import bulkcopy_from_pandas +from sqlalchemy import create_engine, text +from sqlalchemy.engine import URL +from bcpandas import SqlCreds, to_sql +from functools import partial + +cn = r"Server=PC\SQLEXPRESS;Database=test;Trusted_Connection=True;Encrypt=false;" +tablename = "test" +max_chunksize = 10_000 +df = pd.read_parquet(r"C:\Users\russe\Downloads\yellow_tripdata_2024-01.parquet") + +connection_url = URL.create( + "mssql+pyodbc", + host=r"PC\SQLEXPRESS", + database="test", + query={ + "driver": "SQL Server Native Client 11.0", + "Encrypt": "yes", + "TrustServerCertificate": "yes", + }, +) +engine = create_engine(connection_url) +fast_executemany_engine = create_engine(connection_url, echo=False, fast_executemany=True) +creds = SqlCreds.from_engine(engine) + +# Create the table +df.head(1).to_sql(name=tablename, con=engine, index=False, if_exists="replace") + +def default_to_sql(nrows=None): + with engine.begin() as conn: + conn.execute(text(f"TRUNCATE TABLE {tablename}")) + local_df = df.iloc[:nrows] if nrows else df + with engine.begin() as conn: + local_df.to_sql(name=tablename, con=conn, index=False, chunksize=max_chunksize, if_exists="append") + +def fast_executemany__to_sql(nrows=None): + with fast_executemany_engine.begin() as conn: + conn.execute(text(f"TRUNCATE TABLE {tablename}")) + local_df = df.iloc[:nrows] if nrows else df + with fast_executemany_engine.begin() as conn: + local_df.to_sql(name=tablename, con=conn, index=False, chunksize=max_chunksize, if_exists="append") + +def arrow_to_sql(nrows=None): + with engine.begin() as conn: + conn.execute(text(f"TRUNCATE TABLE {tablename}")) + local_df = df.iloc[:nrows] if nrows else df + bulkcopy_from_pandas(local_df, cn, tablename, max_chunksize=max_chunksize) + +def bcpandas_to_sql(nrows=None): + with engine.begin() as conn: + conn.execute(text(f"TRUNCATE TABLE {tablename}")) + local_df = df.iloc[:nrows] if nrows else df + to_sql(local_df, tablename, creds, index=False, if_exists="append", batch_size=min(max_chunksize, local_df.shape[0])) + +default_to_sql_1000 = partial(default_to_sql, 1_000) +fast_executemany__to_sql_1000 = partial(fast_executemany__to_sql, 1_000) +arrow_to_sql_1000 = partial(arrow_to_sql, 1_000) +bcpandas_to_sql_1000 = partial(bcpandas_to_sql, 1_000) +default_to_sql_10000 = partial(default_to_sql, 10_000) +fast_executemany__to_sql_10000 = partial(fast_executemany__to_sql, 10_000) +arrow_to_sql_10000 = partial(arrow_to_sql, 10_000) +bcpandas_to_sql_10000 = partial(bcpandas_to_sql, 10_000) +default_to_sql_100000 = partial(default_to_sql, 100_000) +fast_executemany__to_sql_100000 = partial(fast_executemany__to_sql, 100_000) +arrow_to_sql_100000 = partial(arrow_to_sql, 100_000) +bcpandas_to_sql_100000 = partial(bcpandas_to_sql, 100_000) +default_to_sql_1000000 = partial(default_to_sql, 1_000_000) +fast_executemany__to_sql_1000000 = partial(fast_executemany__to_sql, 1_000_000) +arrow_to_sql_1000000 = partial(arrow_to_sql, 1_000_000) +bcpandas_to_sql_1000000 = partial(bcpandas_to_sql, 1_000_000) + +__benchmarks__ = [ + (default_to_sql_1000, fast_executemany__to_sql_1000, "1e3 rows - fast_executemany=True"), + (default_to_sql_1000, bcpandas_to_sql_1000, "1e3 rows - bcpandas"), + (default_to_sql_1000, arrow_to_sql_1000, "1e3 rows - arrowsqlbcp"), + (default_to_sql_10000, fast_executemany__to_sql_10000, "1e4 rows - fast_executemany=True"), + (default_to_sql_10000, bcpandas_to_sql_10000, "1e4 rows - bcpandas"), + (default_to_sql_10000, arrow_to_sql_10000, "1e4 rows - arrowsqlbcp"), + (default_to_sql_100000, fast_executemany__to_sql_100000, "1e5 rows - fast_executemany=True"), + (default_to_sql_100000, bcpandas_to_sql_100000, "1e5 rows - bcpandas"), + (default_to_sql_100000, arrow_to_sql_100000, "1e5 rows - arrowsqlbcp"), + (default_to_sql_1000000, fast_executemany__to_sql_1000000, "1e6 rows - fast_executemany=True"), + (default_to_sql_1000000, bcpandas_to_sql_1000000, "1e6 rows - bcpandas"), + (default_to_sql_1000000, arrow_to_sql_1000000, "1e6 rows - arrowsqlbcp"), + (default_to_sql, fast_executemany__to_sql, "3e6 rows - fast_executemany=True"), + (default_to_sql, bcpandas_to_sql, "3e6 rows - bcpandas"), + (default_to_sql, arrow_to_sql, "3e6 rows - arrowsqlbcp") +] \ No newline at end of file diff --git a/performance.png b/performance.png new file mode 100644 index 0000000..1c00c13 Binary files /dev/null and b/performance.png differ diff --git a/pyproject.toml b/pyproject.toml index d9aceeb..a2af51e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "arrowsqlbcpy" license = {text = "MIT"} -description = "Fast bcp from pandas to SQL Server using .Net SqlBulkCopy" +description = "A tiny library that uses .Net SqlBulkCopy to enable fast data loading to Microsoft SQL Server. Apache Arrow is used to serialise data between Python and the native DLL. .Net Native Library AOT compilation is used to generate the native DLL." readme = "README.md" keywords = ["bcp", "sql", "pandas"] authors = [ @@ -13,6 +13,22 @@ dependencies = [ "pyarrow>=19.0.0", ] dynamic = ["version"] +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: C#", + "Programming Language :: Python :: Implementation :: CPython", + "Topic :: Database", + "Topic :: Database :: Database Engines/Servers" +] + +[project.urls] +Repository = "https://github.com/RusselWebber/arrowsqlbcpy.git" [build-system] requires = ["setuptools>=61", "wheel"] @@ -33,9 +49,11 @@ addopts = [ [dependency-groups] dev = [ + "bcpandas>=2.6.5", "pymssql>=2.3.2", "pyodbc>=5.2.0", "pytest>=8.3.4", + "richbench>=1.0.3", "ruff>=0.9.3", "sqlalchemy>=2.0.37", "wheel>=0.45.1", diff --git a/src/arrowsqlbcpy/__init__.py b/src/arrowsqlbcpy/__init__.py index 2477f28..7d6a1b0 100644 --- a/src/arrowsqlbcpy/__init__.py +++ b/src/arrowsqlbcpy/__init__.py @@ -14,11 +14,11 @@ sqllibname = "Microsoft.Data.SqlClient.SNI.dll" elif is_mac: libname = "ArrowSqlBulkCopyNet.dylib" - sqllibname = None + sqllibname = None else: libname = "ArrowSqlBulkCopyNet.so" sqllibname = None - + func_name = "write" error_size = 1000 diff --git a/uv.lock b/uv.lock index 20f4f19..b315803 100644 --- a/uv.lock +++ b/uv.lock @@ -1,15 +1,86 @@ version = 1 requires-python = ">=3.9" resolution-markers = [ - "python_full_version >= '3.12'", + "python_full_version >= '3.13'", + "python_full_version == '3.12.*'", "python_full_version == '3.11.*'", "python_full_version == '3.10.*'", "python_full_version < '3.10'", ] +[[package]] +name = "adbc-driver-manager" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version >= '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/20/2c/580f0e2024ce0c6330c5e990eaeffd2b206355b5929d19889b3eac008064/adbc_driver_manager-1.4.0.tar.gz", hash = "sha256:fb8437f3e3aad9aa119ccbdfe05b83418ae552ca7e1e3f6d46d53e1f316610b8", size = 107712 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/8b/4d39624e8c35d0a1efed8a9f250e8d70ce5577753e35bee93af821ba46dd/adbc_driver_manager-1.4.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:018622cefcfa5ab60faefe31ca687075dc9fdfc814d39fb34a12afd26523511f", size = 380842 }, + { url = "https://files.pythonhosted.org/packages/e7/a0/2620ea468b4fb878a7398f968be096cd6a3ee248e92b07ee41b507fc2e01/adbc_driver_manager-1.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d38f512cc52e44fdfaea19410e49032cf8599fd2df94134467e2325fc14cd6e5", size = 368018 }, + { url = "https://files.pythonhosted.org/packages/7e/69/b629f8b5f80e40cf8bbcdccff436ba298e588f04f40d173e5db6db801864/adbc_driver_manager-1.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d8dc29ec8997217e45746205f42a0c79fdc44d07b76b97422fb11b12478b4d6", size = 2038383 }, + { url = "https://files.pythonhosted.org/packages/dc/bf/075c581aae412e2588472066a32c66aee79fcbbfc14e119275c2bfa4ef00/adbc_driver_manager-1.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fa6d7dec7b3629bb154606e7ea40e8b82beb6c6950658e39fd32d8febfb94f0", size = 2060218 }, + { url = "https://files.pythonhosted.org/packages/e5/6b/949f034e30e0c0b4942d200c0d8773e2806ec283835eb1f263e3ac14ec26/adbc_driver_manager-1.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:2c3073ff54998f04ef92f43d7637b5e96d2437f13a9e243db32c807031f8819e", size = 536713 }, + { url = "https://files.pythonhosted.org/packages/b9/07/72cfaec3fb1e5090e4495bb310e4ae62d4262ea2330ee7f7395909b3505d/adbc_driver_manager-1.4.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:7bd274386c3decd52212d225cc46f934ce3503a3f9e0e823e4f8a40162d89b2b", size = 381818 }, + { url = "https://files.pythonhosted.org/packages/20/80/efb076dd9148f903a4e96f969dd7a0cdafeeabba8e14c1db9bf21452ce31/adbc_driver_manager-1.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:90d1055f2557d703fa2e7073d7b26cc6394159ff4b1422d2dae05d08b774f687", size = 368704 }, + { url = "https://files.pythonhosted.org/packages/0f/29/ed9525e46d474230a0fb310ab077a681b49c45c6e4e5a305e0c704702256/adbc_driver_manager-1.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db899b18caeb9e26b99c0baf17e239f35274d6c3dc3aa0e3afc4d278ef3c6747", size = 2150204 }, + { url = "https://files.pythonhosted.org/packages/a5/32/c00c7b5dd4c187003f0f6799090d17db42effc3396b5a6971228e0d1cbb4/adbc_driver_manager-1.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1a7079c7f254c7010afe08872c4bfab6e716a507fc343c32204e8ce6bfd898", size = 2164967 }, + { url = "https://files.pythonhosted.org/packages/37/30/3b62800f5f7aad8c51e2e71fc8e9a87dadb007588289fddab09d180ea1ae/adbc_driver_manager-1.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:27a8943ba838a4038b4ec6466e11eafe336ca5d382adb7c5d2cc9c00dd44bd10", size = 538168 }, + { url = "https://files.pythonhosted.org/packages/59/30/e76d5bdb044b4126b4deed32ff5cf02b62d9e7eba4eec5a06c6005a3952f/adbc_driver_manager-1.4.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:3770180aa2cccc6c18ffd189d623ebbf35dccad75895f0fd4275b73d39297849", size = 381431 }, + { url = "https://files.pythonhosted.org/packages/c8/25/a96b04c0162253ff9e014b774789cc76e84e536f9ef874c9d2af240bfa42/adbc_driver_manager-1.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6ba26a0510d1e7596c827d1ef58185d32fb4f97837e463608801ec3b4850ce74", size = 365687 }, + { url = "https://files.pythonhosted.org/packages/1e/8d/caae84fceed7e2cff414ce9a17f62eee0ceca98058bb8b1fbde1a1941904/adbc_driver_manager-1.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50eedc6b173a80a0a8f46ef6352761a2c53063ac94327b1f45603db33176010d", size = 2129076 }, + { url = "https://files.pythonhosted.org/packages/fb/8b/7d4ce1622b2930205261c5b7dae7ded7f3328033fdfe02f213f2bb41720f/adbc_driver_manager-1.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:168a07ce237902dd9aa0e079d7e8c131ad6f61fb20f3b43020597b2a3c29d3ea", size = 2161148 }, + { url = "https://files.pythonhosted.org/packages/59/ab/991d5dc4d8b65adab2990f949524ce5ca504aa84727bc501fa6ba919288f/adbc_driver_manager-1.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1c165069fe3bcffc25e593cb933958b4a0563aff317cb6a37fc390c8dd0ed26f", size = 535674 }, + { url = "https://files.pythonhosted.org/packages/80/97/e33d558177e8dcbdaec2191bc37970e5068e46095a21dc157aaa65530e58/adbc_driver_manager-1.4.0-cp313-cp313-macosx_10_15_x86_64.whl", hash = "sha256:acfe7ca9c227a0835abc52289601337bde7a96c20befc443c9ba4eb78d673214", size = 379612 }, + { url = "https://files.pythonhosted.org/packages/1e/4f/11aacce2421902b9bed07970d5f4565c5948f58788392962ffeceadbac21/adbc_driver_manager-1.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b5fbf822e90fc6df5321067a25564cae11b404d4c9ba56fe4471c73c5b54e38f", size = 363412 }, + { url = "https://files.pythonhosted.org/packages/0d/bd/68672ab658dbcb154500cb668e2fe630861b3ac3348c5cdb6bf501ae10ab/adbc_driver_manager-1.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e1d255116003514088990cc5af5995cc7f5d2ebea96b00e5b2a1f4d922d7137", size = 2123358 }, + { url = "https://files.pythonhosted.org/packages/f7/4a/5a966873541d580bf27711355ed9fd40cd46bea702eb092c6825306957a6/adbc_driver_manager-1.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:682364a252de1029fa12a2f7526d4cb9e8e03e009d8d0f64bc3530a7539a74f6", size = 2156251 }, + { url = "https://files.pythonhosted.org/packages/ca/4b/19d32beccfcb647451db25cc2e40dbeb6b763bf274cdc85d22e68511baa4/adbc_driver_manager-1.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:f01441fb8cc7859037ae0c39692bffa26f2fa0da68664589ced5b3794540f402", size = 533846 }, + { url = "https://files.pythonhosted.org/packages/e4/82/eac48a29eabc0a122537a3473b9f983c880caaa38c1cf9cdba977b909aa9/adbc_driver_manager-1.4.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:36a1019da980b4d0250f6139a0b4da019e362dd1dbc8cc1f4e5572590e4a765d", size = 382181 }, + { url = "https://files.pythonhosted.org/packages/68/b0/5ffd86cd152ee98b9d3df2b06bb717fc95d763e27f47c1cd21a1a8cd151d/adbc_driver_manager-1.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b4e59fcb9ba1e0c61f904d52a378ded3b5841aa6f6679fe01e2e10211dfcd0b9", size = 369121 }, + { url = "https://files.pythonhosted.org/packages/2f/38/327490f80e3b29e6af5068b52e23935a737e19dca8bba36104e9ff790d40/adbc_driver_manager-1.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88456823258e2bb43a5e43c18c462033da0877025784ee72ec6db7105709d510", size = 2044622 }, + { url = "https://files.pythonhosted.org/packages/78/c4/239c3f4a68ef1c056a21c00c60be9c98985adc6337af02d83546c56d3fce/adbc_driver_manager-1.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c113a4f3bed057217b046a1c22a7cf0daed63533faa1107da6b996f56b162e56", size = 2059145 }, + { url = "https://files.pythonhosted.org/packages/14/3f/36cd720c1bb1036405105317ed0fb32e4488048ec5be07bf502d6d5f607f/adbc_driver_manager-1.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:39a1a84783e2290c34f348382fe257500c0ea0b1c3232199cfc3dc15397af236", size = 538314 }, +] + +[[package]] +name = "adbc-driver-postgresql" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "adbc-driver-manager", marker = "python_full_version >= '3.12'" }, + { name = "importlib-resources", marker = "python_full_version >= '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2a/8b/5d088a3c4d739a3a62df081a819117df924318b5044ab3214d72723591ad/adbc_driver_postgresql-1.4.0.tar.gz", hash = "sha256:0bc9c34911b8d1a2e333ee5ef3d284a6517a8f20d5509b2c183cb4cf8337efc7", size = 18402 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/69/165a7155a9514aa472beae1e16fc93c51a363c7deed0db7d2d470c28788d/adbc_driver_postgresql-1.4.0-py3-none-macosx_10_15_x86_64.whl", hash = "sha256:ca62087f1496192c3131a30fc3e4d2710fa3b31b1982bf8374b6a05fdc446513", size = 2683068 }, + { url = "https://files.pythonhosted.org/packages/7c/37/d991e047b931a3f005156a43c8be92ffbfd234589d5969b38adee03faa80/adbc_driver_postgresql-1.4.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c75827a5cfdc8ea429c21292ac6bd598a64a42af53797c7ace3ad2b3044ddc71", size = 2996305 }, + { url = "https://files.pythonhosted.org/packages/2d/5e/dc25c82cf2055e500b2f8e47093cf6037fd636866e0e6c54ccadccda1e6a/adbc_driver_postgresql-1.4.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ce4e30ced25802acd6d0baad70e7b9c7394869043c1349206218d51d27613c1", size = 3190063 }, + { url = "https://files.pythonhosted.org/packages/42/bd/910e7b8e0d6e91f94348fe23a2f8d3dfc4e86a0b933b26d41a4298f14772/adbc_driver_postgresql-1.4.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d04b2ea0353bacca814fb15c5da0d407888d27e86b4f3f58d66ebe71a2e8d3da", size = 2846350 }, + { url = "https://files.pythonhosted.org/packages/7d/fc/19fb644ab228040a01971e21bb42c98c48a95d3701e68dd38fa1bfb0bc61/adbc_driver_postgresql-1.4.0-py3-none-win_amd64.whl", hash = "sha256:10ae2584e47928e15da8ca541bbf594de13d6c1afc8c1adad6af3f832cf0a5fc", size = 2656378 }, +] + +[[package]] +name = "adbc-driver-sqlite" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "adbc-driver-manager", marker = "python_full_version >= '3.12'" }, + { name = "importlib-resources", marker = "python_full_version >= '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0e/13/0a5ab8ecebbe13b1abd3e4bdd966250685d63a9c066bd56f59e3a9488bea/adbc_driver_sqlite-1.4.0.tar.gz", hash = "sha256:957171d87e28a917c6b22a558ef226beb7490740813609e77bf37098c60d53bd", size = 17007 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ae/76/11efcc31e2851a60246995abe76419c1b81ad0c7cada35635c89fecee734/adbc_driver_sqlite-1.4.0-py3-none-macosx_10_15_x86_64.whl", hash = "sha256:9754f956ffb9749a19365bd6749f0f6e8ec82387d85ea66c08455e443095878a", size = 1040870 }, + { url = "https://files.pythonhosted.org/packages/8a/71/b726710e0c111324d4331c2ce272f65eb71642e37118e52892d148d38a10/adbc_driver_sqlite-1.4.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7f602528ee8c2ef78f8e7ad409d37bbbc604ca404ad93e5b52685d32c73b6e00", size = 1011240 }, + { url = "https://files.pythonhosted.org/packages/d1/9c/3e421bde3c6501c0298f13074055935a64a16d0dae4b83e01e70a4bfbd0e/adbc_driver_sqlite-1.4.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30f8d658343923a10933ca9657f6373e7fb5e6e05891ec70bc27a719160f0484", size = 955018 }, + { url = "https://files.pythonhosted.org/packages/d7/96/b387c1e47a263e315861eed4bc1680ded534b4e220c365d5804364852add/adbc_driver_sqlite-1.4.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f111e982a0816c1f6471c32b87fbfdc21431d46004be301484047acc62d5b07e", size = 976394 }, + { url = "https://files.pythonhosted.org/packages/09/f2/0d250000bb12d0c37a010d26260893624b111fdfe3bd407e5fa369aea90e/adbc_driver_sqlite-1.4.0-py3-none-win_amd64.whl", hash = "sha256:0a22cd5c442f31a87727ba62fb6137f08df54774a25e355e7da06617ecf56b6a", size = 863483 }, +] + [[package]] name = "arrowsqlbcpy" -version = "0.0.1.dev0" +version = "0.2.0" source = { editable = "." } dependencies = [ { name = "pandas" }, @@ -18,9 +89,12 @@ dependencies = [ [package.dev-dependencies] dev = [ + { name = "bcpandas", version = "2.6.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, + { name = "bcpandas", version = "2.7.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, { name = "pymssql" }, { name = "pyodbc" }, { name = "pytest" }, + { name = "richbench" }, { name = "ruff" }, { name = "sqlalchemy" }, { name = "wheel" }, @@ -34,14 +108,53 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ + { name = "bcpandas", specifier = ">=2.6.5" }, { name = "pymssql", specifier = ">=2.3.2" }, { name = "pyodbc", specifier = ">=5.2.0" }, { name = "pytest", specifier = ">=8.3.4" }, + { name = "richbench", specifier = ">=1.0.3" }, { name = "ruff", specifier = ">=0.9.3" }, { name = "sqlalchemy", specifier = ">=2.0.37" }, { name = "wheel", specifier = ">=0.45.1" }, ] +[[package]] +name = "bcpandas" +version = "2.6.5" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version == '3.11.*'", + "python_full_version == '3.10.*'", + "python_full_version < '3.10'", +] +dependencies = [ + { name = "pandas", marker = "python_full_version < '3.12'" }, + { name = "pyodbc", marker = "python_full_version < '3.12'" }, + { name = "sqlalchemy", marker = "python_full_version < '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ec/ac/cb3e90271a186d49da5039f41bf95f2c29ae1dbced751c52ad15d1b5d139/bcpandas-2.6.5.tar.gz", hash = "sha256:1f68df236e966852d3c91825626e81f6f3325d213b3ff3bbe5e28571525fa990", size = 25093 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/a0/e5ffc8465474357aa21870882f812324db7a56b7d2f4317988da3fa132c7/bcpandas-2.6.5-py3-none-any.whl", hash = "sha256:51d23e7893c8d6716df302cf833e42e0db24010a8c4542d99891bbf72312285d", size = 20444 }, +] + +[[package]] +name = "bcpandas" +version = "2.7.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.13'", + "python_full_version == '3.12.*'", +] +dependencies = [ + { name = "pandas", extra = ["sql-other"], marker = "python_full_version >= '3.12'" }, + { name = "pyodbc", marker = "python_full_version >= '3.12'" }, + { name = "sqlalchemy", marker = "python_full_version >= '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/40/61/69888dff70436049ab6127392dea7b3e9cae7e86c1cb2ff5f382afe6accc/bcpandas-2.7.2.tar.gz", hash = "sha256:f3d47e737f0c99643d9a16a538c7d2fd7097bc5867483f7647dca9c8332b85b5", size = 33436 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/d4/c6bb3b6cb97b3ebf5922c7830158d2628797e43e444324c0db05747165d6/bcpandas-2.7.2-py3-none-any.whl", hash = "sha256:bc198074b925274944d2b20088a8a6113b51110eb79fe97000a14d0e7573ae98", size = 19860 }, +] + [[package]] name = "colorama" version = "0.4.6" @@ -121,6 +234,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ae/02/e7d0aef2354a38709b764df50b2b83608f0621493e47f47694eb80922822/greenlet-3.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:3319aa75e0e0639bc15ff54ca327e8dc7a6fe404003496e3c6925cd3142e0e22", size = 298306 }, ] +[[package]] +name = "importlib-resources" +version = "6.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/8c/f834fbf984f691b4f7ff60f50b514cc3de5cc08abfc3295564dd89c5e2e7/importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c", size = 44693 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec", size = 37461 }, +] + [[package]] name = "iniconfig" version = "2.0.0" @@ -130,6 +252,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, ] +[[package]] +name = "markdown-it-py" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, +] + [[package]] name = "numpy" version = "2.0.2" @@ -190,7 +333,8 @@ name = "numpy" version = "2.2.2" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.12'", + "python_full_version >= '3.13'", + "python_full_version == '3.12.*'", "python_full_version == '3.11.*'", "python_full_version == '3.10.*'", ] @@ -317,6 +461,13 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2f/49/5c30646e96c684570925b772eac4eb0a8cb0ca590fa978f56c5d3ae73ea1/pandas-2.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:4850ba03528b6dd51d6c5d273c46f183f39a9baf3f0143e566b89450965b105e", size = 11618011 }, ] +[package.optional-dependencies] +sql-other = [ + { name = "adbc-driver-postgresql", marker = "python_full_version >= '3.12'" }, + { name = "adbc-driver-sqlite", marker = "python_full_version >= '3.12'" }, + { name = "sqlalchemy", marker = "python_full_version >= '3.12'" }, +] + [[package]] name = "pluggy" version = "1.5.0" @@ -375,6 +526,73 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c4/28/c51c9af2703b5a592d1b66546611b24de8ca01e04c3f5da769c3318bca6c/pyarrow-19.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:597360ffc71fc8cceea1aec1fb60cb510571a744fffc87db33d551d5de919bec", size = 25464978 }, ] +[[package]] +name = "pygments" +version = "2.19.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, +] + +[[package]] +name = "pyinstrument" +version = "5.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/64/6e/85c2722e40cab4fd9df6bbe68a0d032e237cf8cfada71e5f067e4e433214/pyinstrument-5.0.1.tar.gz", hash = "sha256:f4fd0754d02959c113a4b1ebed02f4627b6e2c138719ddf43244fd95f201c8c9", size = 263162 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/35/06f943dc6bc147e0f39db714b14a67fa2dcff4930392658b529e8f523530/pyinstrument-5.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a14d3a90c432f1ce1be91716fa76b75dc74ed03100282878d2a4d30c7c75c980", size = 129015 }, + { url = "https://files.pythonhosted.org/packages/ff/a8/d91857423b9c0f9604db9974b782753049e9f6f86f3500fb76306c4b06bf/pyinstrument-5.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6afe94a27a9016b365b9dd3a5f03732a3cd29d8bcb178113b09e73d36cf51196", size = 121591 }, + { url = "https://files.pythonhosted.org/packages/68/c4/6ad462fc766f578973402aca949ac7783a7c40c2e750b9a996bd6640ccae/pyinstrument-5.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3f16a0bde13a4ac1b8fdbcaf49626926e523028bd68804caa186ba9e9c51d09", size = 145275 }, + { url = "https://files.pythonhosted.org/packages/d3/20/9c9732ac3e0be811df6893f7230bc0b3b5b2c2e95c0bed415de51a2324dc/pyinstrument-5.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ceee4fa6c24c5a1c346ee641b50f63438cf76bf25d2e86ee6fbfe5d505e00e6", size = 144076 }, + { url = "https://files.pythonhosted.org/packages/f3/40/f0d5920cea0543012367b338cd8ce6b1cbc9e4dd98e31829946d35f650be/pyinstrument-5.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:835ecac9061ce8926321276b47b7d17a6ae19a932d33c5ef7be632a83a07f78a", size = 145396 }, + { url = "https://files.pythonhosted.org/packages/de/c7/a365da27070773f8fb6e2f6e305b0962fa60a6acbb802772d5e348b9a599/pyinstrument-5.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c0e26a6fc51f259882b621a13ec2736a4788a57e304a102aee1bf0401eb29ce2", size = 144925 }, + { url = "https://files.pythonhosted.org/packages/75/00/a56bc74cb4468b413e6849067d95b7c3ba59386ed703045437d8f040a7d5/pyinstrument-5.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:81b7192c7dc956923829355a85ac361f2409093a3f998e8a0294ffd447863526", size = 144397 }, + { url = "https://files.pythonhosted.org/packages/db/08/eaac32dfed78a8b0cf4398da4b9bf36c370ff42d963f666f52293fec9cdc/pyinstrument-5.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d18e37baaaae969f3cf5b3187db386de7f458a8393f6825564ebb6e51714363a", size = 144795 }, + { url = "https://files.pythonhosted.org/packages/47/3e/fd73018f941e658a2b1b736c8e8e181df3735f117331dab4c33f43fbe1d7/pyinstrument-5.0.1-cp310-cp310-win32.whl", hash = "sha256:cbfdc71be2dd8e5a8a349df0430e4908897ced448a2f2c50c1cac493cd2565b5", size = 122957 }, + { url = "https://files.pythonhosted.org/packages/4c/76/5c5b2e7b381a470ced1d899ee55c532e68269e72ec1b0b9e9c3b561acc49/pyinstrument-5.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:442c763c8311557062a7ad20f9edd77600182cb14cd9fcb207cdf947d42038bb", size = 123830 }, + { url = "https://files.pythonhosted.org/packages/d8/6e/dab9eef973f8a573eea492f2ad6ba46a5fc3ce6ae947947a97f7b40ddf6e/pyinstrument-5.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a5f0a468382198b84991e83beff7c43e9315f974379b17abcc285caff154bdfc", size = 128765 }, + { url = "https://files.pythonhosted.org/packages/14/2d/c729e0bc525d070a1916b8a84c0b6088e85ea8d79f507f1c7c1a66db6cda/pyinstrument-5.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dabda1485011aa2bfa6cb293020f2e35163ccc3b2746c1e72ff0ea5e62dfe730", size = 121472 }, + { url = "https://files.pythonhosted.org/packages/e3/54/dc9fbd755337b66fb0a8309bb3451379ecee1236ff17ec44323b54f61ee7/pyinstrument-5.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f54285f0924d443dd27f0510693a76ecafd6d38573be2254b3c86314db42efe", size = 143599 }, + { url = "https://files.pythonhosted.org/packages/63/f3/26394bd74f5fe632b0a7670f008f675df397fb38d5d8fb363f5243ce8dd9/pyinstrument-5.0.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7387acabf1eb74b7a0deead0d5ad3b1a41c2c7b2d7c9b5507047f04700d0b446", size = 142529 }, + { url = "https://files.pythonhosted.org/packages/73/9a/7751e9070a6f7a4ae56de93e3e8991cf321c15f9878b2a1c390ea1839e3b/pyinstrument-5.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5ee80ac5e7821c28458b19ca61b082e1f71f1171e2c5da700e07e21c114fd31", size = 143670 }, + { url = "https://files.pythonhosted.org/packages/fa/3c/9421fa66fdf60d80994b2d69ae4d22a89a98b9993fb7d09552374902f340/pyinstrument-5.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d29093f7fd419aa26c0ef5a81dfed80cbe48799d9ab977f343570a6864ce76e2", size = 143618 }, + { url = "https://files.pythonhosted.org/packages/68/62/17a973a9dee2ce1e25d9b3289b0d606fa4e512a6dd4df64e3aed87bcb28a/pyinstrument-5.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:000de38068c10769ce9268955191df2738b065e606b5a3453077e31c0db96259", size = 143142 }, + { url = "https://files.pythonhosted.org/packages/cc/cb/9812a0ee561c158ad91d1eaa90291772061708676a8cf81e81934cbe3bfd/pyinstrument-5.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:219ed803f5e3887a9f345ec73c9e2b1f76e993202bc8f9c46a681cda2b7040f6", size = 143383 }, + { url = "https://files.pythonhosted.org/packages/93/37/8d8ea4442f2c067e0c15c745e4bf5e04eae7a6a1f48ad909a96a9fee32a3/pyinstrument-5.0.1-cp311-cp311-win32.whl", hash = "sha256:fe85109415bc63e2cc22144e6c6202b99a8087dc54330abf6d1067c775c6eb54", size = 122929 }, + { url = "https://files.pythonhosted.org/packages/d7/e9/1565ac257a7b6c9d439823848d065196fb13082d952212eaf28467737615/pyinstrument-5.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:29ff672575fc44ca775c1bd6d5871323d6e8e3b5ad49791107b750be682e5865", size = 123737 }, + { url = "https://files.pythonhosted.org/packages/e1/09/696e29364503393c5bd0471f1c396d41820167b3f496bf8b128dc981f30d/pyinstrument-5.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:cfd7b7dc56501a1f30aa059cc2f1746ece6258a841d2e4609882581f9c17f824", size = 128903 }, + { url = "https://files.pythonhosted.org/packages/b5/dd/36d1641414eb0ab3fb50815de8d927b74924a9bfb1e409c53e9aad4a16de/pyinstrument-5.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fe1f33178a2b0ddb3c6d2321406228bdad41286774e65314d511dcf4a71b83e4", size = 121440 }, + { url = "https://files.pythonhosted.org/packages/9e/3f/05196fb514735aceef9a9439f56bcaa5ccb8b440685aa4f13fdb9e925182/pyinstrument-5.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0519d02dee55a87afcf6d787f8d8f5a16d2b89f7ba9533064a986a2d31f27340", size = 144783 }, + { url = "https://files.pythonhosted.org/packages/73/4b/1b041b974e7e465ca311e712beb8be0bc9cf769bcfc6660b1b2ba630c27c/pyinstrument-5.0.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f59ed9ac9466ff9b30eb7285160fa794aa3f8ce2bcf58a94142f945882d28ab", size = 143717 }, + { url = "https://files.pythonhosted.org/packages/4a/dc/3fa73e2dde1588b6281e494a14c183a27e1a67db7401fddf9c528fb8e1a9/pyinstrument-5.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbf3114d332e499ba35ca4aedc1ef95bc6fb15c8d819729b5c0aeb35c8b64dd2", size = 145082 }, + { url = "https://files.pythonhosted.org/packages/91/24/b86d4273cc524a4f334a610a1c4b157146c808d8935e85d44dff3a6b75ee/pyinstrument-5.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:20f8054e85dd710f5a8c4d6b738867366ceef89671db09c87690ba1b5c66bd67", size = 144737 }, + { url = "https://files.pythonhosted.org/packages/3c/39/6025a71082122bfbfee4eac6649635e4c688954bdf306bcd3629457c49b2/pyinstrument-5.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:63e8d75ffa50c3cf6d980844efce0334659e934dcc3832bad08c23c171c545ff", size = 144488 }, + { url = "https://files.pythonhosted.org/packages/da/ce/679b0e9a278004defc93c277c3f81b456389dd530f89e28a45bd9dae203e/pyinstrument-5.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a3ca9c8540051513dd633de9d7eac9fee2eda50b78b6eedeaa7e5a7be66026b5", size = 144895 }, + { url = "https://files.pythonhosted.org/packages/58/d8/cf80bb278e2a071325e4fb244127eb68dce9d0520d20c1fda75414f119ee/pyinstrument-5.0.1-cp312-cp312-win32.whl", hash = "sha256:b549d910b846757ffbf74d94528d1a694a3848a6cfc6a6cab2ce697ee71e4548", size = 123027 }, + { url = "https://files.pythonhosted.org/packages/39/49/9251fe641d242d4c0dc49178b064f22da1c542d80e4040561428a9f8dd1c/pyinstrument-5.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:86f20b680223697a8ac5c061fb40a63d3ee519c7dfb1097627bd4480711216d9", size = 123818 }, + { url = "https://files.pythonhosted.org/packages/0f/ae/f8f84ecd0dc2c4f0d84920cb4ffdbea52a66e4b4abc2110f18879b57f538/pyinstrument-5.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f5065639dfedc3b8e537161f9aaa8c550c8717c935a962e9bf1e843bf0e8791f", size = 128900 }, + { url = "https://files.pythonhosted.org/packages/23/2f/b742c46d86d4c1f74ec0819f091bbc2fad0bab786584a18d89d9178802f1/pyinstrument-5.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b5d20802b0c2bd1ddb95b2e96ebd3e9757dbab1e935792c2629166f1eb267bb2", size = 121445 }, + { url = "https://files.pythonhosted.org/packages/d9/e0/297dc8454ed437aec0fbdc3cc1a6a5fdf6701935b91dd31caf38c5e3ff92/pyinstrument-5.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e6f5655d580429e7992c37757cc5f6e74ca81b0f2768b833d9711631a8cb2f7", size = 144904 }, + { url = "https://files.pythonhosted.org/packages/8b/df/e4faff09fdbad7e685ceb0f96066d434fc8350382acf8df47577653f702b/pyinstrument-5.0.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4c8c9ad93f62f0bf2ddc7fb6fce3a91c008d422873824e01c5e5e83467fd1fb", size = 143801 }, + { url = "https://files.pythonhosted.org/packages/b1/63/ed2955d980bbebf17155119e2687ac15e170b6221c4bb5f5c37f41323fe5/pyinstrument-5.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db15d1854b360182d242da8de89761a0ffb885eea61cb8652e40b5b9a4ef44bc", size = 145204 }, + { url = "https://files.pythonhosted.org/packages/c4/18/31b8dcdade9767afc7a36a313d8cf9c5690b662e9755fe7bd0523125e06f/pyinstrument-5.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c803f7b880394b7bba5939ff8a59d6962589e9a0140fc33c3a6a345c58846106", size = 144881 }, + { url = "https://files.pythonhosted.org/packages/1f/14/cd19894eb03dd28093f564e8bcf7ae4edc8e315ce962c8155cf795fc0784/pyinstrument-5.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:84e37ffabcf26fe820d354a1f7e9fc26949f953addab89b590c5000b3ffa60d0", size = 144643 }, + { url = "https://files.pythonhosted.org/packages/80/54/3dd08f5a869d3b654ff7e4e4c9d2b34f8de73fb0f2f792fac5024a312e0f/pyinstrument-5.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a0d23d3763ec95da0beb390c2f7df7cbe36ea62b6a4d5b89c4eaab81c1c649cf", size = 145070 }, + { url = "https://files.pythonhosted.org/packages/5d/dc/ac8e798235a1dbccefc1b204a16709cef36f02c07587763ba8eb510fc8bc/pyinstrument-5.0.1-cp313-cp313-win32.whl", hash = "sha256:967f84bd82f14425543a983956ff9cfcf1e3762755ffcec8cd835c6be22a7a0a", size = 123030 }, + { url = "https://files.pythonhosted.org/packages/52/59/adcb3e85c9105c59382723a67f682012aa7f49027e270e721f2d59f63fcf/pyinstrument-5.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:70b16b5915534d8df40dcf04a7cc78d3290464c06fa358a4bc324280af4c74e0", size = 123825 }, + { url = "https://files.pythonhosted.org/packages/02/cb/76e92f4069c8e14ed1a154a982c4c08ad8f70ae5e21e9f9a5b8f9ef28f4b/pyinstrument-5.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9bdded62e0a6878a4a061d6cfdd9ec92a1ec1002776688a90f0b5329938a087b", size = 129008 }, + { url = "https://files.pythonhosted.org/packages/ce/d2/b296472da1e25883f919857b1e0394d1bb3829da76ffb56ab58e5ab54eb1/pyinstrument-5.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de3a7b81236f893fb43aa428db9919a1fbc8ccb47c2428ade1fc2a6b96e007ec", size = 121586 }, + { url = "https://files.pythonhosted.org/packages/b3/94/75aad28b763b36259deb287a2d4d5567fb5b7823f200e984ace3b0f9efc8/pyinstrument-5.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed712b88fe6f0dbd4a1966d4254e546545e512dc3b69329c74aded0c7e7baff2", size = 144901 }, + { url = "https://files.pythonhosted.org/packages/ee/40/0efcef4354ab1c9343940d498d8192797fb71afc7e785c753746740f880c/pyinstrument-5.0.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:823d2022c47b8d635f0d8ec6dfd36eb3d50a77abfcabc32aa6d3cdea8eea3fe9", size = 143749 }, + { url = "https://files.pythonhosted.org/packages/ab/34/879361b76fc119f4a62cc1628adaa1a524e40b5186d0c0a9da4a23a17123/pyinstrument-5.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47959cd63cfc0559639199a4a88c871790cd7f0a0f9043057e7408048c035319", size = 145011 }, + { url = "https://files.pythonhosted.org/packages/a9/b9/eb9bf583648225e5c3980b577582b0d71ad336fdc9ff8275cf86651ee1a3/pyinstrument-5.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0e0197702dab98ef7da02a9e1def0b9b04659ac09a67266791b096837d0d3f68", size = 144624 }, + { url = "https://files.pythonhosted.org/packages/55/fe/753581a17ac4a9da29923790f67407a279498e617dac8bc967e0ab5eb532/pyinstrument-5.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:248dc2d016fe935ae7365cd0f83f9d32a7285593f23b703b363c2db9f126983f", size = 144054 }, + { url = "https://files.pythonhosted.org/packages/b0/5b/c096f23b9cac850f52025c9b1b9ac7ca41197dc1498bf2f416c3c5557025/pyinstrument-5.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8f3af11d4219360b89307581ea204fde476c6f5ab91afc932c34655f0974ed6f", size = 144500 }, + { url = "https://files.pythonhosted.org/packages/ff/94/733553e1fc43a8a2e6f39ac84e9861f937911f68dde171b1d3a48439c0ce/pyinstrument-5.0.1-cp39-cp39-win32.whl", hash = "sha256:8f1b7d6d4b9d1ed1b9e222352421a5b080a87b9e6b7cd654b9ba94c5c8266286", size = 122966 }, + { url = "https://files.pythonhosted.org/packages/53/0a/32c7f168f45cf6b7e4c7dfa792a509a82ea66d339352366915da5d8a2b22/pyinstrument-5.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:a876d6f6d6ad7840be62d2eeb8af868d3bf9ab0b023e082a79b22909bce7c755", size = 123842 }, +] + [[package]] name = "pymssql" version = "2.3.2" @@ -516,6 +734,33 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/11/c3/005fcca25ce078d2cc29fd559379817424e94885510568bc1bc53d7d5846/pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725", size = 508002 }, ] +[[package]] +name = "rich" +version = "13.9.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 }, +] + +[[package]] +name = "richbench" +version = "1.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyinstrument" }, + { name = "rich" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9e/5b/d400ecddd716348ff7eac2a40df67cde1c9b60b1f7083577605db4bd4b31/richbench-1.0.3.tar.gz", hash = "sha256:744afa3e78cbd919721042c11f7b7f9d2f546cebb3333d40290c4a0d88791701", size = 1071038 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/a2/725f87821d93f82cba818037fba0b86b14c721d75d4e9935b441ced8471f/richbench-1.0.3-py3-none-any.whl", hash = "sha256:f52651cc0e0069a1355c5ed8cda214cb3f8961e7aaa431e440071d30f62e3e55", size = 5227 }, +] + [[package]] name = "ruff" version = "0.9.3"