From eaf84c68d21a7b0c639c21167945be45b39a7c28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Br=C3=A4uer?= Date: Thu, 2 Jul 2026 09:09:18 +0200 Subject: [PATCH 1/8] Added mdf datasources --- Makefile | 4 +- pyproject.toml | 6 +- src/impulse_ds/__init__.py | 2 + src/impulse_ds/mdf/README.md | 184 ++++ src/impulse_ds/mdf/__init__.py | 55 ++ src/impulse_ds/mdf/arrow_emit.py | 673 +++++++++++++ src/impulse_ds/mdf/bin_packer.py | 376 +++++++ src/impulse_ds/mdf/converter.py | 567 +++++++++++ src/impulse_ds/mdf/datasources.py | 488 ++++++++++ src/impulse_ds/mdf/mdf4_reader.py | 646 ++++++++++++ src/impulse_ds/mdf/mdf_blocks.py | 394 ++++++++ src/impulse_ds/mdf/mdf_decode.py | 364 +++++++ src/impulse_ds/mdf/schemas.py | 29 + src/impulse_ds/mdf/udf_helpers.py | 47 + tests/impulse_ds/__init__.py | 0 tests/impulse_ds/mdf/__init__.py | 0 tests/impulse_ds/mdf/_mdf_samples.py | 87 ++ tests/impulse_ds/mdf/test_datasources.py | 443 +++++++++ tests/impulse_ds/mdf/test_mdf4_reader.py | 394 ++++++++ tests/impulse_ds/mdf/test_telemetry.py | 85 ++ uv.lock | 1134 ++++++++++++---------- 21 files changed, 5463 insertions(+), 515 deletions(-) create mode 100644 src/impulse_ds/__init__.py create mode 100644 src/impulse_ds/mdf/README.md create mode 100644 src/impulse_ds/mdf/__init__.py create mode 100644 src/impulse_ds/mdf/arrow_emit.py create mode 100644 src/impulse_ds/mdf/bin_packer.py create mode 100644 src/impulse_ds/mdf/converter.py create mode 100644 src/impulse_ds/mdf/datasources.py create mode 100644 src/impulse_ds/mdf/mdf4_reader.py create mode 100644 src/impulse_ds/mdf/mdf_blocks.py create mode 100644 src/impulse_ds/mdf/mdf_decode.py create mode 100644 src/impulse_ds/mdf/schemas.py create mode 100644 src/impulse_ds/mdf/udf_helpers.py create mode 100644 tests/impulse_ds/__init__.py create mode 100644 tests/impulse_ds/mdf/__init__.py create mode 100644 tests/impulse_ds/mdf/_mdf_samples.py create mode 100644 tests/impulse_ds/mdf/test_datasources.py create mode 100644 tests/impulse_ds/mdf/test_mdf4_reader.py create mode 100644 tests/impulse_ds/mdf/test_telemetry.py diff --git a/Makefile b/Makefile index 12be2605..491a50e4 100644 --- a/Makefile +++ b/Makefile @@ -10,14 +10,14 @@ endif # Ensure that build-system requires are hash-verified when building. export UV_BUILD_CONSTRAINT := .build-constraints.txt -UV_RUN := uv run --exact --all-extras +UV_RUN := uv run --exact --all-extras --group test clean: rm -fr .venv htmlcov .pytest_cache .ruff_cache .coverage coverage.xml test-results.xml find . -name '__pycache__' -print0 | xargs -0 rm -fr dev: - uv sync --all-extras + uv sync --all-extras --group test lint: $(UV_RUN) black --check src/ tests/ diff --git a/pyproject.toml b/pyproject.toml index 51ce3249..38000104 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,6 +54,10 @@ dev = [ "setuptools==75.8.2", "black==26.3.1" ] +# Test-only deps (not installed with the published wheel or local-dev extras). +test = [ + "asammdf==8.0.1", +] # Setuptools options [tool.setuptools.dynamic] @@ -134,7 +138,7 @@ ignore = [ convention = "numpy" [tool.ruff.lint.isort] -known-first-party = ["impulse_query_engine", "impulse_reporting"] +known-first-party = ["impulse_query_engine", "impulse_reporting", "impulse_ds"] [tool.black] line-length = 99 diff --git a/src/impulse_ds/__init__.py b/src/impulse_ds/__init__.py new file mode 100644 index 00000000..1f55ac7d --- /dev/null +++ b/src/impulse_ds/__init__.py @@ -0,0 +1,2 @@ +# https://packaging.python.org/en/latest/guides/packaging-namespace-packages/#pkgutil-style-namespace-packages +__path__ = __import__("pkgutil").extend_path(__path__, __name__) diff --git a/src/impulse_ds/mdf/README.md b/src/impulse_ds/mdf/README.md new file mode 100644 index 00000000..0dd4d9e3 --- /dev/null +++ b/src/impulse_ds/mdf/README.md @@ -0,0 +1,184 @@ +# impulse_ds.mdf + +Convert ASAM **MDF4** measurement files to **Delta Lake** tables with PySpark / +Databricks. The reader parses MDF4 binary blocks directly (no `asammdf` at +runtime), so conversion parallelises across Spark workers, each reading only the +bytes for its partition. + +Every output row is identified by **`file_uri`** — the source file path. + +## Two ways to use it + +### 1. Custom Spark data sources (read MDF4 as DataFrames) + +Requires the wheel installed on the cluster (the registered data-source workers +import the package). + +```python +from databricks.sdk import WorkspaceClient +from impulse_ds.mdf import register_mdf_datasources + +register_mdf_datasources(spark, WorkspaceClient()) + +signals = spark.read.format("mdf_signals").option("path", "/Volumes/.../mdf").load() +# discovers every *.mf4 under /Volumes/.../mdf, including subdirectories +``` + +**File selection** (`path` / `files` — shared by all three formats): + +| behaviour | example | +|---|---| +| Recursive scan (default) | `.option("path", "/Volumes/.../mdf").load()` | +| Relative paths under `path` | `.option("path", "/data").option("files", "batch_a/run.mf4,run_b/other.mf4")` | +| Absolute file URIs (no scan) | `.option("path", "/data").option("files", "/mnt/a.mf4,/mnt/b.mf4")` | + +When `files` is set, only the listed paths are read. Each entry may be absolute or +relative to `path`; a mix of both in one list is allowed. + +#### Output schemas + +##### `mdf_signals` + +One row per sample (default), or one row per constant-value interval when +`run_length_encoding=true`. `time` / `tstart` / `tend` follow `time_dtype` +(`float64` or `float32`); `absolute_time=true` forces time columns to `float64`. +`value` follows `value_dtype` independently. + +| column | Spark type | nullable | notes | +|---|---|---|---| +| `file_uri` | `string` | no | source `.mf4` path | +| `channel_id` | `int` | no | sequential signal id within the file | +| `time` | `double` or `float` | no | sample timestamp (relative seconds, or epoch seconds with `absolute_time`) | +| `value` | `double` or `float` | yes | decoded channel value | + +With `run_length_encoding=true`, `time` is replaced by: + +| column | Spark type | nullable | notes | +|---|---|---|---| +| `tstart` | `double` or `float` | no | start of a constant-value interval (inclusive) | +| `tend` | `double` or `float` | no | end of the interval (exclusive), except the terminal point row where `tstart = tend` | + +##### `mdf_metadata` + +One row per signal channel. Schema is fixed (not affected by `time_dtype` / RLE options). + +| column | Spark type | nullable | notes | +|---|---|---|---| +| `file_uri` | `string` | no | source `.mf4` path | +| `channel_id` | `int` | no | sequential signal id within the file | +| `group_idx` | `int` | no | MDF channel-group index | +| `channel_idx` | `int` | no | channel index within the group | +| `channel_name` | `string` | no | CN block name | +| `unit` | `string` | yes | physical unit, if present | +| `header_datetime` | `timestamp` | yes | measurement start time from the HD block (UTC) | +| `md_comment` | `string` | yes | CN comment block (`##MD` XML or `##TX` text), if present | + +##### `mdf_masters` + +One row per **original** master-channel sample — the time base of each acquisition +group. Used with RLE-encoded `mdf_signals` to recover the full per-sample grid. +`timestamp` follows `time_dtype` (`float64` or `float32`); `absolute_time=true` +forces `float64`. + +| column | Spark type | nullable | notes | +|---|---|---|---| +| `file_uri` | `string` | no | source `.mf4` path | +| `group_idx` | `int` | no | MDF channel-group index (matches `mdf_metadata.group_idx`) | +| `timestamp` | `double` or `float` | no | master time for one sample (relative seconds, or epoch seconds with `absolute_time`) | + +**Shared options** (`mdf_signals`, `mdf_metadata`, `mdf_masters`): + +| option | default | meaning | +|---|---|---| +| `path` | — (required) | root directory; used for recursive discovery and as the base for relative `files` entries | +| `files` | all `*.mf4` under `path` | comma-separated file list; each entry may be an absolute path or relative to `path`. When set, only these files are read (no directory scan) | + +**`mdf_signals` / `mdf_masters` options** (in addition to the shared options above): + +| option | default | meaning | +|---|---|---| +| `target_partition_mb` | 64 | target output size per Spark task | +| `partitioning` | `group` | `group` (per-channel-group) or `stripe` (byte-offset; reads each file once to build a block map) | +| `stripe_target_mb` | 128 | compressed bytes per stripe (stripe mode) | +| `max_groups_per_partition` | 64 | cap on small groups coalesced into one task | +| `time_dtype` / `value_dtype` | `float64` | `float32` halves a column's on-disk size | +| `run_length_encoding` | `false` | collapse constant runs into `[tstart, tend)` intervals (+ a terminal point row per channel) | +| `absolute_time` | `false` | add the MDF start time so timestamps are UTC epoch seconds (forces the time columns to `float64`) | + +> Reverse RLE: join RLE intervals against `mdf_masters` timestamps — +> `t >= tstart AND (t < tend OR (tstart = tend AND t = tstart))` — using the same +> `time_dtype`/`absolute_time` on both sources. + +#### Telemetry + +Call `register_mdf_datasources(spark, ws)` instead of registering the three data +source classes manually. It verifies the workspace client, tags API calls with +`databricks-impulse` product info, and emits a lightweight telemetry beacon +(`mdf` → `mdf_signals` / `mdf_metadata` / `mdf_masters`) each time Spark plans +partitions for a read. If the data sources are registered without +`register_mdf_datasources`, reads still work but no telemetry is sent. + +### 2. The high-level converter (writes the Delta tables) + +Also works over Databricks Connect (no cluster install needed — uses the +`mapInArrow` path with shipped artifacts). + +```python +from impulse_ds.mdf import MDFToDeltaConverter +conv = MDFToDeltaConverter( + spark, + signals_table="cat.sch.signals", # CLUSTER BY (file_uri, channel_id) + metadata_table="cat.sch.metadata", # CLUSTER BY file_uri + target_partition_mb=64, + time_dtype="float32", value_dtype="float32", + run_length_encoding=False, +) +conv.convert("/Volumes/.../drive.mf4") # one file +conv.convert_batch(["/Volumes/.../a.mf4", ...]) # many files, sequential +``` + +### Low-level reader + +```python +from impulse_ds.mdf import MDF4Reader +r = MDF4Reader("/path/drive.mf4") # or MDF4Reader(file_bytes=blob) +org = r.scan_channels_organized() # masters / signals / channel_id_map +r.read_header_datetime() # measurement start (UTC) +``` + +## Module layout + +Package path: `src/impulse_ds/mdf/` + +| module | responsibility | +|---|---| +| `mdf4_reader.py` | parse MDF4 structure (HD/DG/CG/CN) → `ChannelInfo`; header datetime | +| `mdf_blocks.py` | low-level data-block I/O (`##DT`/`##DZ`/`##DL`/`##HL`, sub-blocks) | +| `mdf_decode.py` | raw-bytes → values/timestamps (data types, CC conversion, invalidation) | +| `arrow_emit.py` | build Arrow batches (per-group, stripe, master) + run-length encoding | +| `udf_helpers.py` | re-export shim over the three modules above (stable import surface) | +| `bin_packer.py` | partition planning (`plan_partitions`, `plan_stripes_for_file`, `plan_master_partitions`) | +| `converter.py` | `MDFToDeltaConverter` orchestration + Delta writes | +| `datasources.py` | the three Spark data sources | +| `schemas.py` | shared Spark schemas (`SIGNALS_SCHEMA`, `METADATA_SCHEMA`) | + +## Limitations (backlog) + +Known gaps in the numeric-first reader/converter. **Sorted** data groups (`rec_id_size = 0`) +and CC types 0–2, 4–6 work as expected. + +| area | severity | status | +|---|---|---| +| **Unsorted data groups** — metadata scan records `rec_id_size` / `record_id` and offsets channel fields past the record-id prefix, but read paths (`read_channel_pair`, `arrow_emit`, converter UDF) still treat every record in a shared data block as belonging to one CG. For `rec_id_size > 0`, interleaved records are not filtered → wrong values. `rec_id_size` / `record_id` are also not passed through partition specs today. | MEDIUM | metadata only | +| **VLSD channels** — variable-length signals store an offset in the fixed record; payload in SDBLOCK is not followed. Channels currently emit NaN. String/byte output would need schema changes. | MEDIUM | not implemented | +| **CC type 3 (algebraic / formula)** — formula text in `cc_ref[0]` (TXBLOCK) is not read or evaluated; `apply_cc_conversion` has no handler for type 3. | LOW–MEDIUM | not implemented | +| **CC types 7–10 (text conversions)** — require TXBLOCK / `cc_ref` resolution. Unsupported by design for the numeric-only `value` column; `_parse_cc_block` returns `(-1, ())` for `cc_type > 6`. | LOW | not implemented (by design) | + +**CC types 7–10:** types 7, 8, 10 produce text (need a string extraction path / separate table); type 9 (text→value) could stay numeric but needs reference-text matching. + +**Unsorted DGs:** fix requires per-CG record filtering in `mdf_decode` / `arrow_emit` / converter UDF, plus `rec_id_size`, `record_id`, and per-DG CG record sizes in partition specs. + +## Dependencies + +- Runtime: `numpy`, `pyarrow` (`pyspark` is provided by the Databricks runtime). +- Tests: `pytest`, `asammdf` (dev/test dependency only — synthesises small MDF4 files on the fly). diff --git a/src/impulse_ds/mdf/__init__.py b/src/impulse_ds/mdf/__init__.py new file mode 100644 index 00000000..73df758f --- /dev/null +++ b/src/impulse_ds/mdf/__init__.py @@ -0,0 +1,55 @@ +""" +MDF4 → Delta Lake converter for PySpark / Databricks. + +Reads ASAM MDF4 measurement files directly from their binary blocks (no +asammdf dependency at runtime) and converts them to long-format Delta tables, +parallelised across Spark workers. + +Public API (lazy-loaded to avoid importing PySpark unless needed):: + + from impulse_ds.mdf import ( + MDFToDeltaConverter, + MDF4Reader, + register_mdf_datasources, + MdfSignalsDataSource, + MdfMetadataDataSource, + MdfMastersDataSource, + ) +""" + +__all__ = [ + "MDFToDeltaConverter", + "MDF4Reader", + "register_mdf_datasources", + "MdfSignalsDataSource", + "MdfMetadataDataSource", + "MdfMastersDataSource", +] + + +def __getattr__(name): + if name == "MDFToDeltaConverter": + from .converter import MDFToDeltaConverter + + return MDFToDeltaConverter + if name == "MDF4Reader": + from .mdf4_reader import MDF4Reader + + return MDF4Reader + if name == "register_mdf_datasources": + from .datasources import register_mdf_datasources + + return register_mdf_datasources + if name in ("MdfSignalsDataSource", "MdfMetadataDataSource", "MdfMastersDataSource"): + from .datasources import ( + MdfMetadataDataSource, + MdfMastersDataSource, + MdfSignalsDataSource, + ) + + return { + "MdfSignalsDataSource": MdfSignalsDataSource, + "MdfMetadataDataSource": MdfMetadataDataSource, + "MdfMastersDataSource": MdfMastersDataSource, + }[name] + raise AttributeError(f"module 'impulse_ds.mdf' has no attribute {name!r}") diff --git a/src/impulse_ds/mdf/arrow_emit.py b/src/impulse_ds/mdf/arrow_emit.py new file mode 100644 index 00000000..5b721043 --- /dev/null +++ b/src/impulse_ds/mdf/arrow_emit.py @@ -0,0 +1,673 @@ +""" +Build PyArrow RecordBatches from MDF4 partition specs — the executor-side decode +core shared by both the mapInArrow converter and the custom data sources. + +Three entry points emit the public output schemas: + - convert_spec_to_arrow_batches -> signals (per channel group) + - convert_stripe_spec_to_arrow_batches -> signals (byte-offset stripe) + - convert_master_spec_to_arrow_batches -> per-group master time base + +plus run-length encoding (collapse constant runs into [tstart, tend) intervals). +""" +import numpy as np + +from .mdf_blocks import ( + dt_data_extent, resolve_dl_addr, read_data_list_range, read_raw_data, + _decompress_subblock_blob, _read_block_chunks, +) +from .mdf_decode import extract_signal, extract_timestamps + + +def _pa_float(dtype): + import pyarrow as pa + return pa.float32() if str(dtype) == "float32" else pa.float64() + + +def _np_float(dtype): + return np.float32 if str(dtype) == "float32" else np.float64 + + +def _eq_nan(a, b): + """Value equality for run-length encoding, treating NaN == NaN as equal so + consecutive invalid samples collapse into a single run.""" + return a == b or (a != a and b != b) + + +def _rle_run_starts(vs): + """Indices at which a new run begins in `vs` (value differs from predecessor; + NaN is considered equal to NaN). Always includes index 0.""" + n = len(vs) + if n <= 1: + return np.zeros(n, dtype=np.int64) + neq = vs[1:] != vs[:-1] + nan_both = np.isnan(vs[1:]) & np.isnan(vs[:-1]) + change = neq & ~nan_both + return np.concatenate(([0], np.nonzero(change)[0] + 1)).astype(np.int64) + + +def _rle_compress_chunk(ts, vs, carry): + """Run-length-encode one time-ordered (ts, vs) chunk for a SINGLE channel, + merging with the trailing run carried over from the previous chunk. + + Uses a zero-order hold: a run holding value v from ts[s] ends when the value + next changes, so its tend is the start time of the following run. The final + run of the whole channel stays open (its tend is only known once a later + sample arrives, or, at flush, falls back to the last sample's own time). + + Returns (closed, new_carry): + closed = (tstart_arr, tend_arr, value_arr) of fully-determined runs, + or None if this chunk produced no closed runs yet. + new_carry = [value, tstart, last_ts] describing the still-open trailing + run (fed back in on the next chunk, or flushed at the end). + """ + n = len(vs) + if n == 0: + return None, carry + starts = _rle_run_starts(vs) + run_vals = vs[starts] + run_t0 = ts[starts] + m = len(starts) + last_ts = ts[n - 1] + + seg_t0, seg_t1, seg_v = [], [], [] + first_t0 = run_t0[0] + if carry is not None: + c_val, c_t0, _c_last = carry + if _eq_nan(c_val, run_vals[0]): + # The open run continues into this chunk: keep its original start. + first_t0 = c_t0 + else: + # Value changed at this chunk's first sample: close the carried run + # there (zero-order hold to the change point). + seg_t0.append(np.array([c_t0])); seg_t1.append(np.array([ts[0]])) + seg_v.append(np.array([c_val])) + + if m >= 2: + t0 = run_t0[:m - 1].copy() + t0[0] = first_t0 + seg_t0.append(t0) + seg_t1.append(run_t0[1:m]) # tend = start of the next run + seg_v.append(run_vals[:m - 1]) + new_carry = [run_vals[m - 1], run_t0[m - 1], last_ts] + else: + # Whole chunk is a single run; it remains open. + new_carry = [run_vals[0], first_t0, last_ts] + + if seg_v: + return (np.concatenate(seg_t0), np.concatenate(seg_t1), + np.concatenate(seg_v)), new_carry + return None, new_carry + + +def _rle_flush(carry): + """Close the final open run. Runs are half-open [tstart, tend); the final + sample sits exactly on the trailing boundary, so it is emitted as an extra + zero-width POINT row with tstart == tend == last timestamp. This guarantees + every original sample (including the last) is recoverable — a consumer + re-expanding with `t >= tstart AND t < tend` also accepts a point row via + `tstart == tend AND t == tstart`. + + Returns (tstart_arr, tend_arr, value_arr) or None: + - multi-sample final run -> [c_t0, c_last) held interval + [c_last, c_last] point + - single-sample final run -> just the [c_last, c_last] point (already a point) + """ + if carry is None: + return None + c_val, c_t0, c_last = carry + if c_t0 < c_last: + return (np.array([c_t0, c_last]), np.array([c_last, c_last]), + np.array([c_val, c_val])) + return np.array([c_last]), np.array([c_last]), np.array([c_val]) + + +def signals_arrow_schema(time_dtype="float64", value_dtype="float64", + run_length_encoding=False): + """Arrow schema for emitted signal batches. time/value default to float64 but + can be float32 (halves their on-disk bytes) per the data-source options. + value is nullable to accept NaN/None invalid samples. + + With run_length_encoding the per-sample `time` column is replaced by the + [`tstart`, `tend`) half-open interval over which the (run-length-collapsed) + value holds. Each channel also ends with a zero-width point row + (tstart == tend == last timestamp) so the final sample is recoverable. + """ + import pyarrow as pa + if run_length_encoding: + return pa.schema([ + pa.field("file_uri", pa.string(), nullable=False), + pa.field("channel_id", pa.int32(), nullable=False), + pa.field("tstart", _pa_float(time_dtype), nullable=False), + pa.field("tend", _pa_float(time_dtype), nullable=False), + pa.field("value", _pa_float(value_dtype), nullable=True), + ]) + return pa.schema([ + pa.field("file_uri", pa.string(), nullable=False), + pa.field("channel_id", pa.int32(), nullable=False), + pa.field("time", _pa_float(time_dtype), nullable=False), + pa.field("value", _pa_float(value_dtype), nullable=True), + ]) + + +def master_arrow_schema(time_dtype="float64"): + """Arrow schema for the master time-base output: one row per ORIGINAL sample + of each group's master channel (file_uri, group_idx, timestamp).""" + import pyarrow as pa + return pa.schema([ + pa.field("file_uri", pa.string(), nullable=False), + pa.field("group_idx", pa.int32(), nullable=False), + pa.field("timestamp", _pa_float(time_dtype), nullable=False), + ]) + + +def _make_signal_emitters(file_uri, output_schema, pa_time, pa_value, + np_time, np_value, run_length_encoding, prof, + max_batch_rows=2_000_000): + """Build the ``(emit_fn, flush_fn)`` pair shared by the per-group and + stripe signal converters, so both inherit identical batching/RLE behaviour. + + emit_fn(timestamps, values, channel_id) -> iterator[pyarrow.RecordBatch] + flush_fn() -> iterator[pyarrow.RecordBatch] + + Both close over a cached, full-width ``file_uri`` constant column (the + source path repeated for every row — the row identifier — built once and + sliced per batch), the float dtypes, and the ``prof`` accumulator, and cap + each output batch at ``max_batch_rows`` rows. + + Without RLE, emit_fn yields per-sample (file_uri, channel_id, time, value) + batches and flush_fn is a no-op. With RLE, emit_fn collapses consecutive + equal samples into [tstart, tend] interval rows (zero-order hold), carrying + one open trailing run per channel across the internal chunks of a partition + /stripe; flush_fn drains those trailing runs (incl. the terminal + zero-width point row per channel).""" + import time + import pyarrow as pa + _now = time.perf_counter_ns + + uri_cache = [] + + def _uri_const(): + if not uri_cache: + uri_cache.append( + pa.array(np.full(max_batch_rows, file_uri, dtype=object), type=pa.string())) + return uri_cache[0] + + def _emit_points(timestamps, values, channel_id): + n = len(values) + if n == 0: + return + cont_full = _uri_const() + t0 = _now() + chan_full = pa.array(np.full(min(n, max_batch_rows), channel_id, dtype=np.int32), + type=pa.int32()) + prof["arrow"] += _now() - t0 + for offset in range(0, n, max_batch_rows): + end = min(offset + max_batch_rows, n) + clen = end - offset + t1 = _now() + ts = timestamps[offset:end] + vs = values[offset:end] + if np_time is np.float32: + ts = ts.astype(np.float32) + if np_value is np.float32: + vs = vs.astype(np.float32) + rb = pa.RecordBatch.from_arrays( + [cont_full.slice(0, clen), chan_full.slice(0, clen), + pa.array(ts, type=pa_time), pa.array(vs, type=pa_value)], + schema=output_schema) + prof["arrow"] += _now() - t1 + prof["rows"] += clen + yield rb + + if not run_length_encoding: + return _emit_points, (lambda: iter(())) + + rle_state = {} # channel_id -> open trailing run carried between chunks + + def _emit_rle_batch(t0arr, t1arr, varr, channel_id): + n = len(varr) + if n == 0: + return + cont_full = _uri_const() + for offset in range(0, n, max_batch_rows): + end = min(offset + max_batch_rows, n) + clen = end - offset + _ta = _now() + t0 = t0arr[offset:end]; te = t1arr[offset:end]; vv = varr[offset:end] + if np_time is np.float32: + t0 = t0.astype(np.float32); te = te.astype(np.float32) + if np_value is np.float32: + vv = vv.astype(np.float32) + chan_full = pa.array(np.full(clen, channel_id, dtype=np.int32), type=pa.int32()) + rb = pa.RecordBatch.from_arrays( + [cont_full.slice(0, clen), chan_full, + pa.array(t0, type=pa_time), pa.array(te, type=pa_time), + pa.array(vv, type=pa_value)], + schema=output_schema) + prof["arrow"] += _now() - _ta + prof["rows"] += clen + yield rb + + def emit_fn(timestamps, values, channel_id): + closed, new_carry = _rle_compress_chunk(timestamps, values, rle_state.get(channel_id)) + rle_state[channel_id] = new_carry + if closed is not None: + yield from _emit_rle_batch(closed[0], closed[1], closed[2], channel_id) + + def flush_fn(): + for channel_id, carry in rle_state.items(): + out = _rle_flush(carry) + if out is not None: + yield from _emit_rle_batch(out[0], out[1], out[2], channel_id) + rle_state.clear() + + return emit_fn, flush_fn + + +def convert_spec_to_arrow_batches(spec, prof=None, time_dtype="float64", value_dtype="float64", + run_length_encoding=False): + """ + Convert ONE partition spec into an iterator of pyarrow.RecordBatch with the + signals schema (file_uri, channel_id, time, value). + + This is the single shared Arrow conversion core used by BOTH the mapInArrow + UDF (converter._convert_partition_arrow) and the 'mdf_signals' custom data + source (datasources.MdfSignalsReader.read), so both inherit the same + optimizations: stream uncompressed DT blocks in record-aligned chunks to + bound memory, fall back to whole-block reads for DL/DZ/HL, reuse a cached + file_uri constant column, and cap output batches at _MAX_BATCH_ROWS rows. + + spec: dict with keys file_path, channels (list of channel specs). + prof: optional mutable dict accumulating {read, decode, arrow, rows} nanoseconds. + + run_length_encoding: when True, collapse consecutive equal samples of a + channel into one row spanning [tstart, tend] (the interval over which the + value stays constant, zero-order hold), emitting the + (file_uri, channel_id, tstart, tend, value) schema instead. Runs are + merged across the internal read/output chunks of a partition; note that + because the planner may split one channel group into several record-range + partitions, runs that straddle a partition boundary are not merged across + partitions (at most one extra row per boundary per channel). + """ + import time + import logging + + log = logging.getLogger("impulse_ds.mdf.convert") + _now = time.perf_counter_ns + if prof is None: + prof = {"read": 0, "decode": 0, "arrow": 0, "rows": 0} + + output_schema = signals_arrow_schema(time_dtype, value_dtype, run_length_encoding) + pa_time, pa_value = _pa_float(time_dtype), _pa_float(value_dtype) + np_time, np_value = _np_float(time_dtype), _np_float(value_dtype) + + # Coarse read chunk for I/O efficiency (bounds memory for huge DT blocks); + # output batch sizing is independent (see _make_signal_emitters) so a small + # record_size cannot produce a huge single batch. + _CHUNK_BYTES = 256 * 1024 * 1024 + + file_path = spec["file_path"] + file_uri = file_path + channels_spec = spec["channels"] + # Optional record-range slice (set by the planner for deep DT groups so a + # single channel group is processed by many parallel tasks). Applies to the + # DT fast path only; all channels in such a spec belong to one DT block. + spec_row_start = spec.get("row_start") + spec_row_end = spec.get("row_end") + + # Absolute-time offset (epoch seconds, UTC) added to every timestamp when the + # planner baked one in (absolute_time option). 0.0 => relative times unchanged. + time_offset = float(spec.get("time_offset", 0.0)) + + # Emission dispatch (shared with the stripe converter): per-sample batches, + # or run-length-encoded interval rows. flush_fn() drains any state held back + # between read chunks (only RLE carries a trailing open run). + emit_fn, flush_fn = _make_signal_emitters( + file_uri, output_schema, pa_time, pa_value, np_time, np_value, + run_length_encoding, prof) + + block_groups = {} + for ch_spec in channels_spec: + if ch_spec["sample_count"] == 0: + continue + block_groups.setdefault(ch_spec["data_block_addr"], []).append(ch_spec) + + with open(file_path, "rb") as f: + for data_block_addr, group_channels in block_groups.items(): + record_size = group_channels[0]["record_size"] + sample_count = group_channels[0]["sample_count"] + master_info = group_channels[0].get("master_info") + + try: + extent = dt_data_extent(f, data_block_addr) + except Exception as e: + log.warning("DT extent probe failed at %d in %s: %s", + data_block_addr, file_path, e) + extent = None + + if extent is not None: + # Fast path: stream the contiguous DT block in record-aligned chunks. + data_start, data_size = extent + total_records = data_size // record_size if record_size else 0 + if total_records == 0: + continue + # Honor the planner's record-range slice (defaults to whole block). + lo = 0 if spec_row_start is None else max(0, min(spec_row_start, total_records)) + hi = total_records if spec_row_end is None else max(lo, min(spec_row_end, total_records)) + if hi <= lo: + continue + chunk_records = max(1, _CHUNK_BYTES // record_size) + for rec0 in range(lo, hi, chunk_records): + recN = min(rec0 + chunk_records, hi) + nrec = recN - rec0 + t0 = _now() + f.seek(data_start + rec0 * record_size) + raw_chunk = f.read(nrec * record_size) + prof["read"] += _now() - t0 + actual = len(raw_chunk) // record_size + if actual == 0: + continue + t0 = _now() + if master_info is not None: + timestamps = extract_timestamps( + raw_chunk, record_size, master_info, index_offset=rec0, + ) + else: + timestamps = np.arange(rec0, rec0 + actual, dtype=np.float64) + if time_offset: + timestamps = timestamps + time_offset + prof["decode"] += _now() - t0 + for ch_spec in group_channels: + try: + t0 = _now() + values = extract_signal(raw_chunk, record_size, ch_spec) + prof["decode"] += _now() - t0 + if values is None: + continue + yield from emit_fn( + timestamps, values, ch_spec["channel_id"], + ) + except Exception as e: + log.warning("extract failed ch=%s block=%d: %s", + ch_spec.get("channel_id"), data_block_addr, e) + continue + continue + + # ##DL/##HL with a planner record-range slice: read only the + # sub-blocks overlapping [row_start, row_end). This lets many tasks + # split one compressed channel group with no redundant decompression. + if spec_row_start is not None: + dl_addr = resolve_dl_addr(f, data_block_addr) + if dl_addr is not None: + re_hi = spec_row_end if spec_row_end is not None else (1 << 62) + t0 = _now() + raw_data, start_rec = read_data_list_range( + f, dl_addr, record_size, spec_row_start, re_hi, + ) + prof["read"] += _now() - t0 + actual = len(raw_data) // record_size if record_size else 0 + if actual == 0: + continue + t0 = _now() + if master_info is not None: + timestamps = extract_timestamps( + raw_data, record_size, master_info, index_offset=start_rec, + ) + else: + timestamps = np.arange(start_rec, start_rec + actual, dtype=np.float64) + if time_offset: + timestamps = timestamps + time_offset + prof["decode"] += _now() - t0 + for ch_spec in group_channels: + try: + t0 = _now() + values = extract_signal(raw_data, record_size, ch_spec) + prof["decode"] += _now() - t0 + if values is None: + continue + yield from emit_fn( + timestamps, values, ch_spec["channel_id"], + ) + except Exception as e: + log.warning("extract failed ch=%s block=%d: %s", + ch_spec.get("channel_id"), data_block_addr, e) + continue + continue + + # Fallback: standalone ##DZ / unknown blocks read whole. If the + # planner assigned this partition a record range (it splits large + # groups blindly, without peeking block type), slice the whole block + # to that range so range partitions don't duplicate rows. + try: + t0 = _now() + raw_data = read_raw_data(f, data_block_addr, record_size, sample_count) + prof["read"] += _now() - t0 + except Exception as e: + log.warning("read_raw_data failed at %d in %s: %s", + data_block_addr, file_path, e) + continue + total = len(raw_data) // record_size if record_size else 0 + if total == 0: + continue + if spec_row_start is not None: + lo = max(0, min(spec_row_start, total)) + hi = total if spec_row_end is None else max(lo, min(spec_row_end, total)) + raw_data = raw_data[lo * record_size:hi * record_size] + start_rec = lo + else: + start_rec = 0 + actual = len(raw_data) // record_size + if actual == 0: + continue + t0 = _now() + if master_info is not None: + timestamps = extract_timestamps( + raw_data, record_size, master_info, index_offset=start_rec) + else: + timestamps = np.arange(start_rec, start_rec + actual, dtype=np.float64) + if time_offset: + timestamps = timestamps + time_offset + prof["decode"] += _now() - t0 + for ch_spec in group_channels: + try: + t0 = _now() + values = extract_signal(raw_data, record_size, ch_spec) + prof["decode"] += _now() - t0 + if values is None: + continue + yield from emit_fn( + timestamps, values, ch_spec["channel_id"], + ) + except Exception as e: + log.warning("extract failed ch=%s block=%d: %s", + ch_spec.get("channel_id"), data_block_addr, e) + continue + + # Drain state held across read chunks (RLE keeps one open trailing run + # per channel; the per-sample path holds nothing, so this is a no-op). + yield from flush_fn() + + +def convert_master_spec_to_arrow_batches(spec, prof=None, time_dtype="float64"): + """Convert ONE master spec into a pyarrow.RecordBatch iterator with schema + (file_uri, group_idx, timestamp): the ORIGINAL per-sample timestamps of + each acquisition group's master channel, one row per sample. + + Stored alongside run-length-encoded signals so the original sample grid can + be reconstructed ("reverse RLE"): every signal in group g held value v over + [tstart, tend], so re-expanding it means assigning v to each of this table's + group-g timestamps that fall within that interval. + + spec: dict with keys file_path, time_dtype, masters (list of + {group_idx, data_block_addr, record_size, sample_count, master_info}) and an + optional whole-spec row_start/row_end (set only for single-master record-range + splits of a large group). + """ + import time + import logging + import pyarrow as pa + + log = logging.getLogger("impulse_ds.mdf.convert") + _now = time.perf_counter_ns + if prof is None: + prof = {"read": 0, "decode": 0, "arrow": 0, "rows": 0} + + output_schema = master_arrow_schema(time_dtype) + pa_time = _pa_float(time_dtype) + np_time = _np_float(time_dtype) + _MAX_BATCH_ROWS = 2_000_000 + + file_path = spec["file_path"] + file_uri = file_path + masters = spec["masters"] + r0 = spec.get("row_start") + r1 = spec.get("row_end") + time_offset = float(spec.get("time_offset", 0.0)) + + _uri_full_cache = [] + + def _uri_const(): + if not _uri_full_cache: + _uri_full_cache.append( + pa.array(np.full(_MAX_BATCH_ROWS, file_uri, dtype=object), type=pa.string())) + return _uri_full_cache[0] + + def _emit(ts, group_idx): + n = len(ts) + if n == 0: + return + cont_full = _uri_const() + for off in range(0, n, _MAX_BATCH_ROWS): + end = min(off + _MAX_BATCH_ROWS, n) + clen = end - off + t0 = _now() + seg = ts[off:end] + if np_time is np.float32: + seg = seg.astype(np.float32) + grp = pa.array(np.full(clen, group_idx, dtype=np.int32), type=pa.int32()) + rb = pa.RecordBatch.from_arrays( + [cont_full.slice(0, clen), grp, pa.array(seg, type=pa_time)], + schema=output_schema, + ) + prof["arrow"] += _now() - t0 + prof["rows"] += clen + yield rb + + with open(file_path, "rb") as f: + for mspec in masters: + rs = mspec["record_size"] + if not rs: + continue + gid = mspec["group_idx"] + minfo = mspec["master_info"] + sc = mspec["sample_count"] + + # Virtual master: timestamps ARE the sample index — no block read. + if minfo.get("channel_type") == 3: + lo = 0 if r0 is None else max(0, min(r0, sc)) + hi = sc if r1 is None else max(lo, min(r1, sc)) + if hi > lo: + t0 = _now() + ts = np.arange(lo, hi, dtype=np.float64) + if time_offset: + ts = ts + time_offset + prof["decode"] += _now() - t0 + yield from _emit(ts, gid) + continue + + for raw, start in _read_block_chunks( + f, mspec["data_block_addr"], rs, sc, r0, r1, prof, log): + t0 = _now() + ts = extract_timestamps(raw, rs, minfo, index_offset=start) + if time_offset: + ts = ts + time_offset + prof["decode"] += _now() - t0 + yield from _emit(ts, gid) + + +def convert_stripe_spec_to_arrow_batches(spec, prof=None, time_dtype="float64", + value_dtype="float64", run_length_encoding=False): + """Decode ONE byte-offset stripe (Design B): a contiguous file region holding + a set of data sub-blocks from possibly several groups. The whole region is read + in ONE sequential IO, then each sub-block is decompressed + extracted from RAM. + + spec keys: file_path, byte_start, byte_end, time_dtype, + value_dtype, run_length_encoding, time_offset, + groups: {str(group_key): {record_size, master_info, channels:[ch_dicts]}}, + subblocks: [{grp, abs_off, on_disk_len, rec_start, rec_count}]. + + Emits the SAME schema as convert_spec_to_arrow_batches (signals, or the RLE + variant), so it is a drop-in alternative read path. + """ + import time + import logging + + log = logging.getLogger("impulse_ds.mdf.convert") + _now = time.perf_counter_ns + if prof is None: + prof = {"read": 0, "decode": 0, "arrow": 0, "rows": 0} + + output_schema = signals_arrow_schema(time_dtype, value_dtype, run_length_encoding) + pa_time, pa_value = _pa_float(time_dtype), _pa_float(value_dtype) + np_time, np_value = _np_float(time_dtype), _np_float(value_dtype) + + file_path = spec["file_path"] + file_uri = file_path + byte_start = spec["byte_start"] + byte_end = spec["byte_end"] + groups = spec["groups"] + subblocks = spec["subblocks"] + time_offset = float(spec.get("time_offset", 0.0)) + + # Same emission dispatch as convert_spec_to_arrow_batches (per-sample or RLE). + emit_fn, flush_fn = _make_signal_emitters( + file_uri, output_schema, pa_time, pa_value, np_time, np_value, + run_length_encoding, prof) + + # One sequential read of the whole stripe. + t0 = _now() + with open(file_path, "rb") as f: + f.seek(byte_start) + blob = f.read(byte_end - byte_start) + prof["read"] += _now() - t0 + + by_grp = {} + for sb in subblocks: + by_grp.setdefault(sb["grp"], []).append(sb) + + for grp, subs in by_grp.items(): + meta = groups[str(grp)] + record_size = meta["record_size"] + master_info = meta["master_info"] + channels = meta["channels"] + for sb in sorted(subs, key=lambda x: x["rec_start"]): + rel = sb["abs_off"] - byte_start + try: + t0 = _now() + raw = _decompress_subblock_blob(blob, rel) + prof["decode"] += _now() - t0 + except Exception as e: + log.warning("stripe decompress failed grp=%s off=%d: %s", grp, sb["abs_off"], e) + continue + actual = len(raw) // record_size if record_size else 0 + if actual == 0: + continue + t0 = _now() + if master_info is not None: + ts = extract_timestamps(raw, record_size, master_info, index_offset=sb["rec_start"]) + else: + ts = np.arange(sb["rec_start"], sb["rec_start"] + actual, dtype=np.float64) + if time_offset: + ts = ts + time_offset + prof["decode"] += _now() - t0 + for ch in channels: + try: + t0 = _now() + values = extract_signal(raw, record_size, ch) + prof["decode"] += _now() - t0 + if values is None: + continue + yield from emit_fn(ts, values, ch["channel_id"]) + except Exception as e: + log.warning("stripe extract failed ch=%s: %s", ch.get("channel_id"), e) + continue + yield from flush_fn() diff --git a/src/impulse_ds/mdf/bin_packer.py b/src/impulse_ds/mdf/bin_packer.py new file mode 100644 index 00000000..184e3b28 --- /dev/null +++ b/src/impulse_ds/mdf/bin_packer.py @@ -0,0 +1,376 @@ +""" +Partition planning for distributing MDF4 channel data across Spark tasks. + +`plan_partitions` is the primary planner: it sizes partitions by estimated +output rows (record-range splits for big groups, channel-subset splits for very +wide groups, coalescing for many small groups) using only scan metadata — no +file I/O. `plan_stripes_for_file` is the alternative byte-offset "stripe" +planner, and `plan_master_partitions` plans the per-group master time base. +""" + +from typing import Dict, List + +def plan_partitions( + file_path: str, + master_channels: dict, + signal_channels: list, + channel_id_map: dict, + target_partition_mb: float = 64.0, + channel_threshold: int = 256, + time_dtype: str = "float64", + value_dtype: str = "float64", + run_length_encoding: bool = False, + max_groups_per_partition: int = 64, + time_offset: float = 0.0, +) -> List[dict]: + """ + Plan Spark partitions for one MDF file, decoupling parallelism from channel + count so executors stay saturated and a single dominant channel group no + longer becomes one serial straggler. + + Strategy per channel group, sized to ~target rows of output (16 bytes/row), + so parallelism tracks data volume, not channel count — using ONLY metadata + already in hand (no per-group file reads): + - Few channels (<= channel_threshold): split by EVEN RECORD RANGE so many + tasks process disjoint row ranges of the group. At read time DT blocks + seek to the range, DL/HL blocks decompress only the overlapping + sub-blocks (read_data_list_range), and a standalone DZ is decompressed + and sliced. Adjacent DL partitions share at most one boundary sub-block + (negligible redundant decompression). + - Wide groups (> channel_threshold channels): split by CHANNEL SUBSET + (full rows) to avoid duplicating a huge channel list across slices. + - Small groups whose whole output fits one partition are COALESCED with + neighbouring small groups into a shared partition (see below), so that a + file with thousands of tiny groups does not produce thousands of tiny + tasks (per-task scheduling + Python round-trip overhead dominated, while + a few big groups became stragglers — a severe load skew). + + Coalescing: small groups are packed, in file order (ascending data block + address, for read locality), into a shared spec until EITHER the combined + output reaches ~target_rows OR the spec already holds + max_groups_per_partition groups. The second bound matters because each group + in a coalesced spec is a separate (often scattered) block read on the + executor; without it, a spec of thousands of tiny groups would just relocate + the straggler into one task doing thousands of latency-bound reads. The + executor (convert_spec_to_arrow_batches) already loops over the distinct + data block addresses within a spec, so a multi-group spec needs no special + handling there. + + Returns spec dicts consumed by udf_helpers.convert_spec_to_arrow_batches + (each: file_path, channels, and optional row_start/row_end). + + Args use scan ChannelInfo objects (master_channels: {group_idx: ChannelInfo}, + signal_channels: [ChannelInfo], channel_id_map: {(group_idx, channel_idx): id}). + """ + target_rows = max(1, int(target_partition_mb * 1024 * 1024 / 16)) + + groups: Dict[int, list] = {} + for ch in signal_channels: + groups.setdefault(ch.data_block_addr, []).append(ch) + + def _master_info(group_idx): + m = master_channels.get(group_idx) + if not m: + return None + return { + "byte_offset": m.byte_offset, "bit_offset": m.bit_offset, + "bit_count": m.bit_count, "data_type": m.data_type, + "channel_type": m.channel_type, "cc_type": m.cc_type, + "cc_params": list(m.cc_params) if m.cc_params else [], + } + + def _ch_dict(ch): + return { + "channel_id": channel_id_map.get((ch.group_idx, ch.channel_idx), -1), + "group_idx": ch.group_idx, "channel_idx": ch.channel_idx, + "sample_count": ch.sample_count, "data_type": ch.data_type, + "bit_offset": ch.bit_offset, "byte_offset": ch.byte_offset, + "bit_count": ch.bit_count, "channel_type": ch.channel_type, + "data_block_addr": ch.data_block_addr, "record_size": ch.record_size, + "master_info": _master_info(ch.group_idx), "cn_flags": ch.cn_flags, + "invalidation_bit_pos": ch.invalidation_bit_pos, + "invalidation_bytes": ch.invalidation_bytes, "data_bytes": ch.data_bytes, + "cc_type": ch.cc_type, + "cc_params": list(ch.cc_params) if ch.cc_params else [], + } + + def _spec(ch_dicts, r0=None, r1=None): + s = {"file_path": file_path, "channels": ch_dicts, + "time_dtype": time_dtype, "value_dtype": value_dtype, + "run_length_encoding": run_length_encoding, "time_offset": time_offset} + if r0 is not None: + s["row_start"] = r0 + s["row_end"] = r1 + return s + + # NOTE: this function performs NO file I/O. It is pure metadata, O(channels), + # so it scales to tens of thousands of groups. (Earlier versions peeked the + # block id per group and/or walked DL sub-block chains on the driver; on a + # FUSE-mounted volume those are scattered cold reads ~10-25 ms each, i.e. + # minutes for 30k+ groups — a planning blocker.) Block type is resolved at + # READ time on executors instead (DT seek / DL sub-block range / DZ slice). + specs: List[dict] = [] + # Open bin for coalescing small (single-partition) groups. Flushed when it + # reaches ~target_rows of output or max_groups_per_partition groups. + pending_ch: List[dict] = [] + pending_rows = 0 + pending_groups = 0 + + def _flush_small(): + nonlocal pending_ch, pending_rows, pending_groups + if pending_ch: + specs.append(_spec(pending_ch)) + pending_ch = [] + pending_rows = 0 + pending_groups = 0 + + for chans in groups.values(): + c = len(chans) + group_records = chans[0].sample_count + if c == 0 or group_records == 0: + continue + ch_dicts = [_ch_dict(ch) for ch in chans] + + if c > channel_threshold: + # Wide group: split by channel subset (no channel-list duplication). + ch_per_part = max(1, target_rows // group_records) + for i in range(0, c, ch_per_part): + specs.append(_spec(ch_dicts[i:i + ch_per_part])) + else: + rows_per_part = max(1, target_rows // c) + if rows_per_part >= group_records: + # Small group (fits one partition): coalesce with neighbours. + grp_rows = c * group_records + if pending_ch and ( + pending_rows + grp_rows > target_rows + or pending_groups >= max_groups_per_partition + ): + _flush_small() + pending_ch.extend(ch_dicts) + pending_rows += grp_rows + pending_groups += 1 + else: + r = 0 + while r < group_records: + r1 = min(r + rows_per_part, group_records) + specs.append(_spec(ch_dicts, r, r1)) + r = r1 + + _flush_small() + return specs + + +def plan_master_partitions( + file_path: str, + master_channels: dict, + target_partition_mb: float = 64.0, + time_dtype: str = "float64", + max_groups_per_partition: int = 64, + time_offset: float = 0.0, +) -> List[dict]: + """ + Plan Spark partitions for the MASTER channels of one MDF file — the time + base of each acquisition group, one master per group, emitted as one row per + ORIGINAL sample (file_uri, group_idx, timestamp). This is the companion of + run-length-encoded signals: RLE keeps only [tstart, tend] intervals, so the + original per-sample grid is recovered by joining a group's stored timestamps + against the intervals. + + Same sizing strategy as plan_partitions (no file I/O): a group with more than + ~target_rows samples is split by EVEN RECORD RANGE; smaller groups are + COALESCED (in file order, bounded by max_groups_per_partition block reads per + task) so thousands of tiny groups don't each become a task. + + Returns spec dicts consumed by udf_helpers.convert_master_spec_to_arrow_batches + (each: file_path, time_dtype, masters[list], optional + row_start/row_end). Groups without a master are simply absent from the input. + """ + target_rows = max(1, int(target_partition_mb * 1024 * 1024 / 16)) + + def _master_entry(group_idx, m): + return { + "group_idx": group_idx, + "data_block_addr": m.data_block_addr, + "record_size": m.record_size, + "sample_count": m.sample_count, + "master_info": { + "byte_offset": m.byte_offset, "bit_offset": m.bit_offset, + "bit_count": m.bit_count, "data_type": m.data_type, + "channel_type": m.channel_type, "cc_type": m.cc_type, + "cc_params": list(m.cc_params) if m.cc_params else [], + }, + } + + def _spec(masters, r0=None, r1=None): + s = {"file_path": file_path, + "time_dtype": time_dtype, "masters": masters, "time_offset": time_offset} + if r0 is not None: + s["row_start"] = r0 + s["row_end"] = r1 + return s + + specs: List[dict] = [] + pending: List[dict] = [] + pending_rows = 0 + + def _flush(): + nonlocal pending, pending_rows + if pending: + specs.append(_spec(pending)) + pending = [] + pending_rows = 0 + + for group_idx, m in master_channels.items(): + group_records = m.sample_count + if group_records == 0: + continue + entry = _master_entry(group_idx, m) + if group_records > target_rows: + # Big group: split the master into even record ranges (one per spec). + r = 0 + while r < group_records: + r1 = min(r + target_rows, group_records) + specs.append(_spec([entry], r, r1)) + r = r1 + else: + # Small group: coalesce with neighbours toward target_rows, bounding + # the number of (scattered) block reads per task. + if pending and ( + pending_rows + group_records > target_rows + or len(pending) >= max_groups_per_partition + ): + _flush() + pending.append(entry) + pending_rows += group_records + + _flush() + return specs + + +def plan_stripes_for_file( + file_path: str, + target_partition_mb: float = 64.0, + time_dtype: str = "float64", + value_dtype: str = "float64", + run_length_encoding: bool = False, + time_offset: float = 0.0, + stripe_target_mb: float = 128.0, + gap_threshold_mb: float = 8.0, + max_subblocks_per_stripe: int = 4096, + file_bytes: bytes = None, +) -> List[dict]: + """Design B planner: read the file ONCE (in RAM), build a sub-block map, and + pack sub-blocks — sorted by file offset — into contiguous byte-offset STRIPES. + + Each stripe is bounded by: target_rows (output budget, from target_partition_mb, + keeps Delta file sizing consistent), stripe_target_mb (compressed bytes read + per task, memory/IO bound), a gap guard (don't read large non-data spans), and + a sub-block-count cap. A stripe is decoded with one sequential read + (udf_helpers.convert_stripe_spec_to_arrow_batches). + + Returns stripe spec dicts. file_bytes lets a caller that already loaded the + file pass it in (avoids a re-read). + """ + import io + from .mdf4_reader import MDF4Reader + from .udf_helpers import parse_subblocks + + if file_bytes is None: + with open(file_path, "rb") as fh: + file_bytes = fh.read() + organized = MDF4Reader(file_bytes=file_bytes).scan_channels_organized() + master_channels = organized["master_channels"] + signal_channels = organized["signal_channels"] + channel_id_map = organized["channel_id_map"] + + target_rows = max(1, int(target_partition_mb * 1024 * 1024 / 16)) + stripe_bytes_cap = int(stripe_target_mb * 1024 * 1024) + gap_threshold = int(gap_threshold_mb * 1024 * 1024) + + def _minfo(group_idx): + m = master_channels.get(group_idx) + if not m: + return None + return { + "byte_offset": m.byte_offset, "bit_offset": m.bit_offset, + "bit_count": m.bit_count, "data_type": m.data_type, + "channel_type": m.channel_type, "cc_type": m.cc_type, + "cc_params": list(m.cc_params) if m.cc_params else [], + } + + def _chd(ch): + return { + "channel_id": channel_id_map.get((ch.group_idx, ch.channel_idx), -1), + "group_idx": ch.group_idx, "channel_idx": ch.channel_idx, + "sample_count": ch.sample_count, "data_type": ch.data_type, + "bit_offset": ch.bit_offset, "byte_offset": ch.byte_offset, + "bit_count": ch.bit_count, "channel_type": ch.channel_type, + "data_block_addr": ch.data_block_addr, "record_size": ch.record_size, + "cn_flags": ch.cn_flags, "invalidation_bit_pos": ch.invalidation_bit_pos, + "invalidation_bytes": ch.invalidation_bytes, "data_bytes": ch.data_bytes, + "cc_type": ch.cc_type, + "cc_params": list(ch.cc_params) if ch.cc_params else [], + } + + bio = io.BytesIO(file_bytes) + by_block = {} + for ch in signal_channels: + by_block.setdefault(ch.data_block_addr, []).append(ch) + + groups_meta = {} + subblocks = [] + for addr, chans in by_block.items(): + rs = chans[0].record_size + sc = chans[0].sample_count + gi = chans[0].group_idx + if rs == 0 or sc == 0: + continue + groups_meta[addr] = { + "record_size": rs, "master_info": _minfo(gi), + "channels": [_chd(c) for c in chans], "n_channels": len(chans), + } + for (soff, slen, rstart, rcount) in parse_subblocks(bio, addr, rs, sc): + if rcount <= 0: + continue + subblocks.append({"grp": addr, "abs_off": soff, "on_disk_len": slen, + "rec_start": rstart, "rec_count": rcount}) + + subblocks.sort(key=lambda s: s["abs_off"]) + + specs = [] + cur = [] + cur_rows = cur_bytes = 0 + cur_lo = cur_hi = None + cur_grps = set() + + def _flush(): + nonlocal cur, cur_rows, cur_bytes, cur_lo, cur_hi, cur_grps + if cur: + specs.append({ + "file_path": file_path, + "byte_start": cur_lo, "byte_end": cur_hi, + "time_dtype": time_dtype, "value_dtype": value_dtype, + "run_length_encoding": run_length_encoding, "time_offset": time_offset, + "groups": {str(g): groups_meta[g] for g in cur_grps}, + "subblocks": cur, + }) + cur = []; cur_rows = cur_bytes = 0; cur_lo = cur_hi = None; cur_grps = set() + + for sb in subblocks: + rows = sb["rec_count"] * groups_meta[sb["grp"]]["n_channels"] + gap = (sb["abs_off"] - cur_hi) if cur_hi is not None else 0 + if cur and (cur_rows + rows > target_rows + or cur_bytes + sb["on_disk_len"] > stripe_bytes_cap + or gap > gap_threshold + or len(cur) >= max_subblocks_per_stripe): + _flush() + cur.append(sb) + cur_rows += rows + cur_bytes += sb["on_disk_len"] + cur_grps.add(sb["grp"]) + end = sb["abs_off"] + sb["on_disk_len"] + cur_lo = sb["abs_off"] if cur_lo is None else min(cur_lo, sb["abs_off"]) + cur_hi = end if cur_hi is None else max(cur_hi, end) + + _flush() + return specs diff --git a/src/impulse_ds/mdf/converter.py b/src/impulse_ds/mdf/converter.py new file mode 100644 index 00000000..6574ae3b --- /dev/null +++ b/src/impulse_ds/mdf/converter.py @@ -0,0 +1,567 @@ +""" +Main converter module: orchestrates MDF4 -> Delta Lake conversion using PySpark. + +Architecture: +1. Driver reads MDF4 metadata (fast, sequential scan of block headers) +2. Identifies master channels for each channel group +3. Bin-packs signal channels into balanced partitions +4. Each Spark task reads its assigned channels directly from the MDF binary +5. Uses mapInArrow for zero-copy vectorized processing +6. Writes to two Delta tables: signals (time series) and metadata (channel info) +""" + +import time +from datetime import datetime +from typing import List, Dict, Optional, Tuple +from dataclasses import dataclass + +from pyspark.sql import SparkSession +from pyspark.sql.types import ( + StructType, StructField, IntegerType, StringType +) + +from .mdf4_reader import ( + MDF4Reader, ChannelInfo, CN_TYPE_MASTER, CN_TYPE_VIRTUAL_MASTER, +) +from .bin_packer import plan_partitions +from .schemas import METADATA_SCHEMA + + +_artifacts_shipped = False + + +def _ensure_artifacts_shipped(spark: SparkSession): + """Ship the impulse_ds.mdf package to Spark workers once per session. + + NOTE: this `addArtifact(pyfile=True)` reaches mapInArrow UDF workers (which + import the package at runtime, by-value serialized) but does NOT reach the + server's `create_data_source` worker, which deserializes the registered + custom data-source class BY REFERENCE and therefore must + `import impulse_ds.mdf` at that point. So the mapInArrow conversion path + works with only this shipped artifact, while the `mdf_signals`/`mdf_metadata` + data sources additionally require the package to be importable cluster-side + (e.g. installed as a cluster library). A warm-up mapInArrow was tried and did + NOT help — the create_data_source worker is a separate/fresh process. + """ + global _artifacts_shipped + if _artifacts_shipped: + return + import pathlib + import zipfile + import tempfile + package_dir = pathlib.Path(__file__).parent + impulse_ds_dir = package_dir.parent + # Ship as a zip to preserve package structure (import impulse_ds.mdf.*) + zip_path = pathlib.Path(tempfile.gettempdir()) / "impulse_ds_mdf.zip" + with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf: + zf.write(impulse_ds_dir / "__init__.py", "impulse_ds/__init__.py") + for py_file in package_dir.glob("*.py"): + zf.write(py_file, f"impulse_ds/mdf/{py_file.name}") + spark.addArtifact(str(zip_path), pyfile=True) + _artifacts_shipped = True + + +@dataclass +class ConversionResult: + """Result of an MDF to Delta conversion.""" + file_uri: str + file_path: str + num_channels: int + total_samples: int + num_partitions: int + duration_seconds: float + signals_table: str + metadata_table: str + + +class MDFToDeltaConverter: + """ + Converts MDF4 files to Delta Lake tables using distributed Spark processing. + + Usage: + converter = MDFToDeltaConverter(spark, signals_table="catalog.schema.signals", + metadata_table="catalog.schema.metadata") + result = converter.convert("/path/to/file.mf4") + """ + + def __init__( + self, + spark: SparkSession, + signals_table: str, + metadata_table: str, + target_partition_mb: float = 64.0, + time_dtype: str = "float64", + value_dtype: str = "float64", + run_length_encoding: bool = False, + max_groups_per_partition: int = 64, + ): + """ + Args: + spark: Active SparkSession (local cluster or Databricks Connect). + signals_table: Fully-qualified Delta table for the signal rows + (file_uri, channel_id, time, value); created with liquid + clustering on (file_uri, channel_id). + metadata_table: Fully-qualified Delta table for channel metadata + (file_uri, channel_id, group_idx, channel_idx, channel_name, + unit, header_datetime, md_comment); clustered on file_uri. + target_partition_mb: Target output size per Spark task (drives how + large channel groups are split into record ranges and how many + small groups are coalesced). Lower => more, smaller tasks. + time_dtype / value_dtype: 'float64' (default) or 'float32'. float32 + halves that column's on-disk size when source precision allows. + run_length_encoding: When True, collapse consecutive equal samples of + a channel into half-open [tstart, tend) interval rows (plus a + terminal point row per channel); the signals schema becomes + (file_uri, channel_id, tstart, tend, value). + max_groups_per_partition: Upper bound on how many small channel + groups are coalesced into one task (caps scattered reads/task). + """ + self.spark = spark + self.signals_table = signals_table + self.metadata_table = metadata_table + self.target_partition_mb = target_partition_mb + self.time_dtype = time_dtype + self.value_dtype = value_dtype + self.run_length_encoding = run_length_encoding + self.max_groups_per_partition = max_groups_per_partition + + def convert( + self, + file_path: str, + mode: str = "append", + ) -> ConversionResult: + """ + Convert a single MDF4 file to Delta Lake. + + Args: + file_path: Path to the MDF4 file (must be accessible from Spark workers). + Also used verbatim as the row identifier (file_uri). + mode: Write mode for Delta table ("append" or "overwrite"). + + Returns: + ConversionResult with statistics about the conversion. + """ + start_time = time.time() + + # Step 1: Scan metadata on the driver + reader = MDF4Reader(file_path) + all_channels = reader.scan_metadata() + header_datetime = reader.read_header_datetime() + + if not all_channels: + raise ValueError(f"No channels found in {file_path}") + + # Step 2: Identify master channels per group and build channel map + master_channels, signal_channels, channel_id_map = self._organize_channels( + all_channels + ) + + # Step 3: Write metadata table + self._write_metadata(signal_channels, channel_id_map, file_path, header_datetime) + + # Step 4: Plan record-range / channel-subset partitions + partition_specs = self._plan( + file_path, master_channels, signal_channels, channel_id_map) + + # Step 5: Run distributed conversion + total_samples = sum(ch.sample_count for ch in signal_channels) + self._run_spark_conversion(partition_specs, mode) + + duration = time.time() - start_time + + return ConversionResult( + file_uri=file_path, + file_path=file_path, + num_channels=len(signal_channels), + total_samples=total_samples, + num_partitions=len(partition_specs), + duration_seconds=duration, + signals_table=self.signals_table, + metadata_table=self.metadata_table, + ) + + def _organize_channels( + self, channels: List[ChannelInfo] + ) -> Tuple[Dict[int, ChannelInfo], List[ChannelInfo], Dict[Tuple[int, int], int]]: + """ + Separate master and signal channels, assign channel IDs. + + Returns: + - master_channels: {group_idx: ChannelInfo} for time channels + - signal_channels: list of non-master channels + - channel_id_map: {(group_idx, channel_idx): channel_id} + """ + master_channels: Dict[int, ChannelInfo] = {} + signal_channels: List[ChannelInfo] = [] + channel_id_map: Dict[Tuple[int, int], int] = {} + + channel_id = 0 + for ch in channels: + if ch.channel_type in (CN_TYPE_MASTER, CN_TYPE_VIRTUAL_MASTER): + master_channels[ch.group_idx] = ch + else: + channel_id_map[(ch.group_idx, ch.channel_idx)] = channel_id + signal_channels.append(ch) + channel_id += 1 + + return master_channels, signal_channels, channel_id_map + + def _metadata_rows(self, signal_channels, channel_id_map, file_uri, header_datetime): + """Build the metadata-table rows (one dict per signal channel) for one + file. Shared by convert() and convert_batch_parallel().""" + return [ + { + "file_uri": file_uri, + "channel_id": channel_id_map[(ch.group_idx, ch.channel_idx)], + "group_idx": ch.group_idx, + "channel_idx": ch.channel_idx, + "channel_name": ch.channel_name, + "unit": ch.unit or "", + "header_datetime": header_datetime, + "md_comment": ch.md_comment or None, + } + for ch in signal_channels + ] + + def _plan(self, file_path, master_channels, signal_channels, channel_id_map): + """Plan partition specs for one file using this converter's settings. + Shared by convert() and convert_batch_parallel().""" + return plan_partitions( + file_path, master_channels, signal_channels, channel_id_map, + target_partition_mb=self.target_partition_mb, + time_dtype=self.time_dtype, value_dtype=self.value_dtype, + run_length_encoding=self.run_length_encoding, + max_groups_per_partition=self.max_groups_per_partition, + ) + + def _write_metadata( + self, + signal_channels: List[ChannelInfo], + channel_id_map: Dict[Tuple[int, int], int], + file_uri: str, + header_datetime: Optional[datetime], + ): + """Write channel metadata to the metadata Delta table.""" + metadata_rows = self._metadata_rows( + signal_channels, channel_id_map, file_uri, header_datetime) + if metadata_rows: + meta_df = self.spark.createDataFrame(metadata_rows, schema=METADATA_SCHEMA) + _write_metadata_df(meta_df, self.metadata_table, "append") + + def _run_spark_conversion(self, partition_specs: List[dict], mode: str): + """ + Execute the distributed conversion using mapInArrow for vectorized processing. + + Creates one partition per bin, each partition reads its assigned channels + from the MDF file and produces Arrow record batches. + """ + import json + + # Serialize partition specs as JSON strings - one per partition + spec_strings = [json.dumps(spec) for spec in partition_specs] + + # Create a seed DataFrame with one row per partition + seed_df = self.spark.createDataFrame( + [(i, spec_strings[i]) for i in range(len(spec_strings))], + schema=StructType([ + StructField("partition_id", IntegerType(), False), + StructField("spec_json", StringType(), False), + ]) + ).repartition(len(spec_strings), "partition_id") + + # Use mapInArrow for zero-copy vectorized conversion. The output schema + # follows the dtype carried in the specs (time/value may be float32). + # _make_arrow_udf returns a local function that cloudpickle can serialize + # without requiring the impulse_ds.mdf module on workers + udf_func = _make_arrow_udf() + td = partition_specs[0].get("time_dtype", "float64") if partition_specs else "float64" + vd = partition_specs[0].get("value_dtype", "float64") if partition_specs else "float64" + rle = bool(partition_specs[0].get("run_length_encoding", False)) if partition_specs else False + result_df = seed_df.mapInArrow(udf_func, schema=_signals_spark_schema(td, vd, rle)) + + # Write to Delta (plain write; see _write_signals_df for storage findings) + _write_signals_df(result_df, self.signals_table, mode) + + def convert_batch( + self, + file_paths: List[str], + mode: str = "append", + ) -> List[ConversionResult]: + """ + Convert multiple MDF4 files in sequence; each row is tagged with its + source file path (file_uri). + + Args: + file_paths: List of paths to MDF4 files. + mode: Write mode ("append" or "overwrite"). First file uses given mode, + subsequent files always append. + + Returns: + List of ConversionResult for each file. + """ + results = [] + for i, path in enumerate(file_paths): + current_mode = mode if i == 0 else "append" + result = self.convert(path, current_mode) + results.append(result) + return results + + def convert_batch_parallel( + self, + file_paths: List[str], + mode: str = "overwrite", + ) -> ConversionResult: + """ + Convert multiple MDF4 files in a single Spark job. + + Scans all files on the driver, bin-packs channels across all files, + and submits one large mapInArrow job. More efficient than sequential + convert() calls when files are numerous but individually small. + + Args: + file_paths: List of paths to MDF4 files. + mode: Write mode for the Delta table. + + Returns: + Aggregate ConversionResult. + """ + from concurrent.futures import ThreadPoolExecutor + + start_time = time.time() + all_partition_specs = [] + all_metadata_rows = [] + total_channels = 0 + total_samples = 0 + + # Scan all files' metadata in parallel (item 5a). Scanning walks block + # headers and is I/O-bound; CPython releases the GIL during file reads, + # so threads overlap the per-file latency. Spec building stays sequential + # afterward to keep output ordering deterministic by input order. + def _scan(idx_path): + idx, fp = idx_path + reader = MDF4Reader(fp) + return idx, fp, reader.scan_metadata(), reader.read_header_datetime() + + max_workers = min(16, max(1, len(file_paths))) + with ThreadPoolExecutor(max_workers=max_workers) as ex: + scanned = sorted( + ex.map(_scan, enumerate(file_paths)), + key=lambda r: r[0], + ) + + for i, file_path, all_channels_in_file, header_datetime in scanned: + if not all_channels_in_file: + continue + + master_channels, signal_channels, channel_id_map = self._organize_channels( + all_channels_in_file + ) + + all_metadata_rows.extend(self._metadata_rows( + signal_channels, channel_id_map, file_path, header_datetime)) + all_partition_specs.extend(self._plan( + file_path, master_channels, signal_channels, channel_id_map)) + + total_channels += len(signal_channels) + total_samples += sum(ch.sample_count for ch in signal_channels) + + # Write all metadata at once + if all_metadata_rows: + meta_df = self.spark.createDataFrame(all_metadata_rows, schema=METADATA_SCHEMA) + _write_metadata_df(meta_df, self.metadata_table, mode) + + # Run all partitions in a single Spark job + if all_partition_specs: + self._run_spark_conversion(all_partition_specs, mode) + + duration = time.time() - start_time + + return ConversionResult( + file_uri=f"{len(file_paths)} files", + file_path=f"{len(file_paths)} files", + num_channels=total_channels, + total_samples=total_samples, + num_partitions=len(all_partition_specs), + duration_seconds=duration, + signals_table=self.signals_table, + metadata_table=self.metadata_table, + ) + + +def _make_arrow_udf(): + """Return the Arrow UDF with __module__ set so cloudpickle serializes it inline.""" + func = _convert_partition_arrow + # Prevent cloudpickle from trying to import impulse_ds.mdf on workers + func.__module__ = "__main__" + func.__qualname__ = "_convert_partition_arrow" + return func + + +def _schema_to_ddl(schema) -> str: + """Render a Spark StructType as a CREATE TABLE column list (e.g. + 'file_uri string, channel_id int, ...'). simpleString() yields the SQL + type name for each field.""" + return ", ".join(f"{f.name} {f.dataType.simpleString()}" for f in schema.fields) + + +def _ensure_clustered_table(spark, table: str, schema, cluster_cols: str): + """ + Ensure `table` exists as a Delta table with liquid clustering on + `cluster_cols` BEFORE data is written, so the write itself is + clustering-aware (clustering-on-write). + + - CREATE TABLE IF NOT EXISTS ... CLUSTER BY: creates a fresh table already + configured for liquid clustering. + - ALTER TABLE ... CLUSTER BY: idempotently enforces the clustering columns + on a pre-existing (e.g. legacy, non-clustered) unpartitioned table. + """ + ddl = _schema_to_ddl(schema) + spark.sql( + f"CREATE TABLE IF NOT EXISTS {table} ({ddl}) " + f"USING DELTA CLUSTER BY ({cluster_cols})" + ) + try: + spark.sql(f"ALTER TABLE {table} CLUSTER BY ({cluster_cols})") + except Exception: + # No-op when already clustered on these columns; best-effort enforcement. + pass + + +def _write_metadata_df(df, table: str, mode: str): + """Write the channel-metadata DataFrame to its Delta table with liquid + clustering on file_uri (item: clustering). Schema is unchanged.""" + _ensure_clustered_table(df.sparkSession, table, METADATA_SCHEMA, "file_uri") + df.write.format("delta").mode(mode).saveAsTable(table) + + +def _write_signals_df(df, table: str, mode: str): + """ + Write the signals DataFrame to the Delta signals table. Preserves the fixed + (file_uri, channel_id, time, value) schema exactly. + + History / measured findings (kept here so the dead-ends aren't re-explored): + - Item 1a (sortWithinPartitions + ZSTD) gave NO storage win and added write + CPU: the heavy columns are float64 and Parquet has no delta/RLE encoding + for DOUBLE, so sorting `time` enables no better encoding. Reverted. + - BYTE_STREAM_SPLIT prototype (on real extracted columns): it helps `time` + (~-11% with zstd, monotonic high-cardinality doubles) but is catastrophic + for `value` (+73%) because `value` is low-cardinality and default + DICTIONARY encoding already crushes it. The win only exists *per-column* + (BSS on `time`, dictionary on `value` → ~-23% vs the snappy default), but + Spark/Delta expose no per-column Parquet encoding control, so it is not + wireable through the standard Delta write. Not applied. + - ZSTD looked promising locally (~-14% vs pyarrow's snappy default), but on + the Databricks Delta writer the codec is NOT controllable: verified that + compression.codec = uncompressed / snappy / zstd all produce BYTE-IDENTICAL + output (the runtime forces its own codec, and the data is already ~10:1 + compressed). Neither the DataFrameWriter ".option('compression', ...)" nor + the session conf "spark.sql.parquet.compression.codec" has any effect. + + Conclusion: under the fixed schema + Databricks Delta write there is no + achievable codec lever, so this is a plain write. The table is created with + liquid clustering on (file_uri, channel_id) so data is organized for + pruning on those keys. Keeps a best-effort delta.targetFileSize hint (item + 1c) for downstream OPTIMIZE. + + The clustered table is created from df.schema (not the fixed SIGNALS_SCHEMA) + so a float32 time/value DataFrame produces a matching float table. + """ + _ensure_clustered_table( + df.sparkSession, table, df.schema, "file_uri, channel_id" + ) + df.write.format("delta").mode(mode).saveAsTable(table) + try: + df.sparkSession.sql( + f"ALTER TABLE {table} SET TBLPROPERTIES " + f"('delta.targetFileSize' = '128mb')" + ) + except Exception: + # Property hint is best-effort; never fail the conversion over it. + pass + + +def _signals_spark_schema(time_dtype: str = "float64", value_dtype: str = "float64", + run_length_encoding: bool = False): + """Spark StructType for the signals output; time/value follow the configured + dtype (float32 halves their on-disk bytes). With run_length_encoding the + per-sample `time` column is replaced by the [`tstart`, `tend`] interval.""" + from pyspark.sql.types import ( + StructType, StructField, StringType, IntegerType, DoubleType, FloatType, + ) + + def _ft(dt): + return FloatType() if str(dt) == "float32" else DoubleType() + + if run_length_encoding: + return StructType([ + StructField("file_uri", StringType(), False), + StructField("channel_id", IntegerType(), False), + StructField("tstart", _ft(time_dtype), False), + StructField("tend", _ft(time_dtype), False), + StructField("value", _ft(value_dtype), True), + ]) + + return StructType([ + StructField("file_uri", StringType(), False), + StructField("channel_id", IntegerType(), False), + StructField("time", _ft(time_dtype), False), + StructField("value", _ft(value_dtype), True), + ]) + + +def _convert_partition_arrow(batch_iter): + """mapInArrow UDF: one seed row per partition carries a spec JSON; delegate + each spec to the shared Arrow conversion core so the mapInArrow path and the + 'mdf_signals' data source share identical streaming/decoding logic. The + time/value dtype is read from the spec (float32 or float64).""" + import json + import logging + import pyarrow as pa + from .udf_helpers import ( + convert_spec_to_arrow_batches, convert_stripe_spec_to_arrow_batches, + signals_arrow_schema, + ) + + log = logging.getLogger("impulse_ds.mdf.convert") + prof = {"read": 0, "decode": 0, "arrow": 0, "rows": 0} + + for batch in batch_iter: + spec_jsons = batch.column("spec_json").to_pylist() + # dtype is uniform per job; read it from the first spec for the empty + # fallback batch so it matches the mapInArrow-declared schema. + td, vd, rle = "float64", "float64", False + if spec_jsons: + _first = json.loads(spec_jsons[0]) + td = _first.get("time_dtype", "float64") + vd = _first.get("value_dtype", "float64") + rle = bool(_first.get("run_length_encoding", False)) + output_schema = signals_arrow_schema(td, vd, rle) + yielded = False + for spec_json in spec_jsons: + spec = json.loads(spec_json) + # A stripe spec (Design B, byte-offset) carries "subblocks"; a group + # spec (default) carries "channels". Dispatch to the matching decoder. + decode = (convert_stripe_spec_to_arrow_batches if "subblocks" in spec + else convert_spec_to_arrow_batches) + for rb in decode( + spec, prof=prof, + time_dtype=spec.get("time_dtype", "float64"), + value_dtype=spec.get("value_dtype", "float64"), + run_length_encoding=bool(spec.get("run_length_encoding", False)), + ): + yielded = True + yield rb + + if not yielded: + yield pa.RecordBatch.from_arrays( + [pa.array([], type=output_schema.field(i).type) + for i in range(len(output_schema))], + schema=output_schema, + ) + + # Per-task phase breakdown (item 0). WARNING so it surfaces in executor logs + # without raising the default level; it is a measurement line, not an error. + log.warning( + "MDF_PROFILE rows=%d read_ms=%.0f decode_ms=%.0f arrow_ms=%.0f", + prof["rows"], prof["read"] / 1e6, prof["decode"] / 1e6, prof["arrow"] / 1e6, + ) diff --git a/src/impulse_ds/mdf/datasources.py b/src/impulse_ds/mdf/datasources.py new file mode 100644 index 00000000..0e551d76 --- /dev/null +++ b/src/impulse_ds/mdf/datasources.py @@ -0,0 +1,488 @@ +""" +PySpark custom data sources for reading MDF4 files. + +Provides three data sources: + - "mdf_signals": Reads signal time-series data (file_uri, channel_id, time, value) + - "mdf_metadata": Reads channel metadata (file_uri, channel_id, group_idx, channel_idx, channel_name, unit, header_datetime, md_comment) + - "mdf_masters": Reads each group's master time base, one row per original + sample (file_uri, group_idx, timestamp) — used to reverse RLE signals. + +Usage: + from databricks.sdk import WorkspaceClient + from impulse_ds.mdf import register_mdf_datasources + + register_mdf_datasources(spark, WorkspaceClient()) + + signals_df = ( + spark.read.format("mdf_signals") + .option("path", "/mnt/data/mdf_files") + .option("files", "batch_a/run_1/file1.mf4,/other/volume/file2.mf4") # optional + .option("target_partition_mb", "64") + .load() + ) + + metadata_df = ( + spark.read.format("mdf_metadata") + .option("path", "/mnt/data/mdf_files") + .load() # discovers all *.mf4 under path, including subdirectories + ) + +Options (shared by ``mdf_signals``, ``mdf_metadata``, and ``mdf_masters``): + path (required): Base directory for file discovery and relative ``files`` entries. + files (optional): Comma-separated list of MDF4 files to read. Each entry may be + an absolute path or a path relative to ``path``. When set, only + these files are read (no directory scan). When omitted, every + ``*.mf4`` file under ``path`` is discovered recursively. + target_partition_mb (optional, signals/masters): Target partition size in MB. + Default 64. + max_groups_per_partition (optional, signals/masters): Max small channel groups + coalesced into one task. Default 64. +""" + +import os +from typing import TYPE_CHECKING + +from pyspark.sql.datasource import DataSource, DataSourceReader, InputPartition +from .schemas import METADATA_SCHEMA + +if TYPE_CHECKING: + from databricks.sdk import WorkspaceClient + +_ws: "WorkspaceClient | None" = None + + +def register_mdf_datasources(spark, ws: "WorkspaceClient"): + """Register all MDF data sources and enable read telemetry. + + Verifies the workspace client, stores it module-wide for partition-planning + telemetry, and registers ``mdf_signals``, ``mdf_metadata``, and + ``mdf_masters`` with Spark. + """ + from impulse_query_engine import __version__ + from impulse_query_engine.telemetry import verify_workspace_client + + global _ws + _ws = verify_workspace_client(ws, "databricks-impulse", __version__) + spark.dataSource.register(MdfSignalsDataSource) + spark.dataSource.register(MdfMetadataDataSource) + spark.dataSource.register(MdfMastersDataSource) + return _ws + + +def _emit_read_telemetry(source: str) -> None: + if _ws is not None: + from impulse_query_engine.telemetry import log_telemetry + + log_telemetry(_ws, "mdf", source) + + +def _discover_mf4_files(base_path: str) -> list[str]: + """Return sorted paths to every ``.mf4`` file under ``base_path`` (recursive).""" + found: list[str] = [] + for root, _dirs, files in os.walk(base_path): + for name in files: + if name.lower().endswith(".mf4"): + found.append(os.path.join(root, name)) + return sorted(found) + + +def _resolve_file_entry(base_path: str, entry: str) -> str: + """Resolve one ``files`` option entry to a normalized filesystem path.""" + if os.path.isabs(entry): + return os.path.normpath(entry) + return os.path.normpath(os.path.join(base_path, entry)) + + +def _resolve_file_list(options): + """Resolve the list of MDF4 file paths from data source options.""" + base_path = options.get("path") + if not base_path: + raise ValueError("Option 'path' is required: base directory containing MDF4 files") + + files_option = options.get("files", "") + if files_option.strip(): + filenames = [f.strip() for f in files_option.split(",") if f.strip()] + file_paths = [_resolve_file_entry(base_path, f) for f in filenames] + else: + file_paths = _discover_mf4_files(base_path) + + if not file_paths: + raise ValueError(f"No MDF4 files found in '{base_path}'") + + return file_paths + + +class MdfSignalsDataSource(DataSource): + """ + Custom PySpark data source that reads MDF4 signal data. + + Produces rows of (file_uri, channel_id, time, value). + + Options (in addition to path/files/target_partition_mb): + time_dtype, value_dtype: 'float64' (default) or 'float32'. float32 halves + the on-disk size of that column — useful when the source precision allows. + run_length_encoding: 'false' (default) or 'true'. When true, consecutive + equal samples of a channel are collapsed into a single row covering the + half-open interval [tstart, tend) over which the value stays constant + (zero-order hold), and the schema becomes + (file_uri, channel_id, tstart, tend, value). Each channel ends with a + zero-width point row (tstart == tend == last timestamp) so the final + sample is recoverable. + max_groups_per_partition: int (default 64). Upper bound on how many small + channel groups are coalesced into one Spark task (caps the scattered + block reads per task). Raise it to further cut task count for files with + very many tiny groups; lower it for more parallelism per group. + absolute_time: 'false' (default) or 'true'. When true, the MDF measurement + start time (UTC, sub-second precision) is ADDED to every timestamp so the + time columns are absolute Unix epoch seconds. Because epoch seconds need + ~31 bits of integer range, the time columns are forced to float64 + regardless of time_dtype (float32 cannot represent epoch seconds usefully). + """ + + @classmethod + def name(cls): + """Format string for spark.read.format(...): "mdf_signals".""" + return "mdf_signals" + + def _absolute_time(self): + return str(self.options.get("absolute_time", "false")).lower() == "true" + + def schema(self): + """Output schema: (file_uri, channel_id, time, value) — or the RLE variant + (file_uri, channel_id, tstart, tend, value) when run_length_encoding=true. + time/value follow time_dtype/value_dtype; absolute_time forces the time + columns to double.""" + # Built inline (no module-level helper reference): schema() runs when the + # data source instance is created server-side, and referencing a + # module-global function there forces a module import that can fail in + # that context. Inline imports of pyspark types are always safe. + from pyspark.sql.types import ( + StructType, StructField, StringType, IntegerType, DoubleType, FloatType, + ) + absolute = self._absolute_time() + + def _ftype(opt): + # absolute_time forces only the TIME columns to float64 (epoch seconds + # need the range); the value column always follows value_dtype, matching + # what the decoder emits — otherwise schema() and the Arrow batches + # disagree on `value` and the writer fails (getDouble on a float vector). + if absolute and opt == "time_dtype": + return DoubleType() + return FloatType() if str(self.options.get(opt, "float64")) == "float32" else DoubleType() + + if str(self.options.get("run_length_encoding", "false")).lower() == "true": + return StructType([ + StructField("file_uri", StringType(), False), + StructField("channel_id", IntegerType(), False), + StructField("tstart", _ftype("time_dtype"), False), + StructField("tend", _ftype("time_dtype"), False), + StructField("value", _ftype("value_dtype"), True), + ]) + + return StructType([ + StructField("file_uri", StringType(), False), + StructField("channel_id", IntegerType(), False), + StructField("time", _ftype("time_dtype"), False), + StructField("value", _ftype("value_dtype"), True), + ]) + + def reader(self, schema): + return MdfSignalsReader(self.options) + + +class MdfSignalsReader(DataSourceReader): + """Batch reader for MDF4 signal data.""" + + def __init__(self, options): + self.options = options + + def partitions(self): + """ + Plan partitions: scan each file's metadata, then use plan_partitions to + produce record-range / channel-subset partitions (decoupling parallelism + from channel count). Returns one InputPartition per spec, with the spec + JSON carried in InputPartition.value. + """ + _emit_read_telemetry("mdf_signals") + import json + from .mdf4_reader import MDF4Reader + from .bin_packer import plan_partitions, plan_stripes_for_file + + file_paths = _resolve_file_list(self.options) + target_partition_mb = float(self.options.get("target_partition_mb", "64")) + run_length_encoding = str(self.options.get("run_length_encoding", "false")).lower() == "true" + max_groups_per_partition = int(self.options.get("max_groups_per_partition", "64")) + absolute_time = str(self.options.get("absolute_time", "false")).lower() == "true" + # partitioning: "group" (default, per-group/record-range) or "stripe" + # (Design B byte-offset stripes — reads each file once to build the map). + partitioning = str(self.options.get("partitioning", "group")).lower() + stripe_target_mb = float(self.options.get("stripe_target_mb", "128")) + # Absolute time needs float64 for the time columns. + time_dtype = "float64" if absolute_time else str(self.options.get("time_dtype", "float64")) + value_dtype = str(self.options.get("value_dtype", "float64")) + + all_partition_specs = [] + for file_path in file_paths: + time_offset = 0.0 + if absolute_time: + start = MDF4Reader(file_path).read_header_start_epoch_seconds() + if start is None: + raise ValueError( + f"absolute_time=true but {file_path} has no measurement " + f"start time in its HD block") + time_offset = start + + if partitioning == "stripe": + specs = plan_stripes_for_file( + file_path, + target_partition_mb=target_partition_mb, + time_dtype=time_dtype, value_dtype=value_dtype, + run_length_encoding=run_length_encoding, + time_offset=time_offset, stripe_target_mb=stripe_target_mb, + ) + all_partition_specs.extend(json.dumps(s) for s in specs) + continue + + reader = MDF4Reader(file_path) + organized = reader.scan_channels_organized() + if not organized["signal_channels"]: + continue + specs = plan_partitions( + file_path, + organized["master_channels"], + organized["signal_channels"], + organized["channel_id_map"], + target_partition_mb=target_partition_mb, + time_dtype=time_dtype, value_dtype=value_dtype, + run_length_encoding=run_length_encoding, + max_groups_per_partition=max_groups_per_partition, + time_offset=time_offset, + ) + all_partition_specs.extend(json.dumps(s) for s in specs) + + # PySpark's Python DataSource API requires partitions() to return + # InputPartition instances (not plain dicts); the payload is carried in + # InputPartition.value and is read back in read(). + if not all_partition_specs: + return [InputPartition("[]")] + + return [InputPartition(spec_json) for spec_json in all_partition_specs] + + def read(self, partition): + """Read signal data for one partition (one bin of channels). + + Yields pyarrow.RecordBatch via the SAME shared Arrow conversion core as + the mapInArrow converter (udf_helpers.convert_spec_to_arrow_batches), so + the data source inherits the streaming / chunking / constant-array + optimizations instead of the slower row-by-row path. + """ + import json + import logging + from .udf_helpers import ( + convert_spec_to_arrow_batches, convert_stripe_spec_to_arrow_batches) + + spec_json = partition.value + if spec_json == "[]": + return + + spec = json.loads(spec_json) + # Prefer the dtype/flags baked into the spec by plan_partitions (these + # already reflect the absolute_time float64 override); fall back to + # options for older specs. + time_dtype = str(spec.get("time_dtype", self.options.get("time_dtype", "float64"))) + value_dtype = str(spec.get("value_dtype", self.options.get("value_dtype", "float64"))) + run_length_encoding = bool(spec.get( + "run_length_encoding", + str(self.options.get("run_length_encoding", "false")).lower() == "true")) + prof = {"read": 0, "decode": 0, "arrow": 0, "rows": 0} + # Stripe spec (Design B) carries "subblocks"; group spec carries "channels". + decode = (convert_stripe_spec_to_arrow_batches if "subblocks" in spec + else convert_spec_to_arrow_batches) + yield from decode( + spec, prof=prof, time_dtype=time_dtype, value_dtype=value_dtype, + run_length_encoding=run_length_encoding) + logging.getLogger("impulse_ds.mdf.convert").warning( + "MDF_PROFILE rows=%d read_ms=%.0f decode_ms=%.0f arrow_ms=%.0f", + prof["rows"], prof["read"] / 1e6, prof["decode"] / 1e6, prof["arrow"] / 1e6, + ) + + +class MdfMetadataDataSource(DataSource): + """ + Custom PySpark data source that reads MDF4 channel metadata. + + Produces rows of (file_uri, channel_id, group_idx, channel_idx, channel_name, unit, header_datetime, md_comment). + md_comment is the channel's cn_md_comment block (##MD XML header, or ##TX text), or null. + """ + + @classmethod + def name(cls): + """Format string for spark.read.format(...): "mdf_metadata".""" + return "mdf_metadata" + + def schema(self): + """Output schema: (file_uri, channel_id, group_idx, channel_idx, + channel_name, unit, header_datetime, md_comment).""" + return METADATA_SCHEMA + + def reader(self, schema): + return MdfMetadataReader(self.options) + + +class MdfMetadataReader(DataSourceReader): + """Batch reader for MDF4 metadata.""" + + def __init__(self, options): + self.options = options + + def partitions(self): + """One partition per file for metadata scanning.""" + _emit_read_telemetry("mdf_metadata") + file_paths = _resolve_file_list(self.options) + partitions = [InputPartition({"file_path": fp}) for fp in file_paths] + return partitions if partitions else [InputPartition({"file_path": ""})] + + def read(self, partition): + """Read channel metadata for one file.""" + from .mdf4_reader import MDF4Reader + + p = partition.value + file_path = p["file_path"] + + if not file_path: + return iter([]) + + reader = MDF4Reader(file_path) + organized = reader.scan_channels_organized() + header_datetime = reader.read_header_datetime() + + rows = [] + for ch_id, ch in enumerate(organized["signal_channels"]): + rows.append(( + file_path, + ch_id, + ch.group_idx, + ch.channel_idx, + ch.channel_name, + ch.unit or "", + header_datetime, + ch.md_comment or None, + )) + + return iter(rows) + + +class MdfMastersDataSource(DataSource): + """ + Custom PySpark data source that reads MDF4 MASTER channel data — the time + base of each acquisition group, one row per ORIGINAL sample. + + Produces rows of (file_uri, group_idx, timestamp). This is the companion + to run-length-encoded signals (format 'mdf_signals' with + run_length_encoding=true): RLE keeps only [tstart, tend] intervals, so the + original per-sample grid is recovered by joining a group's timestamps here + against those intervals (assign each interval's value to every group + timestamp t with tstart <= t < tend; <= tend for the final interval). + + Options: + path (required), files, target_partition_mb, + max_groups_per_partition: as for 'mdf_signals'. + time_dtype: 'float64' (default) or 'float32'. Use the SAME value as the + signals table so the [tstart, tend] join is exact. + absolute_time: 'false' (default) or 'true'. Adds the measurement start time + so timestamps are absolute Unix epoch seconds (UTC). Set the SAME value + as the signals table so the reverse-RLE join lines up; forces float64. + """ + + @classmethod + def name(cls): + """Format string for spark.read.format(...): "mdf_masters".""" + return "mdf_masters" + + def schema(self): + """Output schema: (file_uri, group_idx, timestamp) — one row per original + master sample. timestamp is float (double unless time_dtype=float32, or + absolute_time which forces double).""" + from pyspark.sql.types import ( + StructType, StructField, StringType, IntegerType, DoubleType, FloatType, + ) + absolute = str(self.options.get("absolute_time", "false")).lower() == "true" + ts_type = DoubleType() if absolute or str(self.options.get("time_dtype", "float64")) != "float32" else FloatType() + return StructType([ + StructField("file_uri", StringType(), False), + StructField("group_idx", IntegerType(), False), + StructField("timestamp", ts_type, False), + ]) + + def reader(self, schema): + return MdfMastersReader(self.options) + + +class MdfMastersReader(DataSourceReader): + """Batch reader for MDF4 master (time-base) data.""" + + def __init__(self, options): + self.options = options + + def partitions(self): + """Plan per-group master partitions (record-range split for big groups, + coalescing for small ones), one InputPartition per spec.""" + _emit_read_telemetry("mdf_masters") + import json + from .mdf4_reader import MDF4Reader + from .bin_packer import plan_master_partitions + + file_paths = _resolve_file_list(self.options) + target_partition_mb = float(self.options.get("target_partition_mb", "64")) + max_groups_per_partition = int(self.options.get("max_groups_per_partition", "64")) + absolute_time = str(self.options.get("absolute_time", "false")).lower() == "true" + time_dtype = "float64" if absolute_time else str(self.options.get("time_dtype", "float64")) + + all_specs = [] + for file_path in file_paths: + reader = MDF4Reader(file_path) + organized = reader.scan_channels_organized() + if not organized["master_channels"]: + continue + time_offset = 0.0 + if absolute_time: + start = reader.read_header_start_epoch_seconds() + if start is None: + raise ValueError( + f"absolute_time=true but {file_path} has no measurement " + f"start time in its HD block") + time_offset = start + specs = plan_master_partitions( + file_path, organized["master_channels"], + target_partition_mb=target_partition_mb, + time_dtype=time_dtype, + max_groups_per_partition=max_groups_per_partition, + time_offset=time_offset, + ) + all_specs.extend(json.dumps(s) for s in specs) + + if not all_specs: + return [InputPartition("[]")] + return [InputPartition(spec_json) for spec_json in all_specs] + + def read(self, partition): + """Yield pyarrow.RecordBatch of (file_uri, group_idx, timestamp) for + one master spec, via the shared master decode core.""" + import json + import logging + from .udf_helpers import convert_master_spec_to_arrow_batches + + spec_json = partition.value + if spec_json == "[]": + return + + spec = json.loads(spec_json) + # Use the dtype baked into the spec (reflects the absolute_time override). + time_dtype = str(spec.get("time_dtype", self.options.get("time_dtype", "float64"))) + prof = {"read": 0, "decode": 0, "arrow": 0, "rows": 0} + yield from convert_master_spec_to_arrow_batches( + spec, prof=prof, time_dtype=time_dtype) + logging.getLogger("impulse_ds.mdf.convert").warning( + "MDF_PROFILE(masters) rows=%d read_ms=%.0f decode_ms=%.0f arrow_ms=%.0f", + prof["rows"], prof["read"] / 1e6, prof["decode"] / 1e6, prof["arrow"] / 1e6, + ) diff --git a/src/impulse_ds/mdf/mdf4_reader.py b/src/impulse_ds/mdf/mdf4_reader.py new file mode 100644 index 00000000..249dcb8f --- /dev/null +++ b/src/impulse_ds/mdf/mdf4_reader.py @@ -0,0 +1,646 @@ +""" +Low-level MDF4 binary reader for extracting channel data without loading +the entire file into memory. Designed to be used inside Spark workers +where each task reads only the channels assigned to it. + +MDF4 format reference: ASAM MDF v4.x specification. +Key blocks: HD (Header), DG (Data Group), CG (Channel Group), CN (Channel), + DT/DZ/DL (Data blocks). +""" + +import struct +from datetime import datetime, timezone +import numpy as np +from typing import BinaryIO, List, Tuple, Dict, Optional +from dataclasses import dataclass + + +# MDF4 block IDs +BLOCK_ID_HD = b"##HD" +BLOCK_ID_DG = b"##DG" +BLOCK_ID_CG = b"##CG" +BLOCK_ID_CN = b"##CN" +BLOCK_ID_DT = b"##DT" +BLOCK_ID_DZ = b"##DZ" +BLOCK_ID_DL = b"##DL" +BLOCK_ID_SD = b"##SD" +BLOCK_ID_TX = b"##TX" +BLOCK_ID_CC = b"##CC" +BLOCK_ID_SI = b"##SI" + +# MDF4 data types for CN blocks +CN_DATA_TYPE_UNSIGNED_INT_LE = 0 +CN_DATA_TYPE_UNSIGNED_INT_BE = 1 +CN_DATA_TYPE_SIGNED_INT_LE = 2 +CN_DATA_TYPE_SIGNED_INT_BE = 3 +CN_DATA_TYPE_FLOAT_LE = 4 +CN_DATA_TYPE_FLOAT_BE = 5 +CN_DATA_TYPE_STRING_LATIN = 6 +CN_DATA_TYPE_STRING_UTF8 = 7 +CN_DATA_TYPE_STRING_UTF16_LE = 8 +CN_DATA_TYPE_STRING_UTF16_BE = 9 +CN_DATA_TYPE_BYTE_ARRAY = 10 +CN_DATA_TYPE_MIME_SAMPLE = 11 +CN_DATA_TYPE_MIME_STREAM = 12 +CN_DATA_TYPE_CANOPEN_DATE = 13 +CN_DATA_TYPE_CANOPEN_TIME = 14 +CN_DATA_TYPE_COMPLEX_LE = 15 +CN_DATA_TYPE_COMPLEX_BE = 16 + +# Channel types +CN_TYPE_FIXED = 0 +CN_TYPE_VLSD = 1 +CN_TYPE_MASTER = 2 +CN_TYPE_VIRTUAL_MASTER = 3 +CN_TYPE_SYNC = 4 +CN_TYPE_MLSD = 5 +CN_TYPE_VIRTUAL_DATA = 6 + +# CN flags for invalidation +CN_FLAG_ALL_INVALID = 1 +CN_FLAG_INVALIDATION_PRESENT = 1 << 1 + + +@dataclass +class ChannelInfo: + """Metadata for a single channel within an MDF4 file.""" + group_idx: int + channel_idx: int + channel_name: str + unit: str + sample_count: int + data_type: int + bit_offset: int + byte_offset: int + bit_count: int + channel_type: int + # Offsets for direct binary access + cn_block_addr: int + cg_block_addr: int + dg_block_addr: int + data_block_addr: int + record_size: int # total bytes per record in this channel group (incl rec_id) + # Invalidation bit handling + cn_flags: int = 0 + invalidation_bit_pos: int = 0 + invalidation_bytes: int = 0 # number of invalidation bytes per record in this CG + data_bytes: int = 0 # data bytes per record (record_size - invalidation_bytes) + # CC (Channel Conversion) block + cc_type: int = -1 # -1 = no conversion, 0 = identity, 1 = linear, etc. + cc_params: tuple = () + # Record ID for unsorted data groups + rec_id_size: int = 0 # 0=sorted, 1/2/4/8=unsorted + record_id: int = 0 # cg_record_id for this channel group + # Raw cn_md_comment block text (##MD XML or ##TX), or "" if none + md_comment: str = "" + + +@dataclass +class DataGroupInfo: + """Metadata for a data group.""" + address: int + data_block_addr: int + channel_groups: List["ChannelGroupInfo"] + + +@dataclass +class ChannelGroupInfo: + """Metadata for a channel group.""" + address: int + record_id: int + cycle_count: int + data_bytes: int + invalidation_bytes: int + channels: List[ChannelInfo] + + +class MDF4Reader: + """ + Reads MDF4 file structure and extracts raw signal data using + direct binary access with minimal memory footprint. + """ + + def __init__(self, file_path: str = None, file_bytes: "bytes" = None): + """Read from a path, or from an in-memory buffer (file_bytes) so a caller + that already loaded the whole file once (Design B planning) can scan + + build the block map from RAM without re-reading the volume.""" + self.file_path = file_path + self._file_bytes = file_bytes + self._data_groups: Optional[List[DataGroupInfo]] = None + self._text_cache: Dict[int, str] = {} # address -> TX/MD text (immutable per file) + + def _open(self): + """Context manager yielding a seekable binary source (in-RAM buffer if + file_bytes was provided, else the file on disk).""" + import contextlib + import io + if self._file_bytes is not None: + @contextlib.contextmanager + def _buf(): + yield io.BytesIO(self._file_bytes) + return _buf() + return open(self.file_path, "rb") + + def _read_hd_start_utc_ns(self) -> Optional[int]: + """Read the measurement start time from the HD block as UTC nanoseconds + since the Unix epoch (full precision), or None if not set. + + The HD block stores the start time in nanoseconds plus, when the local + time flag and offsets-valid flag are both set, a timezone+DST offset in + minutes; that offset is subtracted to normalize to UTC. + """ + with self._open() as f: + f.seek(0) + sig = f.read(8) + if not sig.startswith(b"MDF"): + raise ValueError(f"Not a valid MDF file: {self.file_path}") + + # ID block is 64 bytes; HD block is fixed at offset 64. + f.seek(64) + block_id = f.read(4) + if block_id != BLOCK_ID_HD: + raise ValueError(f"Expected HD block at offset 64, got {block_id}") + f.read(4) # reserved + f.read(8) # block length + hd_link_count = struct.unpack(" Optional[datetime]: + """ + Read measurement start datetime from the MDF4 HD block. + + Returns: + Naive UTC datetime if present, otherwise None. + """ + utc_ns = self._read_hd_start_utc_ns() + if utc_ns is None: + return None + seconds, nanoseconds = divmod(utc_ns, 1_000_000_000) + dt = datetime.fromtimestamp(seconds, tz=timezone.utc).replace( + microsecond=nanoseconds // 1000, + ) + return dt.replace(tzinfo=None) + + def read_header_start_epoch_seconds(self) -> Optional[float]: + """Measurement start time as Unix epoch seconds (UTC), as a float with + the HD block's sub-second precision (not rounded to whole seconds), or + None if not set. Used to make signal timestamps absolute. + + Note: at present-day epoch magnitudes (~1.8e9 s) a float64 resolves to + ~0.3 us, so absolute times keep sub-microsecond — not full nanosecond — + precision. + """ + utc_ns = self._read_hd_start_utc_ns() + return None if utc_ns is None else utc_ns / 1e9 + + def _read_text_block(self, f: BinaryIO, address: int) -> str: + """Read a TX or MD text block, returning the string content. Cached by + address (text blocks are immutable, and an MD comment is often shared by + many channels — avoids re-reading the same block per channel).""" + if address == 0: + return "" + cached = self._text_cache.get(address) + if cached is not None: + return cached + f.seek(address) + block_id = f.read(4) + if block_id not in (BLOCK_ID_TX, b"##MD"): + self._text_cache[address] = "" + return "" + f.read(4) # reserved + block_len = struct.unpack("= 0: + raw = raw[:null_pos] + try: + text = raw.decode("utf-8") + except UnicodeDecodeError: + text = raw.decode("latin-1") + self._text_cache[address] = text + return text + + @staticmethod + def _parse_cc_block(f: BinaryIO, cc_addr: int) -> Tuple[int, tuple]: + """ + Parse a CC (Channel Conversion) block and return (cc_type, cc_params). + + Returns (-1, ()) if the block is invalid or address is 0. + """ + if cc_addr == 0: + return -1, () + f.seek(cc_addr) + block_id = f.read(4) + if block_id != BLOCK_ID_CC: + return -1, () + f.read(4) # reserved + block_len = struct.unpack(" 0: + cc_params = struct.unpack(f"<{cc_val_count}d", f.read(8 * cc_val_count)) + else: + cc_params = () + + # Only support numeric conversion types (0-6) + if cc_type > 6: + return -1, () + + return cc_type, cc_params + + def scan_metadata(self) -> List[ChannelInfo]: + """ + Scan the MDF4 file to extract all channel metadata without + reading actual signal data. Returns list of ChannelInfo objects. + """ + channels = [] + with self._open() as f: + # Verify MDF4 signature + f.seek(0) + sig = f.read(8) + if not sig.startswith(b"MDF"): + raise ValueError(f"Not a valid MDF file: {self.file_path}") + + # Read identification block to get header address + # ID block is 64 bytes, HD block starts at offset 64 + hd_addr = 64 + + # Read HD block + f.seek(hd_addr) + block_id = f.read(4) + if block_id != BLOCK_ID_HD: + raise ValueError(f"Expected HD block at offset 64, got {block_id}") + f.read(4) # reserved + hd_block_len = struct.unpack(" 1 else 0 + # In MDF4, link order is: next_cn, composition, tx_name, si_source, cc_conversion, data, unit, comment + # But link count varies; for standard channels: + # link 0: next CN + # link 1: composition + # link 2: TX name + # link 3: SI source + # link 4: CC conversion + # link 5: signal data (for VLSD) + # link 6: TX unit + # link 7: TX/MD comment + tx_name_addr = cn_links[2] if cn_link_count > 2 else 0 + cc_addr = cn_links[4] if cn_link_count > 4 else 0 + unit_addr = cn_links[6] if cn_link_count > 6 else 0 + comment_addr = cn_links[7] if cn_link_count > 7 else 0 + + # CN data section (after links). The fields the converter + # actually uses are cn_type, cn_data_type, cn_bit_offset, + # cn_byte_offset, cn_bit_count, cn_flags, cn_invalid_bit_pos. + # The rest (sync_type, precision, attachment_count, value/ + # limit ranges) are read in spec order purely to advance the + # file position; they are named to document the block layout. + cn_type = struct.unpack(" np.ndarray: + """ + Read raw signal data for a single channel directly from the binary file. + Returns values as a numpy float64 array with CC conversion applied. + Invalid samples (per the MDF4 invalidation bit mechanism) are marked with np.nan. + + If an open file handle `f` is provided, it will be used instead of + opening the file again. + + This delegates to the executor-side decode functions in udf_helpers so + that this reference API exercises the exact code path used in Spark. + """ + from .udf_helpers import read_raw_data, extract_signal + + ch_spec = { + "channel_type": channel_type, + "data_type": data_type, + "bit_count": bit_count, + "byte_offset": byte_offset, + "bit_offset": bit_offset, + "record_size": record_size, + "cn_flags": cn_flags, + "invalidation_bit_pos": invalidation_bit_pos, + "invalidation_bytes": invalidation_bytes, + "data_bytes": data_bytes, + "cc_type": cc_type, + "cc_params": list(cc_params) if cc_params else [], + } + + def _extract(raw_data): + if not raw_data or record_size <= 0: + return np.array([], dtype=np.float64) + values = extract_signal(raw_data, record_size, ch_spec) + if values is None: + return np.array([], dtype=np.float64) + return values + + if f is not None: + raw_data = read_raw_data(f, data_block_addr, record_size, sample_count) + return _extract(raw_data) + + with open(file_path, "rb") as fh: + raw_data = read_raw_data(fh, data_block_addr, record_size, sample_count) + + return _extract(raw_data) + + @staticmethod + def read_channel_pair( + file_path: str, + master_info: dict, + signal_info: dict, + sample_count: int, + f: Optional[BinaryIO] = None, + ) -> Tuple[np.ndarray, np.ndarray]: + """ + Read both master (time) and signal channel data for a channel group. + Returns (timestamps, values) both as float64 arrays. + Invalid signal samples are marked with np.nan based on invalidation bits. + + If an open file handle `f` is provided, it will be used instead of + opening the file again. + """ + from .udf_helpers import ( + read_raw_data, extract_signal, extract_timestamps, + ) + + def _do_read(fh: BinaryIO) -> Tuple[np.ndarray, np.ndarray]: + data_block_addr = signal_info["data_block_addr"] + record_size = signal_info["record_size"] + + # Read the raw data block once (shared between master and signal) + raw_data = read_raw_data(fh, data_block_addr, record_size, sample_count) + + actual_samples = len(raw_data) // record_size if record_size else 0 + if master_info: + timestamps = extract_timestamps(raw_data, record_size, master_info) + else: + timestamps = np.arange(actual_samples, dtype=np.float64) + + values = extract_signal(raw_data, record_size, signal_info) + if values is None: + values = np.full(len(timestamps), np.nan, dtype=np.float64) + + return timestamps, values + + if f is not None: + return _do_read(f) + + with open(file_path, "rb") as fh: + return _do_read(fh) + + + def scan_channels_organized(self) -> dict: + """ + Scan metadata and return channels organized into masters and signals. + + Returns dict with: + "master_channels": {group_idx: ChannelInfo} - one master per group + "signal_channels": [ChannelInfo] - all non-master channels + "channel_id_map": {(group_idx, channel_idx): channel_id} - sequential IDs for signals + """ + all_channels = self.scan_metadata() + master_channels = {} + signal_channels = [] + channel_id_map = {} + channel_id = 0 + + for ch in all_channels: + if ch.channel_type in (CN_TYPE_MASTER, CN_TYPE_VIRTUAL_MASTER): + master_channels[ch.group_idx] = ch + else: + channel_id_map[(ch.group_idx, ch.channel_idx)] = channel_id + signal_channels.append(ch) + channel_id += 1 + + return { + "master_channels": master_channels, + "signal_channels": signal_channels, + "channel_id_map": channel_id_map, + } + + @staticmethod + def channel_to_dict(ch: "ChannelInfo") -> dict: + """Convert a ChannelInfo to a serializable dict suitable for bin packing.""" + return { + "group_idx": ch.group_idx, + "channel_idx": ch.channel_idx, + "sample_count": ch.sample_count, + "channel_name": ch.channel_name, + "unit": ch.unit, + "data_type": ch.data_type, + "bit_offset": ch.bit_offset, + "byte_offset": ch.byte_offset, + "bit_count": ch.bit_count, + "channel_type": ch.channel_type, + "data_block_addr": ch.data_block_addr, + "record_size": ch.record_size, + "cn_flags": ch.cn_flags, + "invalidation_bit_pos": ch.invalidation_bit_pos, + "invalidation_bytes": ch.invalidation_bytes, + "data_bytes": ch.data_bytes, + "cc_type": ch.cc_type, + "cc_params": list(ch.cc_params) if ch.cc_params else [], + } + + @staticmethod + def master_to_dict(ch: "ChannelInfo") -> dict: + """Convert a master ChannelInfo to a serializable dict for timestamp extraction.""" + return { + "byte_offset": ch.byte_offset, + "bit_offset": ch.bit_offset, + "bit_count": ch.bit_count, + "data_type": ch.data_type, + "channel_type": ch.channel_type, + "cc_type": ch.cc_type, + "cc_params": list(ch.cc_params) if ch.cc_params else [], + } diff --git a/src/impulse_ds/mdf/mdf_blocks.py b/src/impulse_ds/mdf/mdf_blocks.py new file mode 100644 index 00000000..1d611cba --- /dev/null +++ b/src/impulse_ds/mdf/mdf_blocks.py @@ -0,0 +1,394 @@ +""" +Low-level MDF4 data-block I/O: read and decompress ``##DT`` (uncompressed), +``##DZ`` (zlib, possibly transposed), and ``##DL``/``##HL`` (data lists) blocks, +and stream record ranges. Pure binary helpers (struct/zlib/numpy) shared by the +Arrow emitters; they operate on an open binary file object (real file or an +in-memory ``BytesIO``). +""" +import struct +import zlib +import numpy as np + + +def _read_dz_header(f, dz_addr): + """Read DZ block header fields, return (zip_type, zip_parameter, org_size, data_length).""" + f.seek(dz_addr + 24) # skip id(4) + reserved(4) + length(8) + link_count(8) + f.read(2) # org_block_type + dz_zip_type = struct.unpack(" un-transpose + cols = zip_param + rows = len(dec) // cols + remainder = len(dec) % cols + if remainder == 0: + dec = np.frombuffer(dec, dtype=np.uint8).reshape(cols, rows).T.tobytes() + else: + src = np.frombuffer(dec, dtype=np.uint8) + dest_idx = np.empty(len(src), dtype=np.int64) + pos = 0 + for col in range(cols): + cs = rows + (1 if col < remainder else 0) + dest_idx[pos:pos + cs] = np.arange(cs) * cols + col + pos += cs + out = np.empty(len(src), dtype=np.uint8) + out[dest_idx] = src + dec = out.tobytes() + return dec + length = struct.unpack_from("= row_end: + continue + if first is None: + first = rs + parts.append(_decompress_subblock_blob(blob, off) if covered else _read_subblock_file(f, addr)) + if first is None: + return b"", row_start + raw = b"".join(parts) + start_off = (row_start - first) * record_size + end_off = (row_end - first) * record_size + return raw[start_off:end_off], row_start + + +def read_raw_data(f, data_block_addr, record_size, sample_count): + """Read raw record data from any block type (DT, DL, DZ, HL) using an open handle.""" + f.seek(data_block_addr) + block_id = f.read(4) + if block_id == b"##DT": + f.read(4) + dt_block_len = struct.unpack(" the whole block. Shared by the master decoder + so it inherits the streaming/coalescing behaviour without duplicating it.""" + import time + _now = time.perf_counter_ns + _CHUNK_BYTES = 256 * 1024 * 1024 + + try: + extent = dt_data_extent(f, data_block_addr) + except Exception as e: + log.warning("DT extent probe failed at %d: %s", data_block_addr, e) + extent = None + + if extent is not None: + data_start, data_size = extent + total = data_size // record_size if record_size else 0 + if total == 0: + return + lo = 0 if row_start is None else max(0, min(row_start, total)) + hi = total if row_end is None else max(lo, min(row_end, total)) + chunk_records = max(1, _CHUNK_BYTES // record_size) + for rec0 in range(lo, hi, chunk_records): + recN = min(rec0 + chunk_records, hi) + nrec = recN - rec0 + t0 = _now() + f.seek(data_start + rec0 * record_size) + raw = f.read(nrec * record_size) + prof["read"] += _now() - t0 + if len(raw) // record_size: + yield raw, rec0 + return + + if row_start is not None: + dl_addr = resolve_dl_addr(f, data_block_addr) + if dl_addr is not None: + re_hi = row_end if row_end is not None else (1 << 62) + t0 = _now() + raw, start = read_data_list_range(f, dl_addr, record_size, row_start, re_hi) + prof["read"] += _now() - t0 + if len(raw) // record_size: + yield raw, start + return + + t0 = _now() + raw = read_raw_data(f, data_block_addr, record_size, sample_count) + prof["read"] += _now() - t0 + total = len(raw) // record_size if record_size else 0 + if total == 0: + return + if row_start is not None: + lo = max(0, min(row_start, total)) + hi = total if row_end is None else max(lo, min(row_end, total)) + raw = raw[lo * record_size:hi * record_size] + start = lo + else: + start = 0 + if len(raw) // record_size: + yield raw, start + + +def parse_subblocks(f, data_block_addr, record_size, sample_count): + """Return the data sub-blocks of ONE group as a list of + (abs_offset, on_disk_len, rec_start, rec_count). Used to build the block map + during planning; `f` is expected to be the in-RAM whole-file buffer so the + per-sub-block header reads are free (no scattered disk IO). A standalone + ##DT/##DZ is a single sub-block; a ##DL/##HL chain yields one entry per + referenced data block. + """ + f.seek(data_block_addr) + bid = f.read(4) + if bid in (b"##DT", b"##DZ"): + f.seek(data_block_addr + 8) + length = struct.unpack(" 0: + vals = vals >> bit_offset + if bit_count < 64: + vals = vals & ((1 << bit_count) - 1) + return vals.astype(np.float64) + elif data_type in (SINT_LE, SINT_BE): + is_be = data_type == SINT_BE + if bit_count <= 8: + vals = raw_bytes[:, 0].astype(np.uint64) + elif bit_count <= 16: + if value_bytes == 2 and not is_be: + vals = raw_bytes.view(np.uint16).reshape(sample_count).astype(np.uint64) + else: + padded = np.zeros((sample_count, 2), dtype=np.uint8) + padded[:, :value_bytes] = raw_bytes[:, :value_bytes] + if is_be: + padded = padded[:, ::-1].copy() + vals = padded.view(np.uint16).reshape(sample_count).astype(np.uint64) + elif bit_count <= 32: + if value_bytes == 4 and not is_be: + vals = raw_bytes.view(np.uint32).reshape(sample_count).astype(np.uint64) + else: + padded = np.zeros((sample_count, 4), dtype=np.uint8) + padded[:, :value_bytes] = raw_bytes[:, :value_bytes] + if is_be: + padded = padded[:, ::-1].copy() + vals = padded.view(np.uint32).reshape(sample_count).astype(np.uint64) + else: + if value_bytes == 8 and not is_be: + vals = raw_bytes.view(np.uint64).reshape(sample_count) + else: + padded = np.zeros((sample_count, 8), dtype=np.uint8) + padded[:, :value_bytes] = raw_bytes[:, :value_bytes] + if is_be: + padded = padded[:, ::-1].copy() + vals = padded.view(np.uint64).reshape(sample_count) + if bit_offset > 0: + vals = vals >> bit_offset + vals = vals & ((1 << bit_count) - 1) + sign_bit = np.uint64(1 << (bit_count - 1)) + vals = np.where(vals & sign_bit, vals.astype(np.int64) - (1 << bit_count), vals.astype(np.int64)) + return vals.astype(np.float64) + else: + return np.zeros(sample_count, dtype=np.float64) + + +def extract_column_strided(raw_data, record_size, byte_offset, value_bytes, sample_count): + """Extract column bytes using strided access (avoids full 2D reshape).""" + buf = np.frombuffer(raw_data, dtype=np.uint8) + return np.lib.stride_tricks.as_strided( + buf[byte_offset:], + shape=(sample_count, value_bytes), + strides=(record_size, 1), + ).copy() + + +def apply_invalidation(buf, record_size, actual_samples, values, signal_info): + """Apply invalidation bits to values array, setting invalid samples to NaN. + + buf: np.ndarray (uint8) view of the raw data, or raw bytes. + """ + invalidation_bytes_nr = signal_info.get("invalidation_bytes", 0) + cn_flags = signal_info.get("cn_flags", 0) + if invalidation_bytes_nr <= 0: + return values + if not (cn_flags & (CN_FLAG_ALL_INVALID | CN_FLAG_INVALIDATION_PRESENT)): + return values + if cn_flags & CN_FLAG_ALL_INVALID: + values[:] = np.nan + return values + data_bytes_nr = signal_info.get("data_bytes", 0) + inv_bit_pos = signal_info.get("invalidation_bit_pos", 0) + byte_pos = inv_bit_pos // 8 + bit_pos = inv_bit_pos % 8 + inval_col = data_bytes_nr + byte_pos + if not isinstance(buf, np.ndarray): + buf = np.frombuffer(buf, dtype=np.uint8) + inval_bytes = np.lib.stride_tricks.as_strided( + buf[inval_col:], + shape=(actual_samples,), + strides=(record_size,), + ).copy() + invalid_mask = (inval_bytes & (1 << bit_pos)).astype(bool) + values[invalid_mask] = np.nan + return values + + +def apply_cc_conversion(values, cc_type, cc_params): + """ + Apply MDF4 CC (Channel Conversion) block scaling to raw values. + Modifies values in-place where possible to reduce allocations. + """ + if cc_type < 0 or cc_type == CC_IDENTITY or not cc_params: + return values + if cc_type == CC_LINEAR: + b, a = cc_params[0], cc_params[1] + if a != 1.0: + values *= a + if b != 0.0: + values += b + return values + if cc_type == CC_RATIONAL: + P1, P2, P3, P4, P5, P6 = cc_params[:6] + X = values + num = P1 * X * X + P2 * X + P3 + den = P4 * X * X + P5 * X + P6 + with np.errstate(divide="ignore", invalid="ignore"): + np.divide(num, den, out=values) + return values + if cc_type == CC_TAB_INTERP: + raw_tab = np.array(cc_params[0::2]) + phys_tab = np.array(cc_params[1::2]) + return np.interp(values, raw_tab, phys_tab) + if cc_type == CC_TAB_NOINTERP: + n = len(cc_params) // 2 + raw_tab = np.array(cc_params[0::2]) + phys_tab = np.array(cc_params[1::2]) + inds = np.searchsorted(raw_tab, values) + inds = np.clip(inds, 0, n - 1) + inds2 = np.clip(inds - 1, 0, n - 1) + cond = np.abs(values - raw_tab[inds]) >= np.abs(values - raw_tab[inds2]) + return np.where(cond, phys_tab[inds2], phys_tab[inds]) + if cc_type == CC_RANGE_TO_VALUE: + n = (len(cc_params) - 1) // 3 + default = cc_params[3 * n] if len(cc_params) > 3 * n else np.nan + if n <= 0: + return np.full_like(values, default) + # Vectorized: build sorted lower-bound edges and use searchsorted + lowers = np.array([cc_params[i * 3] for i in range(n)]) + uppers = np.array([cc_params[i * 3 + 1] for i in range(n)]) + phys_vals = np.array([cc_params[i * 3 + 2] for i in range(n)]) + # Find which range each value falls into + indices = np.searchsorted(lowers, values, side='right') - 1 + indices = np.clip(indices, 0, n - 1) + result = np.where( + (values >= lowers[indices]) & (values < uppers[indices]), + phys_vals[indices], + default, + ) + return result + return values + + +def extract_signal(raw_data, record_size, ch_spec): + """Extract and convert a signal channel from raw data.""" + actual = len(raw_data) // record_size + if actual == 0: + return None + if ch_spec.get("channel_type") == 1: # VLSD + return np.full(actual, np.nan, dtype=np.float64) + + usable = raw_data[:actual * record_size] + s_data_type = ch_spec["data_type"] + s_bit_count = ch_spec["bit_count"] + s_byte_offset = ch_spec["byte_offset"] + s_bit_offset = ch_spec["bit_offset"] + s_bytes = (s_bit_count + 7) // 8 + + buf = np.frombuffer(usable, dtype=np.uint8) + + # Fast paths: direct strided view for common aligned types (no column copy) + if s_bit_offset == 0: + if s_data_type == FLOAT_LE and s_bit_count == 64 and s_byte_offset % 8 == 0: + values = np.ndarray( + shape=(actual,), dtype=np.float64, buffer=buf, + offset=s_byte_offset, strides=(record_size,), + ).copy() + elif s_data_type == FLOAT_LE and s_bit_count == 32 and s_byte_offset % 4 == 0: + values = np.ndarray( + shape=(actual,), dtype=np.float32, buffer=buf, + offset=s_byte_offset, strides=(record_size,), + ).astype(np.float64) + elif s_data_type == UINT_LE and s_bit_count == 16 and s_byte_offset % 2 == 0: + values = np.ndarray( + shape=(actual,), dtype=np.uint16, buffer=buf, + offset=s_byte_offset, strides=(record_size,), + ).astype(np.float64) + elif s_data_type == UINT_LE and s_bit_count == 32 and s_byte_offset % 4 == 0: + values = np.ndarray( + shape=(actual,), dtype=np.uint32, buffer=buf, + offset=s_byte_offset, strides=(record_size,), + ).astype(np.float64) + elif s_data_type == UINT_LE and s_bit_count == 8: + values = np.ndarray( + shape=(actual,), dtype=np.uint8, buffer=buf, + offset=s_byte_offset, strides=(record_size,), + ).astype(np.float64) + elif s_data_type == SINT_LE and s_bit_count == 16 and s_byte_offset % 2 == 0: + values = np.ndarray( + shape=(actual,), dtype=np.int16, buffer=buf, + offset=s_byte_offset, strides=(record_size,), + ).astype(np.float64) + elif s_data_type == SINT_LE and s_bit_count == 32 and s_byte_offset % 4 == 0: + values = np.ndarray( + shape=(actual,), dtype=np.int32, buffer=buf, + offset=s_byte_offset, strides=(record_size,), + ).astype(np.float64) + elif s_data_type == SINT_LE and s_bit_count == 8: + values = np.ndarray( + shape=(actual,), dtype=np.int8, buffer=buf, + offset=s_byte_offset, strides=(record_size,), + ).astype(np.float64) + elif s_data_type == UINT_LE and s_bit_count == 64 and s_byte_offset % 8 == 0: + values = np.ndarray( + shape=(actual,), dtype=np.uint64, buffer=buf, + offset=s_byte_offset, strides=(record_size,), + ).astype(np.float64) + elif s_data_type == SINT_LE and s_bit_count == 64 and s_byte_offset % 8 == 0: + values = np.ndarray( + shape=(actual,), dtype=np.int64, buffer=buf, + offset=s_byte_offset, strides=(record_size,), + ).astype(np.float64) + else: + sig_raw = extract_column_strided(usable, record_size, s_byte_offset, s_bytes, actual) + values = convert_values(sig_raw, s_data_type, s_bit_count, s_bit_offset, actual) + else: + sig_raw = extract_column_strided(usable, record_size, s_byte_offset, s_bytes, actual) + values = convert_values(sig_raw, s_data_type, s_bit_count, s_bit_offset, actual) + + # Apply invalidation — pass buf to avoid redundant np.frombuffer + cn_flags = ch_spec.get("cn_flags", 0) + invalidation_bytes_nr = ch_spec.get("invalidation_bytes", 0) + if invalidation_bytes_nr > 0 and (cn_flags & (CN_FLAG_ALL_INVALID | CN_FLAG_INVALIDATION_PRESENT)): + signal_info = { + "cn_flags": cn_flags, + "invalidation_bit_pos": ch_spec.get("invalidation_bit_pos", 0), + "invalidation_bytes": invalidation_bytes_nr, + "data_bytes": ch_spec.get("data_bytes", 0), + } + values = apply_invalidation(buf, record_size, actual, values, signal_info) + + # Apply CC conversion if present + cc_type = ch_spec.get("cc_type", -1) + cc_params = ch_spec.get("cc_params") + if cc_type > 0 and cc_params: + values = apply_cc_conversion(values, cc_type, cc_params) + + return values + + +def extract_timestamps(raw_data, record_size, master_info, index_offset=0): + """Extract timestamps from raw data given master channel info. + + index_offset shifts the implicit sample index for virtual masters. It must + be set to the absolute index of the first record when raw_data is a chunk of + a larger block, so that virtual-master timestamps stay globally continuous. + """ + actual = len(raw_data) // record_size + if actual == 0: + return np.array([], dtype=np.float64) + if master_info["channel_type"] == 3: # virtual master + timestamps = np.arange(index_offset, index_offset + actual, dtype=np.float64) + else: + usable = raw_data[:actual * record_size] + m_bit_count = master_info["bit_count"] + m_byte_offset = master_info["byte_offset"] + m_bit_offset = master_info["bit_offset"] + m_data_type = master_info["data_type"] + m_bytes = (m_bit_count + 7) // 8 + + buf = np.frombuffer(usable, dtype=np.uint8) + + if m_bit_offset == 0 and m_data_type == FLOAT_LE and m_bit_count == 64 and m_byte_offset % 8 == 0: + timestamps = np.ndarray( + shape=(actual,), dtype=np.float64, buffer=buf, + offset=m_byte_offset, strides=(record_size,), + ).copy() + elif m_bit_offset == 0 and m_data_type == FLOAT_LE and m_bit_count == 32 and m_byte_offset % 4 == 0: + timestamps = np.ndarray( + shape=(actual,), dtype=np.float32, buffer=buf, + offset=m_byte_offset, strides=(record_size,), + ).astype(np.float64) + elif m_bit_offset == 0 and m_data_type == UINT_LE and m_bit_count == 64 and m_byte_offset % 8 == 0: + timestamps = np.ndarray( + shape=(actual,), dtype=np.uint64, buffer=buf, + offset=m_byte_offset, strides=(record_size,), + ).astype(np.float64) + else: + master_raw = extract_column_strided(usable, record_size, m_byte_offset, m_bytes, actual) + timestamps = convert_values(master_raw, m_data_type, m_bit_count, m_bit_offset, actual) + + # Apply CC conversion to master channel if present + cc_type = master_info.get("cc_type", -1) + cc_params = master_info.get("cc_params") + if cc_type > 0 and cc_params: + timestamps = apply_cc_conversion(timestamps, cc_type, cc_params) + + return timestamps diff --git a/src/impulse_ds/mdf/schemas.py b/src/impulse_ds/mdf/schemas.py new file mode 100644 index 00000000..dfa45ea4 --- /dev/null +++ b/src/impulse_ds/mdf/schemas.py @@ -0,0 +1,29 @@ +"""Shared Spark schemas for MDF converter modules.""" + +from pyspark.sql.types import ( + StructType, + StructField, + IntegerType, + DoubleType, + StringType, + TimestampType, +) + + +SIGNALS_SCHEMA = StructType([ + StructField("file_uri", StringType(), False), + StructField("channel_id", IntegerType(), False), + StructField("time", DoubleType(), False), + StructField("value", DoubleType(), True), +]) + +METADATA_SCHEMA = StructType([ + StructField("file_uri", StringType(), False), + StructField("channel_id", IntegerType(), False), + StructField("group_idx", IntegerType(), False), + StructField("channel_idx", IntegerType(), False), + StructField("channel_name", StringType(), False), + StructField("unit", StringType(), True), + StructField("header_datetime", TimestampType(), True), + StructField("md_comment", StringType(), True), +]) diff --git a/src/impulse_ds/mdf/udf_helpers.py b/src/impulse_ds/mdf/udf_helpers.py new file mode 100644 index 00000000..0df05d58 --- /dev/null +++ b/src/impulse_ds/mdf/udf_helpers.py @@ -0,0 +1,47 @@ +""" +Stable import surface for the executor-side MDF4 decode helpers. + +The implementation is split across three focused modules: + - mdf_blocks : low-level ``##DT``/``##DZ``/``##DL`` block I/O + - mdf_decode : raw bytes -> value / timestamp arrays (+ CC, invalidation) + - arrow_emit : build Arrow batches (per-group, stripe, master) + RLE + +This module re-exports their public names so existing imports +(``from .udf_helpers import convert_spec_to_arrow_batches``) +and the by-value mapInArrow UDFs keep working unchanged. +""" + +from .mdf_blocks import ( # noqa: F401 + decompress_dz, + resolve_dl_addr, + read_data_list_raw, + read_data_list_range, + read_raw_data, + dt_data_extent, + parse_subblocks, + _collect_dl_block_addrs, + _decompress_subblock_blob, + _read_block_chunks, +) +from .mdf_decode import ( # noqa: F401 + convert_values, + extract_column_strided, + apply_invalidation, + apply_cc_conversion, + extract_signal, + extract_timestamps, + FLOAT_LE, FLOAT_BE, UINT_LE, UINT_BE, SINT_LE, SINT_BE, + CC_IDENTITY, CC_LINEAR, CC_RATIONAL, CC_ALGEBRAIC, + CC_TAB_INTERP, CC_TAB_NOINTERP, CC_RANGE_TO_VALUE, + CN_FLAG_ALL_INVALID, CN_FLAG_INVALIDATION_PRESENT, +) +from .arrow_emit import ( # noqa: F401 + signals_arrow_schema, + master_arrow_schema, + convert_spec_to_arrow_batches, + convert_master_spec_to_arrow_batches, + convert_stripe_spec_to_arrow_batches, + _rle_run_starts, + _rle_compress_chunk, + _rle_flush, +) diff --git a/tests/impulse_ds/__init__.py b/tests/impulse_ds/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/impulse_ds/mdf/__init__.py b/tests/impulse_ds/mdf/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/impulse_ds/mdf/_mdf_samples.py b/tests/impulse_ds/mdf/_mdf_samples.py new file mode 100644 index 00000000..0651c2ac --- /dev/null +++ b/tests/impulse_ds/mdf/_mdf_samples.py @@ -0,0 +1,87 @@ +""" +Build small but meaningful MDF4 sample files for the unit tests using asammdf, +so the tests do not depend on any pre-built `.mf4` fixtures in the repo. + +Two files are produced (cached for the test session, cleaned up at exit): + - sample_a.mf4 : uncompressed (##DT data blocks) + - sample_b.mf4 : compressed (##DZ data blocks) + +Each contains two channel groups so the tests exercise grouping/coalescing, +masters, and multi-file behaviour: + group 0 (100 samples @ 10 Hz): + - "Speed" km/h float64 monotonic ramp (all-distinct -> RLE barely compresses) + - "Gear" (none) int32 piecewise-constant (compresses well under RLE) + group 1 (40 samples @ 5 Hz): + - "EngineTemp" degC float64 constant runs (compresses under RLE) + +A known header start time is set so the absolute_time path has something to add, +and one channel carries an XML comment so md_comment is populated. +""" +import atexit +import datetime +import os +import shutil +import tempfile + +import numpy as np + +try: + from asammdf import MDF, Signal + HAS_ASAMMDF = True +except Exception: # pragma: no cover - asammdf is a dev dependency + HAS_ASAMMDF = False + +# Naive UTC start time (asammdf stores it in the HD block). +START_TIME = datetime.datetime(2024, 3, 1, 12, 30, 15, 500000) + +_CACHE = None # (dir, [filenames]) once built + + +def _build_file(path: str, compression: int) -> None: + mdf = MDF(version="4.10") + + # Group 0: 100 samples at 10 Hz. + t0 = (np.arange(100) * 0.1).astype(np.float64) + speed = Signal( + samples=(t0 * 2.0), timestamps=t0, name="Speed", unit="km/h", + comment="vehicle speed", + ) + gear = np.zeros(100, dtype=np.int32) + gear[20:60] = 2 + gear[60:] = 4 + gear_sig = Signal(samples=gear, timestamps=t0, name="Gear", unit="") + mdf.append([speed, gear_sig], comment="powertrain") + + # Group 1: 40 samples at 5 Hz, with constant runs (good for RLE). + t1 = (np.arange(40) * 0.2).astype(np.float64) + temp = np.full(40, 20.0) + temp[10:25] = 21.5 + temp[25:] = 19.0 + temp_sig = Signal(samples=temp, timestamps=t1, name="EngineTemp", unit="degC") + mdf.append([temp_sig], comment="thermal") + + mdf.header.start_time = START_TIME + mdf.save(path, overwrite=True, compression=compression) + mdf.close() + + +def sample_mdf_dir(): + """Return (directory, sorted_filenames) of the generated sample MDF files. + + Builds them once per process (cached) into a temp dir that is removed at + interpreter exit. Returns ("", []) if asammdf is unavailable so callers can + skip the affected tests. + """ + global _CACHE + if _CACHE is not None: + return _CACHE + if not HAS_ASAMMDF: + _CACHE = ("", []) + return _CACHE + d = tempfile.mkdtemp(prefix="mdf_unit_samples_") + atexit.register(shutil.rmtree, d, ignore_errors=True) + _build_file(os.path.join(d, "sample_a.mf4"), compression=0) # ##DT + _build_file(os.path.join(d, "sample_b.mf4"), compression=2) # ##DZ + files = sorted(f for f in os.listdir(d) if f.lower().endswith(".mf4")) + _CACHE = (d, files) + return _CACHE diff --git a/tests/impulse_ds/mdf/test_datasources.py b/tests/impulse_ds/mdf/test_datasources.py new file mode 100644 index 00000000..26e0946c --- /dev/null +++ b/tests/impulse_ds/mdf/test_datasources.py @@ -0,0 +1,443 @@ +""" +Tests for the custom PySpark data sources (non-Spark components). + +Tests the file resolution, metadata scanning, and signal reading logic +without requiring a running Spark session. +""" + +import os +import pytest +import numpy as np + +from impulse_ds.mdf.mdf4_reader import MDF4Reader +from impulse_ds.mdf.datasources import ( + _resolve_file_list, + MdfMetadataReader, + MdfSignalsReader, +) + + +# Sample MDF files are generated on the fly with asammdf (see _mdf_samples.py) +# so the tests don't depend on any pre-built fixtures. EXAMPLE_FILES is empty when +# asammdf is unavailable, and the `if not EXAMPLE_FILES: skip` guards handle that. +from ._mdf_samples import sample_mdf_dir +EXAMPLE_DIR, EXAMPLE_FILES = sample_mdf_dir() + + +class TestResolveFileList: + def test_missing_path_raises(self): + with pytest.raises(ValueError, match="'path' is required"): + _resolve_file_list({}) + + def test_auto_discovery(self): + if not EXAMPLE_FILES: + pytest.skip("No example files") + paths = _resolve_file_list({"path": EXAMPLE_DIR}) + assert len(paths) >= 1 + assert all(p.endswith(".mf4") for p in paths) + + def test_explicit_file_list(self): + if not EXAMPLE_FILES: + pytest.skip("No example files") + first = EXAMPLE_FILES[0] + paths = _resolve_file_list({"path": EXAMPLE_DIR, "files": first}) + assert len(paths) == 1 + assert paths[0] == os.path.join(EXAMPLE_DIR, first) + + def test_comma_separated_files(self): + if len(EXAMPLE_FILES) < 2: + pytest.skip("Need at least 2 example files") + files_str = f"{EXAMPLE_FILES[0]}, {EXAMPLE_FILES[1]}" + paths = _resolve_file_list({"path": EXAMPLE_DIR, "files": files_str}) + assert len(paths) == 2 + + def test_absolute_file_uris(self): + if not EXAMPLE_FILES: + pytest.skip("No example files") + abs_path = os.path.join(EXAMPLE_DIR, EXAMPLE_FILES[0]) + paths = _resolve_file_list({"path": "/unused/base", "files": abs_path}) + assert paths == [abs_path] + + def test_mixed_absolute_and_relative_files(self): + if len(EXAMPLE_FILES) < 2: + pytest.skip("Need at least 2 example files") + abs_path = os.path.join(EXAMPLE_DIR, EXAMPLE_FILES[0]) + rel_path = EXAMPLE_FILES[1] + files_str = f"{abs_path}, {rel_path}" + paths = _resolve_file_list({"path": EXAMPLE_DIR, "files": files_str}) + assert paths == [abs_path, os.path.join(EXAMPLE_DIR, rel_path)] + + def test_auto_discovery_recursive(self, tmp_path): + if not EXAMPLE_FILES: + pytest.skip("No example files") + import shutil + + nested = tmp_path / "batch_a" / "run_1" + nested.mkdir(parents=True) + for name in EXAMPLE_FILES: + shutil.copy(os.path.join(EXAMPLE_DIR, name), nested / name) + + paths = _resolve_file_list({"path": str(tmp_path)}) + assert len(paths) == len(EXAMPLE_FILES) + assert all(p.endswith(".mf4") for p in paths) + assert all("batch_a" in p and "run_1" in p for p in paths) + + def test_empty_dir_raises(self, tmp_path): + with pytest.raises(ValueError, match="No MDF4 files found"): + _resolve_file_list({"path": str(tmp_path)}) + + +class TestScanChannelsOrganized: + def test_returns_organized_structure(self): + if not EXAMPLE_FILES: + pytest.skip("No example files") + file_path = os.path.join(EXAMPLE_DIR, EXAMPLE_FILES[0]) + reader = MDF4Reader(file_path) + organized = reader.scan_channels_organized() + assert "master_channels" in organized + assert "signal_channels" in organized + assert "channel_id_map" in organized + assert len(organized["signal_channels"]) > 0 + assert len(organized["master_channels"]) > 0 + + def test_channel_ids_sequential(self): + if not EXAMPLE_FILES: + pytest.skip("No example files") + file_path = os.path.join(EXAMPLE_DIR, EXAMPLE_FILES[0]) + reader = MDF4Reader(file_path) + organized = reader.scan_channels_organized() + ids = sorted(organized["channel_id_map"].values()) + assert ids == list(range(len(organized["signal_channels"]))) + + +class TestMetadataReader: + def test_read_partition(self): + if not EXAMPLE_FILES: + pytest.skip("No example files") + reader = MdfMetadataReader({"path": EXAMPLE_DIR, "files": EXAMPLE_FILES[0]}) + partitions = reader.partitions() + assert len(partitions) == 1 + rows = list(reader.read(partitions[0])) + assert len(rows) > 0 + from impulse_ds.mdf.schemas import METADATA_SCHEMA + assert len(rows[0]) == len(METADATA_SCHEMA.fields) # md_comment included + (file_uri, channel_id, group_idx, channel_idx, channel_name, unit, + header_datetime, md_comment) = rows[0] + assert isinstance(file_uri, str) and file_uri.endswith(".mf4") + assert channel_id == 0 + assert isinstance(channel_name, str) + assert len(channel_name) > 0 + assert md_comment is None or isinstance(md_comment, str) + + +class TestSignalsReader: + def test_partitions_created(self): + if not EXAMPLE_FILES: + pytest.skip("No example files") + reader = MdfSignalsReader({"path": EXAMPLE_DIR, "files": EXAMPLE_FILES[0]}) + partitions = reader.partitions() + assert len(partitions) >= 1 + # partitions() now returns InputPartition objects carrying the spec JSON + assert "file_path" in partitions[0].value + + def test_read_produces_arrow_batches(self): + if not EXAMPLE_FILES: + pytest.skip("No example files") + import pyarrow as pa + reader = MdfSignalsReader({"path": EXAMPLE_DIR, "files": EXAMPLE_FILES[0]}) + partitions = reader.partitions() + batches = [] + for p in partitions[:2]: + batches.extend(reader.read(p)) + assert len(batches) > 0 + b = batches[0] + assert isinstance(b, pa.RecordBatch) + assert b.schema.names == ["file_uri", "channel_id", "time", "value"] + row0 = {name: b.column(i)[0].as_py() for i, name in enumerate(b.schema.names)} + assert isinstance(row0["file_uri"], str) + assert isinstance(row0["channel_id"], int) + assert isinstance(row0["time"], float) + assert row0["value"] is None or isinstance(row0["value"], float) + + def test_timestamps_nonnegative(self): + if not EXAMPLE_FILES: + pytest.skip("No example files") + reader = MdfSignalsReader({"path": EXAMPLE_DIR, "files": EXAMPLE_FILES[0]}) + partitions = reader.partitions() + times = [] + for b in reader.read(partitions[0]): + times.extend(b.column("time").to_pylist()) + assert all(t >= 0 for t in times), "Negative timestamps found" + + +class TestRunLengthEncoding: + def _read(self, opts): + from collections import defaultdict + reader = MdfSignalsReader(opts) + cols = defaultdict(list) + names = None + for p in reader.partitions(): + for b in reader.read(p): + names = b.schema.names + for n in names: + cols[n].append(b.column(n).to_numpy(zero_copy_only=False)) + return names, {n: (np.concatenate(v) if v else np.array([])) for n, v in cols.items()} + + def test_rle_schema(self): + if not EXAMPLE_FILES: + pytest.skip("No example files") + from impulse_ds.mdf.datasources import MdfSignalsDataSource + opts = {"path": EXAMPLE_DIR, "files": EXAMPLE_FILES[0], "run_length_encoding": "true"} + sch = MdfSignalsDataSource(dict(opts)).schema() + assert [f.name for f in sch.fields] == [ + "file_uri", "channel_id", "tstart", "tend", "value"] + names, _ = self._read(opts) + assert names == ["file_uri", "channel_id", "tstart", "tend", "value"] + + def test_rle_final_sample_is_point(self): + """Each channel must end with a zero-width point row (tstart == tend) at + its last timestamp, so the final sample is recoverable.""" + if not EXAMPLE_FILES: + pytest.skip("No example files") + from collections import defaultdict + base = {"path": EXAMPLE_DIR, "files": EXAMPLE_FILES[0], "target_partition_mb": "16"} + _, plain = self._read(base) + _, rle = self._read({**base, "run_length_encoding": "true"}) + + def per_ch(d, cols): + out = defaultdict(lambda: defaultdict(list)) + for k in np.unique(d["channel_id"]): + m = d["channel_id"] == k + for c in cols: + out[int(k)][c] = d[c][m] + return out + + pch = per_ch(plain, ["time"]) + rch = per_ch(rle, ["tstart", "tend"]) + assert pch + for ch, p in pch.items(): + last_t = float(np.max(p["time"])) + ts, te = rch[ch]["tstart"], rch[ch]["tend"] + points = ts[np.isclose(ts, te)] + # a point row exists exactly at the channel's last timestamp + assert np.any(np.isclose(points, last_t)), f"channel {ch}: no final point at {last_t}" + + def test_rle_reconstructs_original_and_compresses(self): + if not EXAMPLE_FILES: + pytest.skip("No example files") + from collections import defaultdict + from impulse_ds.mdf.udf_helpers import _rle_run_starts + + base = {"path": EXAMPLE_DIR, "files": EXAMPLE_FILES[0], "target_partition_mb": "16"} + _, plain = self._read(base) + _, rle = self._read({**base, "run_length_encoding": "true"}) + + def per_channel(d, cols): + out = defaultdict(lambda: defaultdict(list)) + for k in np.unique(d["channel_id"]): + m = d["channel_id"] == k + for c in cols: + out[int(k)][c] = d[c][m] + return out + + pch = per_channel(plain, ["time", "value"]) + rch = per_channel(rle, ["tstart", "tend", "value"]) + + def whole_rle(t, v): + o = np.argsort(t, kind="stable"); t, v = t[o], v[o] + s = _rle_run_starts(v); m = len(s) + return [(t[s[k]], t[s[k + 1]] if k < m - 1 else t[-1], v[s[k]]) for k in range(m)] + + def merge_adjacent(rows): + rows = sorted(rows, key=lambda r: r[0]); out = [] + for t0, t1, val in rows: + same = out and out[-1][1] == t0 and ( + out[-1][2] == val or (out[-1][2] != out[-1][2] and val != val)) + if same: + out[-1] = (out[-1][0], t1, out[-1][2]) + else: + out.append((t0, t1, val)) + return out + + total_plain = total_runs = 0 + for k, p in pch.items(): + ref = whole_rle(p["time"], p["value"]) + got = merge_adjacent(list(zip(rch[k]["tstart"], rch[k]["tend"], rch[k]["value"]))) + total_plain += len(p["time"]); total_runs += len(got) + assert len(ref) == len(got), f"channel {k}: {len(ref)} runs vs {len(got)}" + for (a0, a1, av), (b0, b1, bv) in zip(ref, got): + assert abs(a0 - b0) < 1e-6 and abs(a1 - b1) < 1e-6 + assert av == bv or (av != av and bv != bv) # NaN == NaN + # This example compresses substantially; guard against a no-op RLE. + assert total_runs < total_plain + + +class TestMastersDataSource: + def _read(self, reader, cols): + from collections import defaultdict + out = defaultdict(lambda: defaultdict(list)) + names = None + for p in reader.partitions(): + for b in reader.read(p): + names = b.schema.names + kc = b.column(cols[0]).to_numpy() + for k in np.unique(kc): + m = kc == k + for c in cols[1:]: + out[int(k)][c].append(b.column(c).to_numpy()[m]) + agg = {k: {c: np.concatenate(v) for c, v in d.items()} for k, d in out.items()} + return names, agg + + def test_masters_schema_and_grid(self): + if not EXAMPLE_FILES: + pytest.skip("No example files") + from impulse_ds.mdf.datasources import ( + MdfMastersDataSource, MdfMastersReader, MdfSignalsReader) + from impulse_ds.mdf.mdf4_reader import MDF4Reader + + opts = {"path": EXAMPLE_DIR, "files": EXAMPLE_FILES[0], "target_partition_mb": "16"} + sch = MdfMastersDataSource(dict(opts)).schema() + assert [f.name for f in sch.fields] == ["file_uri", "group_idx", "timestamp"] + + names, masters = self._read(MdfMastersReader(opts), ["group_idx", "timestamp"]) + assert names == ["file_uri", "group_idx", "timestamp"] + masters = {g: np.sort(d["timestamp"]) for g, d in masters.items()} + assert masters and all(np.all(np.diff(ts) >= 0) for ts in masters.values()) + + # Each channel's signal-time grid equals its group's master timestamps. + org = MDF4Reader(os.path.join(EXAMPLE_DIR, EXAMPLE_FILES[0])).scan_channels_organized() + ch2grp = {cid: g for (g, c), cid in org["channel_id_map"].items()} + _, sig = self._read(MdfSignalsReader(opts), ["channel_id", "time"]) + for ch, d in sig.items(): + ts = np.sort(d["time"]) + assert np.allclose(ts, masters[ch2grp[ch]]) + + def test_reverse_rle_recovers_originals(self): + if not EXAMPLE_FILES: + pytest.skip("No example files") + from impulse_ds.mdf.datasources import MdfMastersReader, MdfSignalsReader + from impulse_ds.mdf.mdf4_reader import MDF4Reader + + opts = {"path": EXAMPLE_DIR, "files": EXAMPLE_FILES[0], "target_partition_mb": "16"} + _, orig = self._read(MdfSignalsReader(opts), ["channel_id", "time", "value"]) + _, rle = self._read(MdfSignalsReader({**opts, "run_length_encoding": "true"}), + ["channel_id", "tstart", "tend", "value"]) + _, masters = self._read(MdfMastersReader(opts), ["group_idx", "timestamp"]) + masters = {g: np.sort(d["timestamp"]) for g, d in masters.items()} + org = MDF4Reader(os.path.join(EXAMPLE_DIR, EXAMPLE_FILES[0])).scan_channels_organized() + ch2grp = {cid: g for (g, c), cid in org["channel_id_map"].items()} + + for ch, d in orig.items(): + o = np.argsort(d["time"], kind="stable") + ot, ov = d["time"][o], d["value"][o] + r = rle[ch] + ro = np.argsort(r["tstart"], kind="stable") + tstart, value = r["tstart"][ro], r["value"][ro] + gts = masters[ch2grp[ch]] + idx = np.clip(np.searchsorted(tstart, gts, side="right") - 1, 0, len(tstart) - 1) + rt, rv = gts, value[idx] + assert len(rt) == len(ot) and np.allclose(rt, ot) + assert ((rv == ov) | (np.isnan(rv) & np.isnan(ov))).all() + + +class TestAbsoluteTime: + def _read(self, opts, cols): + from collections import defaultdict + from impulse_ds.mdf.datasources import MdfSignalsReader + rd = MdfSignalsReader(opts) + out = defaultdict(lambda: defaultdict(list)) + for p in rd.partitions(): + for b in rd.read(p): + c = b.column("channel_id").to_numpy() + for k in np.unique(c): + m = c == k + for col in cols: + out[int(k)][col].append(b.column(col).to_numpy()[m]) + return {k: {col: np.concatenate(v) for col, v in d.items()} for k, d in out.items()} + + def test_absolute_time_adds_start_and_forces_float64(self): + if not EXAMPLE_FILES: + pytest.skip("No example files") + from impulse_ds.mdf.datasources import MdfSignalsDataSource + + f = EXAMPLE_FILES[0] + start = MDF4Reader(os.path.join(EXAMPLE_DIR, f)).read_header_start_epoch_seconds() + if start is None: + pytest.skip("file has no HD start time") + + # Schema forces float64 time even when float32 requested. + sch = MdfSignalsDataSource({"path": EXAMPLE_DIR, "files": f, + "absolute_time": "true", "time_dtype": "float32"}).schema() + assert sch["time"].dataType.simpleString() == "double" + + base = {"path": EXAMPLE_DIR, "files": f, "target_partition_mb": "16"} + rel = self._read(base, ["time", "value"]) + ab = self._read({**base, "absolute_time": "true"}, ["time", "value"]) + for ch in rel: + rt = np.sort(rel[ch]["time"]); at = np.sort(ab[ch]["time"]) + assert np.allclose(at, rt + start, atol=1e-3) # offset applied + assert np.array_equal(np.sort(rel[ch]["value"]), # values unchanged + np.sort(ab[ch]["value"])) + + def test_absolute_time_rle_and_masters_align(self): + if not EXAMPLE_FILES: + pytest.skip("No example files") + from collections import defaultdict + from impulse_ds.mdf.datasources import MdfMastersReader + + f = EXAMPLE_FILES[0] + start = MDF4Reader(os.path.join(EXAMPLE_DIR, f)).read_header_start_epoch_seconds() + if start is None: + pytest.skip("file has no HD start time") + + def masters(opts): + rd = MdfMastersReader(opts) + out = defaultdict(list) + for p in rd.partitions(): + for b in rd.read(p): + g = b.column("group_idx").to_numpy(); ts = b.column("timestamp").to_numpy() + for k in np.unique(g): + out[int(k)].append(ts[g == k]) + return {k: np.sort(np.concatenate(v)) for k, v in out.items()} + + base = {"path": EXAMPLE_DIR, "files": f, "target_partition_mb": "16"} + mrel = masters(base) + mabs = masters({**base, "absolute_time": "true"}) + for g in mrel: + assert np.allclose(mabs[g], mrel[g] + start, atol=1e-3) + + +class TestSchemaMatchesEmittedTypes: + """schema() MUST match the Arrow types read() emits for every option combo; + a mismatch makes Spark's writer call getDouble on a float vector (or similar) + and fail. Regression for the absolute_time + value_dtype=float32 case where + schema() over-forced `value` to double while the decoder emitted float32.""" + + def test_all_option_combos_consistent(self): + if not EXAMPLE_FILES: + pytest.skip("No example files") + from itertools import product + from impulse_ds.mdf.datasources import MdfSignalsDataSource + spark2arrow = {"double": "double", "float": "float", + "bigint": "int64", "int": "int32", "string": "string"} + base = {"path": EXAMPLE_DIR, "files": EXAMPLE_FILES[0], + "target_partition_mb": "8", "stripe_target_mb": "2"} + for abst, vdt, tdt, rle, part in product( + ["false", "true"], ["float64", "float32"], ["float64", "float32"], + ["false", "true"], ["group", "stripe"]): + opts = {**base, "absolute_time": abst, "value_dtype": vdt, + "time_dtype": tdt, "run_length_encoding": rle, "partitioning": part} + sch = MdfSignalsDataSource(dict(opts)).schema() + declared = {f.name: spark2arrow[f.dataType.simpleString()] for f in sch.fields} + reader = MdfSignalsReader(opts) + emitted = None + for p in reader.partitions(): + for b in reader.read(p): + emitted = {f.name: str(f.type) for f in b.schema} + break + if emitted: + break + if emitted is not None: + assert emitted == declared, ( + f"schema/emit mismatch abs={abst} val={vdt} time={tdt} " + f"rle={rle} part={part}: {declared} vs {emitted}") diff --git a/tests/impulse_ds/mdf/test_mdf4_reader.py b/tests/impulse_ds/mdf/test_mdf4_reader.py new file mode 100644 index 00000000..f0863ebb --- /dev/null +++ b/tests/impulse_ds/mdf/test_mdf4_reader.py @@ -0,0 +1,394 @@ +""" +Tests for the MDF4 binary reader. + +Validates metadata scanning and data extraction against MDF4 files generated on +the fly with asammdf (_mdf_samples.py) — no pre-built fixtures required. +This also cross-validates our reader against asammdf's own output. +""" + +import os +import pytest +import numpy as np + +from impulse_ds.mdf.mdf4_reader import ( + MDF4Reader, CN_TYPE_MASTER, CN_TYPE_VIRTUAL_MASTER +) +from ._mdf_samples import sample_mdf_dir + + +_DIR, _FILES = sample_mdf_dir() +EXAMPLE_DIR = _DIR +EXAMPLE_FILES = [os.path.join(_DIR, f) for f in _FILES] # full paths + + +@pytest.fixture( + params=EXAMPLE_FILES if EXAMPLE_FILES else [], + ids=[os.path.basename(p) for p in EXAMPLE_FILES], +) +def mdf_file(request): + return request.param + + +class TestMDF4Reader: + def test_scan_metadata_returns_channels(self, mdf_file): + reader = MDF4Reader(mdf_file) + channels = reader.scan_metadata() + assert len(channels) > 0, f"No channels found in {mdf_file}" + + def test_channels_have_valid_fields(self, mdf_file): + reader = MDF4Reader(mdf_file) + channels = reader.scan_metadata() + for ch in channels: + assert ch.group_idx >= 0 + assert ch.channel_idx >= 0 + assert ch.sample_count >= 0 + assert ch.bit_count >= 0 # virtual masters can have bit_count=0 + assert ch.record_size > 0 + assert ch.data_block_addr > 0 + + def test_has_master_channels(self, mdf_file): + reader = MDF4Reader(mdf_file) + channels = reader.scan_metadata() + masters = [ + ch for ch in channels + if ch.channel_type in (CN_TYPE_MASTER, CN_TYPE_VIRTUAL_MASTER) + ] + assert len(masters) > 0, "No master (time) channels found" + + def test_read_channel_data(self, mdf_file): + reader = MDF4Reader(mdf_file) + channels = reader.scan_metadata() + + # Find a signal channel with data + signal_ch = None + for ch in channels: + if ch.channel_type not in (CN_TYPE_MASTER, CN_TYPE_VIRTUAL_MASTER): + if ch.sample_count > 0: + signal_ch = ch + break + + if signal_ch is None: + pytest.skip("No signal channels with data") + + values = MDF4Reader.read_channel_data( + mdf_file, + signal_ch.data_block_addr, + signal_ch.record_size, + signal_ch.byte_offset, + signal_ch.bit_offset, + signal_ch.bit_count, + signal_ch.data_type, + signal_ch.channel_type, + signal_ch.sample_count, + ) + + assert len(values) > 0 + assert values.dtype == np.float64 + assert not np.all(np.isnan(values)) + + def test_read_channel_pair(self, mdf_file): + reader = MDF4Reader(mdf_file) + channels = reader.scan_metadata() + + # Find master and signal in same group + masters = {} + for ch in channels: + if ch.channel_type in (CN_TYPE_MASTER, CN_TYPE_VIRTUAL_MASTER): + masters[ch.group_idx] = ch + + signal_ch = None + for ch in channels: + if ch.channel_type not in (CN_TYPE_MASTER, CN_TYPE_VIRTUAL_MASTER): + if ch.sample_count > 0 and ch.group_idx in masters: + signal_ch = ch + break + + if signal_ch is None: + pytest.skip("No suitable channel pair found") + + master = masters[signal_ch.group_idx] + master_info = { + "byte_offset": master.byte_offset, + "bit_offset": master.bit_offset, + "bit_count": master.bit_count, + "data_type": master.data_type, + "channel_type": master.channel_type, + "cc_type": master.cc_type, + "cc_params": list(master.cc_params) if master.cc_params else [], + } + signal_info = { + "data_block_addr": signal_ch.data_block_addr, + "record_size": signal_ch.record_size, + "byte_offset": signal_ch.byte_offset, + "bit_offset": signal_ch.bit_offset, + "bit_count": signal_ch.bit_count, + "data_type": signal_ch.data_type, + "channel_type": signal_ch.channel_type, + "cc_type": signal_ch.cc_type, + "cc_params": list(signal_ch.cc_params) if signal_ch.cc_params else [], + } + + timestamps, values = MDF4Reader.read_channel_pair( + mdf_file, master_info, signal_info, signal_ch.sample_count + ) + + assert len(timestamps) == len(values) + assert len(timestamps) > 0 + # Timestamps should be monotonically non-decreasing + assert np.all(np.diff(timestamps) >= 0), "Timestamps not monotonic" + + +class TestCrossValidation: + """Cross-validate our reader against asammdf (when available).""" + + @pytest.fixture(autouse=True) + def _check_asammdf(self): + try: + import asammdf + self.asammdf = asammdf + except ImportError: + pytest.skip("asammdf not installed") + + def test_values_match_asammdf(self, mdf_file): + """Verify our extracted values match asammdf's output.""" + import asammdf + + # Read with asammdf + mdf = asammdf.MDF(mdf_file) + + # Read with our reader + reader = MDF4Reader(mdf_file) + channels = reader.scan_metadata() + + masters = {} + for ch in channels: + if ch.channel_type in (CN_TYPE_MASTER, CN_TYPE_VIRTUAL_MASTER): + masters[ch.group_idx] = ch + + # Compare first 5 signal channels + compared = 0 + for ch in channels: + if ch.channel_type in (CN_TYPE_MASTER, CN_TYPE_VIRTUAL_MASTER): + continue + if ch.sample_count == 0: + continue + if compared >= 5: + break + + # Our reader + master = masters.get(ch.group_idx) + if master: + master_info = { + "byte_offset": master.byte_offset, + "bit_offset": master.bit_offset, + "bit_count": master.bit_count, + "data_type": master.data_type, + "channel_type": master.channel_type, + "cc_type": master.cc_type, + "cc_params": list(master.cc_params) if master.cc_params else [], + } + signal_info = { + "data_block_addr": ch.data_block_addr, + "record_size": ch.record_size, + "byte_offset": ch.byte_offset, + "bit_offset": ch.bit_offset, + "bit_count": ch.bit_count, + "data_type": ch.data_type, + "channel_type": ch.channel_type, + "cc_type": ch.cc_type, + "cc_params": list(ch.cc_params) if ch.cc_params else [], + } + try: + our_times, our_values = MDF4Reader.read_channel_pair( + mdf_file, master_info, signal_info, ch.sample_count + ) + except Exception: + continue + else: + continue + + # asammdf + try: + sig = mdf.get( + ch.channel_name, group=ch.group_idx, index=ch.channel_idx + ) + except Exception: + continue + + ref_values = sig.samples.astype(np.float64) + + # Compare (allow small floating point differences) + n = min(len(our_values), len(ref_values)) + if n == 0: + continue + + np.testing.assert_allclose( + our_values[:n], ref_values[:n], + rtol=1e-5, atol=1e-10, + err_msg=f"Mismatch for channel {ch.channel_name} " + f"(group={ch.group_idx}, idx={ch.channel_idx})" + ) + compared += 1 + + assert compared > 0, "No channels could be compared" + + +class TestCCConversion: + """Test CC (Channel Conversion) block support.""" + + def test_cc_fields_present_on_channel_info(self, mdf_file): + reader = MDF4Reader(mdf_file) + channels = reader.scan_metadata() + for ch in channels: + assert hasattr(ch, "cc_type") + assert hasattr(ch, "cc_params") + assert ch.cc_type in (-1, 0, 1, 2, 3, 4, 5, 6) + assert isinstance(ch.cc_params, tuple) + + def test_apply_cc_linear(self): + from impulse_ds.mdf.udf_helpers import apply_cc_conversion + raw = np.array([0.0, 1.0, 2.0, 100.0]) + # linear: phys = 2.0 * raw + 10.0, params = (b=10.0, a=2.0) + result = apply_cc_conversion(raw, 1, (10.0, 2.0)) + np.testing.assert_allclose(result, [10.0, 12.0, 14.0, 210.0]) + + def test_apply_cc_rational(self): + from impulse_ds.mdf.udf_helpers import apply_cc_conversion + raw = np.array([1.0, 2.0, 10.0]) + # rational: (0*X^2 + 2*X + 1) / (0*X^2 + 0*X + 1) = 2*X + 1 + result = apply_cc_conversion(raw, 2, (0.0, 2.0, 1.0, 0.0, 0.0, 1.0)) + np.testing.assert_allclose(result, [3.0, 5.0, 21.0]) + + def test_apply_cc_identity(self): + from impulse_ds.mdf.udf_helpers import apply_cc_conversion + raw = np.array([42.0, -1.5, 0.0]) + result = apply_cc_conversion(raw, 0, ()) + np.testing.assert_array_equal(result, raw) + + def test_apply_cc_tabular_interp(self): + from impulse_ds.mdf.udf_helpers import apply_cc_conversion + # Interleaved per spec: (key_0, val_0, key_1, val_1, key_2, val_2) + raw = np.array([0.0, 50.0, 100.0, 150.0, 200.0]) + result = apply_cc_conversion(raw, 4, (0.0, 0.0, 100.0, 50.0, 200.0, 100.0)) + np.testing.assert_allclose(result, [0.0, 25.0, 50.0, 75.0, 100.0]) + + def test_apply_cc_no_conversion(self): + from impulse_ds.mdf.udf_helpers import apply_cc_conversion + raw = np.array([1.0, 2.0, 3.0]) + result = apply_cc_conversion(raw, -1, ()) + np.testing.assert_array_equal(result, raw) + result2 = apply_cc_conversion(raw, -1, None) + np.testing.assert_array_equal(result2, raw) + + def test_virtual_master_cc_applied(self): + """Verify CC conversion is applied to virtual master timestamps.""" + from impulse_ds.mdf.udf_helpers import extract_timestamps + # Simulate raw_data for 5 samples with 8-byte records (any content) + raw_data = b'\x00' * 40 + record_size = 8 + master_info = { + "channel_type": 3, # virtual master + "byte_offset": 0, + "bit_offset": 0, + "bit_count": 0, + "data_type": 0, + "cc_type": 1, # linear + "cc_params": [0.0, 10.0], # physical = 10 * index + 0 + } + timestamps = extract_timestamps(raw_data, record_size, master_info) + np.testing.assert_allclose(timestamps, [0, 10, 20, 30, 40]) + + def test_virtual_master_no_cc(self): + """Virtual master without CC returns raw indices.""" + from impulse_ds.mdf.udf_helpers import extract_timestamps + raw_data = b'\x00' * 24 + record_size = 8 + master_info = { + "channel_type": 3, + "byte_offset": 0, + "bit_offset": 0, + "bit_count": 0, + "data_type": 0, + "cc_type": -1, + "cc_params": [], + } + timestamps = extract_timestamps(raw_data, record_size, master_info) + np.testing.assert_array_equal(timestamps, [0, 1, 2]) + + +class TestPlanPartitionsCoalescing: + """plan_partitions must coalesce many small groups into shared tasks while + bounding both the output rows and the number of groups (block reads) per + spec, and still split big groups by record range.""" + + @staticmethod + def _ch(gi, ci, samples, addr, ctype=0): + from impulse_ds.mdf.mdf4_reader import ChannelInfo + return ChannelInfo( + group_idx=gi, channel_idx=ci, channel_name=f"s{gi}_{ci}", unit="", + sample_count=samples, data_type=4, bit_offset=0, byte_offset=0, + bit_count=64, channel_type=ctype, cn_block_addr=0, cg_block_addr=0, + dg_block_addr=0, data_block_addr=addr, record_size=16, cn_flags=0, + invalidation_bit_pos=0, invalidation_bytes=0, data_bytes=8, + cc_type=-1, cc_params=[], rec_id_size=0, record_id=0) + + def _layout(self): + signal, masters, cidmap, gi = [], {}, {}, 0 + for _ in range(2000): # many tiny groups + addr = 1000 + gi + signal.append(self._ch(gi, 1, 100, addr)) + masters[gi] = self._ch(gi, 0, 100, addr, ctype=2) + cidmap[(gi, 1)] = gi; gi += 1 + for _ in range(2): # big groups -> record-range split + addr = 1000 + gi + signal.append(self._ch(gi, 1, 50_000_000, addr)) + masters[gi] = self._ch(gi, 0, 50_000_000, addr, ctype=2) + cidmap[(gi, 1)] = gi; gi += 1 + return masters, signal, cidmap + + def test_coalesces_and_respects_bounds(self): + from impulse_ds.mdf.bin_packer import plan_partitions + masters, signal, cidmap = self._layout() + cap = 64 + target_mb = 256 + target_rows = target_mb * 1024 * 1024 // 16 + specs = plan_partitions( + "f.mf4", masters, signal, cidmap, + target_partition_mb=target_mb, max_groups_per_partition=cap) + + # Far fewer specs than groups (2000 tiny would-be tasks collapse). + assert len(specs) < 2000 / 10 + whole = [s for s in specs if "row_start" not in s] + for s in whole: + blocks = {c["data_block_addr"] for c in s["channels"]} + assert len(blocks) <= cap # group-count bound + rows = sum(c["sample_count"] for c in s["channels"]) + assert rows <= target_rows # output-row bound + + # Big groups still split by record range. + assert any("row_start" in s for s in specs) + + def test_full_channel_coverage_exactly_once(self): + from impulse_ds.mdf.bin_packer import plan_partitions + masters, signal, cidmap = self._layout() + specs = plan_partitions( + "f.mf4", masters, signal, cidmap, + target_partition_mb=256, max_groups_per_partition=64) + # Every channel appears (whole-group once; ranged groups contiguously). + whole_seen = set() + ranges = {} + for s in specs: + for c in s["channels"]: + key = (c["group_idx"], c["channel_idx"]) + if "row_start" in s: + ranges.setdefault(key, []).append((s["row_start"], s["row_end"])) + else: + assert key not in whole_seen, "channel double-counted" + whole_seen.add(key) + for key, ivs in ranges.items(): + ivs.sort() + assert ivs[0][0] == 0 + for a, b in zip(ivs, ivs[1:]): + assert a[1] == b[0] # contiguous, no gaps/overlap + all_keys = whole_seen | set(ranges) + assert len(all_keys) == len(signal) diff --git a/tests/impulse_ds/mdf/test_telemetry.py b/tests/impulse_ds/mdf/test_telemetry.py new file mode 100644 index 00000000..94028b1d --- /dev/null +++ b/tests/impulse_ds/mdf/test_telemetry.py @@ -0,0 +1,85 @@ +"""Tests for MDF data source registration and read telemetry.""" + +from unittest.mock import MagicMock, create_autospec, patch + +import pytest +from databricks.sdk import WorkspaceClient + +from impulse_query_engine import __version__ +from impulse_ds.mdf import datasources +from impulse_ds.mdf.datasources import ( + MdfMetadataDataSource, + MdfMetadataReader, + MdfMastersDataSource, + MdfMastersReader, + MdfSignalsDataSource, + MdfSignalsReader, + register_mdf_datasources, +) +from ._mdf_samples import sample_mdf_dir + +EXAMPLE_DIR, EXAMPLE_FILES = sample_mdf_dir() + + +@pytest.fixture(autouse=True) +def reset_ws(): + """Isolate module-level workspace client between tests.""" + prev = datasources._ws + datasources._ws = None + yield + datasources._ws = prev + + +class TestRegisterMdfDatasources: + @patch("impulse_query_engine.telemetry.verify_workspace_client") + def test_registers_three_sources_and_verifies_workspace(self, mock_verify): + ws = create_autospec(WorkspaceClient) + mock_verify.return_value = ws + spark = MagicMock() + + result = register_mdf_datasources(spark, ws) + + mock_verify.assert_called_once_with(ws, "databricks-impulse", __version__) + assert result is ws + assert datasources._ws is ws + spark.dataSource.register.assert_any_call(MdfSignalsDataSource) + spark.dataSource.register.assert_any_call(MdfMetadataDataSource) + spark.dataSource.register.assert_any_call(MdfMastersDataSource) + assert spark.dataSource.register.call_count == 3 + + +class TestPartitionsTelemetry: + @pytest.fixture + def reader_opts(self): + if not EXAMPLE_FILES: + pytest.skip("No example files") + return {"path": EXAMPLE_DIR, "files": EXAMPLE_FILES[0]} + + @patch("impulse_query_engine.telemetry.log_telemetry") + def test_signals_partitions_emits_telemetry(self, mock_log, reader_opts): + ws = create_autospec(WorkspaceClient) + datasources._ws = ws + MdfSignalsReader(reader_opts).partitions() + mock_log.assert_called_once_with(ws, "mdf", "mdf_signals") + + @patch("impulse_query_engine.telemetry.log_telemetry") + def test_metadata_partitions_emits_telemetry(self, mock_log, reader_opts): + ws = create_autospec(WorkspaceClient) + datasources._ws = ws + MdfMetadataReader(reader_opts).partitions() + mock_log.assert_called_once_with(ws, "mdf", "mdf_metadata") + + @patch("impulse_query_engine.telemetry.log_telemetry") + def test_masters_partitions_emits_telemetry(self, mock_log, reader_opts): + ws = create_autospec(WorkspaceClient) + datasources._ws = ws + MdfMastersReader(reader_opts).partitions() + mock_log.assert_called_once_with(ws, "mdf", "mdf_masters") + + @patch("impulse_query_engine.telemetry.log_telemetry") + def test_partitions_skips_telemetry_when_ws_unset(self, mock_log, reader_opts): + assert datasources._ws is None + MdfSignalsReader(reader_opts).partitions() + MdfMetadataReader(reader_opts).partitions() + MdfMastersReader(reader_opts).partitions() + mock_log.assert_not_called() diff --git a/uv.lock b/uv.lock index 794b4d8f..82c530e2 100644 --- a/uv.lock +++ b/uv.lock @@ -5,16 +5,47 @@ requires-python = "==3.12.*" [[package]] name = "annotated-types" version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", upload-time = "2024-05-20T21:33:25.928Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "asammdf" +version = "8.0.1" +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +dependencies = [ + { name = "canmatrix", extra = ["arxml"] }, + { name = "isal", marker = "platform_machine == 'AMD64' or platform_machine == 'x86_64'" }, + { name = "lxml" }, + { name = "lz4" }, + { name = "numexpr" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "python-dateutil" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/6a/5c/5173d96d95dbb75f2700baf2e30ab71d91326b9187c993b44ad2730a8733/asammdf-8.0.1.tar.gz", hash = "sha256:aa40bb4103aefbea75777ff4888c8ee20089e62f0c141f7e07c01de1beb93247", upload-time = "2024-10-01T13:28:29.812Z" } +wheels = [ + { url = "https://pypi-proxy.cloud.databricks.com/packages/52/38/db219cbbe76dbcb1d32dba768fc4fca192c098b6fca1862805a06e0c1fc0/asammdf-8.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e70cfc85a16e96569d45e304796d4401b5e3796d7f846d6f66da44b6baf77aec", upload-time = "2024-10-01T13:27:59.663Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/44/8c/5b2385bc3b0511a2a96ed8e1643df64dcf190d60cfb95849625a9ab7c8b4/asammdf-8.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a07ebbbf1f4f6f724a2f992eaff809a4f6000e7e9a1796657e9857e589529e57", upload-time = "2024-10-01T13:28:06.293Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/f4/a9/6ad9208ed9f5ed077dddca45c12b192e3b1c9641e959742cdede549c0e49/asammdf-8.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:d9685e07503671816680b485c7032716acac72fd31e247a6acb059a775cd2100", upload-time = "2024-10-01T13:28:13.363Z" }, +] + +[[package]] +name = "attrs" +version = "26.1.0" +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", upload-time = "2026-03-19T14:22:25.026Z" } +wheels = [ + { url = "https://pypi-proxy.cloud.databricks.com/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", upload-time = "2026-03-19T14:22:23.645Z" }, ] [[package]] name = "black" version = "26.3.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "click" }, { name = "mypy-extensions" }, @@ -23,201 +54,219 @@ dependencies = [ { name = "platformdirs" }, { name = "pytokens" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e1/c5/61175d618685d42b005847464b8fb4743a67b1b8fdb75e50e5a96c31a27a/black-26.3.1.tar.gz", hash = "sha256:2c50f5063a9641c7eed7795014ba37b0f5fa227f3d408b968936e24bc0566b07", size = 666155, upload-time = "2026-03-12T03:36:03.593Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/e1/c5/61175d618685d42b005847464b8fb4743a67b1b8fdb75e50e5a96c31a27a/black-26.3.1.tar.gz", hash = "sha256:2c50f5063a9641c7eed7795014ba37b0f5fa227f3d408b968936e24bc0566b07", upload-time = "2026-03-12T03:36:03.593Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/f8/da5eae4fc75e78e6dceb60624e1b9662ab00d6b452996046dfa9b8a6025b/black-26.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e6f89631eb88a7302d416594a32faeee9fb8fb848290da9d0a5f2903519fc1", size = 1895920, upload-time = "2026-03-12T03:40:13.921Z" }, - { url = "https://files.pythonhosted.org/packages/2c/9f/04e6f26534da2e1629b2b48255c264cabf5eedc5141d04516d9d68a24111/black-26.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41cd2012d35b47d589cb8a16faf8a32ef7a336f56356babd9fcf70939ad1897f", size = 1718499, upload-time = "2026-03-12T03:40:15.239Z" }, - { url = "https://files.pythonhosted.org/packages/04/91/a5935b2a63e31b331060c4a9fdb5a6c725840858c599032a6f3aac94055f/black-26.3.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f76ff19ec5297dd8e66eb64deda23631e642c9393ab592826fd4bdc97a4bce7", size = 1794994, upload-time = "2026-03-12T03:40:17.124Z" }, - { url = "https://files.pythonhosted.org/packages/e7/0a/86e462cdd311a3c2a8ece708d22aba17d0b2a0d5348ca34b40cdcbea512e/black-26.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:ddb113db38838eb9f043623ba274cfaf7d51d5b0c22ecb30afe58b1bb8322983", size = 1420867, upload-time = "2026-03-12T03:40:18.83Z" }, - { url = "https://files.pythonhosted.org/packages/5b/e5/22515a19cb7eaee3440325a6b0d95d2c0e88dd180cb011b12ae488e031d1/black-26.3.1-cp312-cp312-win_arm64.whl", hash = "sha256:dfdd51fc3e64ea4f35873d1b3fb25326773d55d2329ff8449139ebaad7357efb", size = 1230124, upload-time = "2026-03-12T03:40:20.425Z" }, - { url = "https://files.pythonhosted.org/packages/8e/0d/52d98722666d6fc6c3dd4c76df339501d6efd40e0ff95e6186a7b7f0befd/black-26.3.1-py3-none-any.whl", hash = "sha256:2bd5aa94fc267d38bb21a70d7410a89f1a1d318841855f698746f8e7f51acd1b", size = 207542, upload-time = "2026-03-12T03:36:01.668Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/dc/f8/da5eae4fc75e78e6dceb60624e1b9662ab00d6b452996046dfa9b8a6025b/black-26.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e6f89631eb88a7302d416594a32faeee9fb8fb848290da9d0a5f2903519fc1", upload-time = "2026-03-12T03:40:13.921Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/2c/9f/04e6f26534da2e1629b2b48255c264cabf5eedc5141d04516d9d68a24111/black-26.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41cd2012d35b47d589cb8a16faf8a32ef7a336f56356babd9fcf70939ad1897f", upload-time = "2026-03-12T03:40:15.239Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/04/91/a5935b2a63e31b331060c4a9fdb5a6c725840858c599032a6f3aac94055f/black-26.3.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f76ff19ec5297dd8e66eb64deda23631e642c9393ab592826fd4bdc97a4bce7", upload-time = "2026-03-12T03:40:17.124Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/e7/0a/86e462cdd311a3c2a8ece708d22aba17d0b2a0d5348ca34b40cdcbea512e/black-26.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:ddb113db38838eb9f043623ba274cfaf7d51d5b0c22ecb30afe58b1bb8322983", upload-time = "2026-03-12T03:40:18.83Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/5b/e5/22515a19cb7eaee3440325a6b0d95d2c0e88dd180cb011b12ae488e031d1/black-26.3.1-cp312-cp312-win_arm64.whl", hash = "sha256:dfdd51fc3e64ea4f35873d1b3fb25326773d55d2329ff8449139ebaad7357efb", upload-time = "2026-03-12T03:40:20.425Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/8e/0d/52d98722666d6fc6c3dd4c76df339501d6efd40e0ff95e6186a7b7f0befd/black-26.3.1-py3-none-any.whl", hash = "sha256:2bd5aa94fc267d38bb21a70d7410a89f1a1d318841855f698746f8e7f51acd1b", upload-time = "2026-03-12T03:36:01.668Z" }, +] + +[[package]] +name = "canmatrix" +version = "1.2" +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +dependencies = [ + { name = "attrs" }, + { name = "click" }, +] +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/8a/ed/a05ab5923cd2a6e239317992cf876753cbb8d4f9ff729ce916599dcd0abb/canmatrix-1.2.tar.gz", hash = "sha256:19d5ba3fd69974bd41985b90198503bfde6ae3639dfc8ce6a2f7a0338787dbf7", upload-time = "2025-02-17T10:22:40.154Z" } +wheels = [ + { url = "https://pypi-proxy.cloud.databricks.com/packages/f2/9c/6c2dc03d2aa30176985257b64bf3393c77d28bc019db28654c8c514493f2/canmatrix-1.2-py3-none-any.whl", hash = "sha256:9fbb03c58404489f7d2832ec31b8b10f3e7d5525f15456f60f852b89e721ebf9", upload-time = "2025-02-17T10:22:38.13Z" }, +] + +[package.optional-dependencies] +arxml = [ + { name = "lxml" }, ] [[package]] name = "certifi" version = "2026.4.22" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/25/ee/6caf7a40c36a1220410afe15a1cc64993a1f864871f698c0f93acb72842a/certifi-2026.4.22.tar.gz", hash = "sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580", size = 137077, upload-time = "2026-04-22T11:26:11.191Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/25/ee/6caf7a40c36a1220410afe15a1cc64993a1f864871f698c0f93acb72842a/certifi-2026.4.22.tar.gz", hash = "sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580", upload-time = "2026-04-22T11:26:11.191Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/22/30/7cd8fdcdfbc5b869528b079bfb76dcdf6056b1a2097a662e5e8c04f42965/certifi-2026.4.22-py3-none-any.whl", hash = "sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a", size = 135707, upload-time = "2026-04-22T11:26:09.372Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/22/30/7cd8fdcdfbc5b869528b079bfb76dcdf6056b1a2097a662e5e8c04f42965/certifi-2026.4.22-py3-none-any.whl", hash = "sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a", upload-time = "2026-04-22T11:26:09.372Z" }, ] [[package]] name = "cffi" version = "2.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "pycparser", marker = "implementation_name != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", upload-time = "2025-09-08T23:24:04.541Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, - { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, - { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, - { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, - { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, - { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, - { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, - { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, - { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, - { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, - { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, - { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", upload-time = "2025-09-08T23:22:59.668Z" }, ] [[package]] name = "cfgv" version = "3.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", upload-time = "2025-11-19T20:55:51.612Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", upload-time = "2025-11-19T20:55:50.744Z" }, ] [[package]] name = "charset-normalizer" version = "3.4.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", size = 311328, upload-time = "2026-04-02T09:26:24.331Z" }, - { url = "https://files.pythonhosted.org/packages/f8/e3/0fadc706008ac9d7b9b5be6dc767c05f9d3e5df51744ce4cc9605de7b9f4/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", size = 208061, upload-time = "2026-04-02T09:26:25.568Z" }, - { url = "https://files.pythonhosted.org/packages/42/f0/3dd1045c47f4a4604df85ec18ad093912ae1344ac706993aff91d38773a2/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", size = 229031, upload-time = "2026-04-02T09:26:26.865Z" }, - { url = "https://files.pythonhosted.org/packages/dc/67/675a46eb016118a2fbde5a277a5d15f4f69d5f3f5f338e5ee2f8948fcf43/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a", size = 225239, upload-time = "2026-04-02T09:26:28.044Z" }, - { url = "https://files.pythonhosted.org/packages/4b/f8/d0118a2f5f23b02cd166fa385c60f9b0d4f9194f574e2b31cef350ad7223/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116", size = 216589, upload-time = "2026-04-02T09:26:29.239Z" }, - { url = "https://files.pythonhosted.org/packages/b1/f1/6d2b0b261b6c4ceef0fcb0d17a01cc5bc53586c2d4796fa04b5c540bc13d/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb", size = 202733, upload-time = "2026-04-02T09:26:30.5Z" }, - { url = "https://files.pythonhosted.org/packages/6f/c0/7b1f943f7e87cc3db9626ba17807d042c38645f0a1d4415c7a14afb5591f/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1", size = 212652, upload-time = "2026-04-02T09:26:31.709Z" }, - { url = "https://files.pythonhosted.org/packages/38/dd/5a9ab159fe45c6e72079398f277b7d2b523e7f716acc489726115a910097/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15", size = 211229, upload-time = "2026-04-02T09:26:33.282Z" }, - { url = "https://files.pythonhosted.org/packages/d5/ff/531a1cad5ca855d1c1a8b69cb71abfd6d85c0291580146fda7c82857caa1/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5", size = 203552, upload-time = "2026-04-02T09:26:34.845Z" }, - { url = "https://files.pythonhosted.org/packages/c1/4c/a5fb52d528a8ca41f7598cb619409ece30a169fbdf9cdce592e53b46c3a6/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d", size = 230806, upload-time = "2026-04-02T09:26:36.152Z" }, - { url = "https://files.pythonhosted.org/packages/59/7a/071feed8124111a32b316b33ae4de83d36923039ef8cf48120266844285b/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7", size = 212316, upload-time = "2026-04-02T09:26:37.672Z" }, - { url = "https://files.pythonhosted.org/packages/fd/35/f7dba3994312d7ba508e041eaac39a36b120f32d4c8662b8814dab876431/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464", size = 227274, upload-time = "2026-04-02T09:26:38.93Z" }, - { url = "https://files.pythonhosted.org/packages/8a/2d/a572df5c9204ab7688ec1edc895a73ebded3b023bb07364710b05dd1c9be/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49", size = 218468, upload-time = "2026-04-02T09:26:40.17Z" }, - { url = "https://files.pythonhosted.org/packages/86/eb/890922a8b03a568ca2f336c36585a4713c55d4d67bf0f0c78924be6315ca/charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c", size = 148460, upload-time = "2026-04-02T09:26:41.416Z" }, - { url = "https://files.pythonhosted.org/packages/35/d9/0e7dffa06c5ab081f75b1b786f0aefc88365825dfcd0ac544bdb7b2b6853/charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6", size = 159330, upload-time = "2026-04-02T09:26:42.554Z" }, - { url = "https://files.pythonhosted.org/packages/9e/5d/481bcc2a7c88ea6b0878c299547843b2521ccbc40980cb406267088bc701/charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d", size = 147828, upload-time = "2026-04-02T09:26:44.075Z" }, - { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" }, +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", upload-time = "2026-04-02T09:28:39.342Z" } +wheels = [ + { url = "https://pypi-proxy.cloud.databricks.com/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", upload-time = "2026-04-02T09:26:24.331Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/f8/e3/0fadc706008ac9d7b9b5be6dc767c05f9d3e5df51744ce4cc9605de7b9f4/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", upload-time = "2026-04-02T09:26:25.568Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/42/f0/3dd1045c47f4a4604df85ec18ad093912ae1344ac706993aff91d38773a2/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", upload-time = "2026-04-02T09:26:26.865Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/dc/67/675a46eb016118a2fbde5a277a5d15f4f69d5f3f5f338e5ee2f8948fcf43/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a", upload-time = "2026-04-02T09:26:28.044Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/4b/f8/d0118a2f5f23b02cd166fa385c60f9b0d4f9194f574e2b31cef350ad7223/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116", upload-time = "2026-04-02T09:26:29.239Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/b1/f1/6d2b0b261b6c4ceef0fcb0d17a01cc5bc53586c2d4796fa04b5c540bc13d/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb", upload-time = "2026-04-02T09:26:30.5Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/6f/c0/7b1f943f7e87cc3db9626ba17807d042c38645f0a1d4415c7a14afb5591f/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1", upload-time = "2026-04-02T09:26:31.709Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/38/dd/5a9ab159fe45c6e72079398f277b7d2b523e7f716acc489726115a910097/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15", upload-time = "2026-04-02T09:26:33.282Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/d5/ff/531a1cad5ca855d1c1a8b69cb71abfd6d85c0291580146fda7c82857caa1/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5", upload-time = "2026-04-02T09:26:34.845Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/c1/4c/a5fb52d528a8ca41f7598cb619409ece30a169fbdf9cdce592e53b46c3a6/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d", upload-time = "2026-04-02T09:26:36.152Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/59/7a/071feed8124111a32b316b33ae4de83d36923039ef8cf48120266844285b/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7", upload-time = "2026-04-02T09:26:37.672Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/fd/35/f7dba3994312d7ba508e041eaac39a36b120f32d4c8662b8814dab876431/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464", upload-time = "2026-04-02T09:26:38.93Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/8a/2d/a572df5c9204ab7688ec1edc895a73ebded3b023bb07364710b05dd1c9be/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49", upload-time = "2026-04-02T09:26:40.17Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/86/eb/890922a8b03a568ca2f336c36585a4713c55d4d67bf0f0c78924be6315ca/charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c", upload-time = "2026-04-02T09:26:41.416Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/35/d9/0e7dffa06c5ab081f75b1b786f0aefc88365825dfcd0ac544bdb7b2b6853/charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6", upload-time = "2026-04-02T09:26:42.554Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/9e/5d/481bcc2a7c88ea6b0878c299547843b2521ccbc40980cb406267088bc701/charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d", upload-time = "2026-04-02T09:26:44.075Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", upload-time = "2026-04-02T09:28:37.794Z" }, ] [[package]] name = "click" version = "8.3.3" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bb/63/f9e1ea081ce35720d8b92acde70daaedace594dc93b693c869e0d5910718/click-8.3.3.tar.gz", hash = "sha256:398329ad4837b2ff7cbe1dd166a4c0f8900c3ca3a218de04466f38f6497f18a2", size = 328061, upload-time = "2026-04-22T15:11:27.506Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/bb/63/f9e1ea081ce35720d8b92acde70daaedace594dc93b693c869e0d5910718/click-8.3.3.tar.gz", hash = "sha256:398329ad4837b2ff7cbe1dd166a4c0f8900c3ca3a218de04466f38f6497f18a2", upload-time = "2026-04-22T15:11:27.506Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ae/44/c1221527f6a71a01ec6fbad7fa78f1d50dfa02217385cf0fa3eec7087d59/click-8.3.3-py3-none-any.whl", hash = "sha256:a2bf429bb3033c89fa4936ffb35d5cb471e3719e1f3c8a7c3fff0b8314305613", size = 110502, upload-time = "2026-04-22T15:11:25.044Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/ae/44/c1221527f6a71a01ec6fbad7fa78f1d50dfa02217385cf0fa3eec7087d59/click-8.3.3-py3-none-any.whl", hash = "sha256:a2bf429bb3033c89fa4936ffb35d5cb471e3719e1f3c8a7c3fff0b8314305613", upload-time = "2026-04-22T15:11:25.044Z" }, ] [[package]] name = "colorama" version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", upload-time = "2022-10-25T02:36:22.414Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", upload-time = "2022-10-25T02:36:20.889Z" }, ] [[package]] name = "contourpy" version = "1.3.3" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", upload-time = "2025-07-26T12:03:12.549Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/be/45/adfee365d9ea3d853550b2e735f9d66366701c65db7855cd07621732ccfc/contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb", size = 293419, upload-time = "2025-07-26T12:01:21.16Z" }, - { url = "https://files.pythonhosted.org/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6", size = 273979, upload-time = "2025-07-26T12:01:22.448Z" }, - { url = "https://files.pythonhosted.org/packages/d4/1c/a12359b9b2ca3a845e8f7f9ac08bdf776114eb931392fcad91743e2ea17b/contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7", size = 332653, upload-time = "2025-07-26T12:01:24.155Z" }, - { url = "https://files.pythonhosted.org/packages/63/12/897aeebfb475b7748ea67b61e045accdfcf0d971f8a588b67108ed7f5512/contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8", size = 379536, upload-time = "2025-07-26T12:01:25.91Z" }, - { url = "https://files.pythonhosted.org/packages/43/8a/a8c584b82deb248930ce069e71576fc09bd7174bbd35183b7943fb1064fd/contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea", size = 384397, upload-time = "2025-07-26T12:01:27.152Z" }, - { url = "https://files.pythonhosted.org/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1", size = 362601, upload-time = "2025-07-26T12:01:28.808Z" }, - { url = "https://files.pythonhosted.org/packages/05/0a/a3fe3be3ee2dceb3e615ebb4df97ae6f3828aa915d3e10549ce016302bd1/contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7", size = 1331288, upload-time = "2025-07-26T12:01:31.198Z" }, - { url = "https://files.pythonhosted.org/packages/33/1d/acad9bd4e97f13f3e2b18a3977fe1b4a37ecf3d38d815333980c6c72e963/contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411", size = 1403386, upload-time = "2025-07-26T12:01:33.947Z" }, - { url = "https://files.pythonhosted.org/packages/cf/8f/5847f44a7fddf859704217a99a23a4f6417b10e5ab1256a179264561540e/contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69", size = 185018, upload-time = "2025-07-26T12:01:35.64Z" }, - { url = "https://files.pythonhosted.org/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b", size = 226567, upload-time = "2025-07-26T12:01:36.804Z" }, - { url = "https://files.pythonhosted.org/packages/d1/e2/f05240d2c39a1ed228d8328a78b6f44cd695f7ef47beb3e684cf93604f86/contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc", size = 193655, upload-time = "2025-07-26T12:01:37.999Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/be/45/adfee365d9ea3d853550b2e735f9d66366701c65db7855cd07621732ccfc/contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb", upload-time = "2025-07-26T12:01:21.16Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6", upload-time = "2025-07-26T12:01:22.448Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/d4/1c/a12359b9b2ca3a845e8f7f9ac08bdf776114eb931392fcad91743e2ea17b/contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7", upload-time = "2025-07-26T12:01:24.155Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/63/12/897aeebfb475b7748ea67b61e045accdfcf0d971f8a588b67108ed7f5512/contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8", upload-time = "2025-07-26T12:01:25.91Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/43/8a/a8c584b82deb248930ce069e71576fc09bd7174bbd35183b7943fb1064fd/contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea", upload-time = "2025-07-26T12:01:27.152Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1", upload-time = "2025-07-26T12:01:28.808Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/05/0a/a3fe3be3ee2dceb3e615ebb4df97ae6f3828aa915d3e10549ce016302bd1/contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7", upload-time = "2025-07-26T12:01:31.198Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/33/1d/acad9bd4e97f13f3e2b18a3977fe1b4a37ecf3d38d815333980c6c72e963/contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411", upload-time = "2025-07-26T12:01:33.947Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/cf/8f/5847f44a7fddf859704217a99a23a4f6417b10e5ab1256a179264561540e/contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69", upload-time = "2025-07-26T12:01:35.64Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b", upload-time = "2025-07-26T12:01:36.804Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/d1/e2/f05240d2c39a1ed228d8328a78b6f44cd695f7ef47beb3e684cf93604f86/contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc", upload-time = "2025-07-26T12:01:37.999Z" }, ] [[package]] name = "coverage" version = "7.13.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9d/e0/70553e3000e345daff267cec284ce4cbf3fc141b6da229ac52775b5428f1/coverage-7.13.5.tar.gz", hash = "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179", size = 915967, upload-time = "2026-03-17T10:33:18.341Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/c3/a396306ba7db865bf96fc1fb3b7fd29bcbf3d829df642e77b13555163cd6/coverage-7.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:460cf0114c5016fa841214ff5564aa4864f11948da9440bc97e21ad1f4ba1e01", size = 219554, upload-time = "2026-03-17T10:30:42.208Z" }, - { url = "https://files.pythonhosted.org/packages/a6/16/a68a19e5384e93f811dccc51034b1fd0b865841c390e3c931dcc4699e035/coverage-7.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e223ce4b4ed47f065bfb123687686512e37629be25cc63728557ae7db261422", size = 219908, upload-time = "2026-03-17T10:30:43.906Z" }, - { url = "https://files.pythonhosted.org/packages/29/72/20b917c6793af3a5ceb7fb9c50033f3ec7865f2911a1416b34a7cfa0813b/coverage-7.13.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6e3370441f4513c6252bf042b9c36d22491142385049243253c7e48398a15a9f", size = 251419, upload-time = "2026-03-17T10:30:45.545Z" }, - { url = "https://files.pythonhosted.org/packages/8c/49/cd14b789536ac6a4778c453c6a2338bc0a2fb60c5a5a41b4008328b9acc1/coverage-7.13.5-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:03ccc709a17a1de074fb1d11f217342fb0d2b1582ed544f554fc9fc3f07e95f5", size = 254159, upload-time = "2026-03-17T10:30:47.204Z" }, - { url = "https://files.pythonhosted.org/packages/9d/00/7b0edcfe64e2ed4c0340dac14a52ad0f4c9bd0b8b5e531af7d55b703db7c/coverage-7.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3f4818d065964db3c1c66dc0fbdac5ac692ecbc875555e13374fdbe7eedb4376", size = 255270, upload-time = "2026-03-17T10:30:48.812Z" }, - { url = "https://files.pythonhosted.org/packages/93/89/7ffc4ba0f5d0a55c1e84ea7cee39c9fc06af7b170513d83fbf3bbefce280/coverage-7.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:012d5319e66e9d5a218834642d6c35d265515a62f01157a45bcc036ecf947256", size = 257538, upload-time = "2026-03-17T10:30:50.77Z" }, - { url = "https://files.pythonhosted.org/packages/81/bd/73ddf85f93f7e6fa83e77ccecb6162d9415c79007b4bc124008a4995e4a7/coverage-7.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8dd02af98971bdb956363e4827d34425cb3df19ee550ef92855b0acb9c7ce51c", size = 251821, upload-time = "2026-03-17T10:30:52.5Z" }, - { url = "https://files.pythonhosted.org/packages/a0/81/278aff4e8dec4926a0bcb9486320752811f543a3ce5b602cc7a29978d073/coverage-7.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f08fd75c50a760c7eb068ae823777268daaf16a80b918fa58eea888f8e3919f5", size = 253191, upload-time = "2026-03-17T10:30:54.543Z" }, - { url = "https://files.pythonhosted.org/packages/70/ee/fe1621488e2e0a58d7e94c4800f0d96f79671553488d401a612bebae324b/coverage-7.13.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:843ea8643cf967d1ac7e8ecd4bb00c99135adf4816c0c0593fdcc47b597fcf09", size = 251337, upload-time = "2026-03-17T10:30:56.663Z" }, - { url = "https://files.pythonhosted.org/packages/37/a6/f79fb37aa104b562207cc23cb5711ab6793608e246cae1e93f26b2236ed9/coverage-7.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:9d44d7aa963820b1b971dbecd90bfe5fe8f81cff79787eb6cca15750bd2f79b9", size = 255404, upload-time = "2026-03-17T10:30:58.427Z" }, - { url = "https://files.pythonhosted.org/packages/75/f0/ed15262a58ec81ce457ceb717b7f78752a1713556b19081b76e90896e8d4/coverage-7.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7132bed4bd7b836200c591410ae7d97bf7ae8be6fc87d160b2bd881df929e7bf", size = 250903, upload-time = "2026-03-17T10:31:00.093Z" }, - { url = "https://files.pythonhosted.org/packages/0f/e9/9129958f20e7e9d4d56d51d42ccf708d15cac355ff4ac6e736e97a9393d2/coverage-7.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a698e363641b98843c517817db75373c83254781426e94ada3197cabbc2c919c", size = 252780, upload-time = "2026-03-17T10:31:01.916Z" }, - { url = "https://files.pythonhosted.org/packages/a4/d7/0ad9b15812d81272db94379fe4c6df8fd17781cc7671fdfa30c76ba5ff7b/coverage-7.13.5-cp312-cp312-win32.whl", hash = "sha256:bdba0a6b8812e8c7df002d908a9a2ea3c36e92611b5708633c50869e6d922fdf", size = 222093, upload-time = "2026-03-17T10:31:03.642Z" }, - { url = "https://files.pythonhosted.org/packages/29/3d/821a9a5799fac2556bcf0bd37a70d1d11fa9e49784b6d22e92e8b2f85f18/coverage-7.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:d2c87e0c473a10bffe991502eac389220533024c8082ec1ce849f4218dded810", size = 222900, upload-time = "2026-03-17T10:31:05.651Z" }, - { url = "https://files.pythonhosted.org/packages/d4/fa/2238c2ad08e35cf4f020ea721f717e09ec3152aea75d191a7faf3ef009a8/coverage-7.13.5-cp312-cp312-win_arm64.whl", hash = "sha256:bf69236a9a81bdca3bff53796237aab096cdbf8d78a66ad61e992d9dac7eb2de", size = 221515, upload-time = "2026-03-17T10:31:07.293Z" }, - { url = "https://files.pythonhosted.org/packages/9e/ee/a4cf96b8ce1e566ed238f0659ac2d3f007ed1d14b181bcb684e19561a69a/coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61", size = 211346, upload-time = "2026-03-17T10:33:15.691Z" }, +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/9d/e0/70553e3000e345daff267cec284ce4cbf3fc141b6da229ac52775b5428f1/coverage-7.13.5.tar.gz", hash = "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179", upload-time = "2026-03-17T10:33:18.341Z" } +wheels = [ + { url = "https://pypi-proxy.cloud.databricks.com/packages/a0/c3/a396306ba7db865bf96fc1fb3b7fd29bcbf3d829df642e77b13555163cd6/coverage-7.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:460cf0114c5016fa841214ff5564aa4864f11948da9440bc97e21ad1f4ba1e01", upload-time = "2026-03-17T10:30:42.208Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/a6/16/a68a19e5384e93f811dccc51034b1fd0b865841c390e3c931dcc4699e035/coverage-7.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e223ce4b4ed47f065bfb123687686512e37629be25cc63728557ae7db261422", upload-time = "2026-03-17T10:30:43.906Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/29/72/20b917c6793af3a5ceb7fb9c50033f3ec7865f2911a1416b34a7cfa0813b/coverage-7.13.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6e3370441f4513c6252bf042b9c36d22491142385049243253c7e48398a15a9f", upload-time = "2026-03-17T10:30:45.545Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/8c/49/cd14b789536ac6a4778c453c6a2338bc0a2fb60c5a5a41b4008328b9acc1/coverage-7.13.5-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:03ccc709a17a1de074fb1d11f217342fb0d2b1582ed544f554fc9fc3f07e95f5", upload-time = "2026-03-17T10:30:47.204Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/9d/00/7b0edcfe64e2ed4c0340dac14a52ad0f4c9bd0b8b5e531af7d55b703db7c/coverage-7.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3f4818d065964db3c1c66dc0fbdac5ac692ecbc875555e13374fdbe7eedb4376", upload-time = "2026-03-17T10:30:48.812Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/93/89/7ffc4ba0f5d0a55c1e84ea7cee39c9fc06af7b170513d83fbf3bbefce280/coverage-7.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:012d5319e66e9d5a218834642d6c35d265515a62f01157a45bcc036ecf947256", upload-time = "2026-03-17T10:30:50.77Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/81/bd/73ddf85f93f7e6fa83e77ccecb6162d9415c79007b4bc124008a4995e4a7/coverage-7.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8dd02af98971bdb956363e4827d34425cb3df19ee550ef92855b0acb9c7ce51c", upload-time = "2026-03-17T10:30:52.5Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/a0/81/278aff4e8dec4926a0bcb9486320752811f543a3ce5b602cc7a29978d073/coverage-7.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f08fd75c50a760c7eb068ae823777268daaf16a80b918fa58eea888f8e3919f5", upload-time = "2026-03-17T10:30:54.543Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/70/ee/fe1621488e2e0a58d7e94c4800f0d96f79671553488d401a612bebae324b/coverage-7.13.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:843ea8643cf967d1ac7e8ecd4bb00c99135adf4816c0c0593fdcc47b597fcf09", upload-time = "2026-03-17T10:30:56.663Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/37/a6/f79fb37aa104b562207cc23cb5711ab6793608e246cae1e93f26b2236ed9/coverage-7.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:9d44d7aa963820b1b971dbecd90bfe5fe8f81cff79787eb6cca15750bd2f79b9", upload-time = "2026-03-17T10:30:58.427Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/75/f0/ed15262a58ec81ce457ceb717b7f78752a1713556b19081b76e90896e8d4/coverage-7.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7132bed4bd7b836200c591410ae7d97bf7ae8be6fc87d160b2bd881df929e7bf", upload-time = "2026-03-17T10:31:00.093Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/0f/e9/9129958f20e7e9d4d56d51d42ccf708d15cac355ff4ac6e736e97a9393d2/coverage-7.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a698e363641b98843c517817db75373c83254781426e94ada3197cabbc2c919c", upload-time = "2026-03-17T10:31:01.916Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/a4/d7/0ad9b15812d81272db94379fe4c6df8fd17781cc7671fdfa30c76ba5ff7b/coverage-7.13.5-cp312-cp312-win32.whl", hash = "sha256:bdba0a6b8812e8c7df002d908a9a2ea3c36e92611b5708633c50869e6d922fdf", upload-time = "2026-03-17T10:31:03.642Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/29/3d/821a9a5799fac2556bcf0bd37a70d1d11fa9e49784b6d22e92e8b2f85f18/coverage-7.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:d2c87e0c473a10bffe991502eac389220533024c8082ec1ce849f4218dded810", upload-time = "2026-03-17T10:31:05.651Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/d4/fa/2238c2ad08e35cf4f020ea721f717e09ec3152aea75d191a7faf3ef009a8/coverage-7.13.5-cp312-cp312-win_arm64.whl", hash = "sha256:bf69236a9a81bdca3bff53796237aab096cdbf8d78a66ad61e992d9dac7eb2de", upload-time = "2026-03-17T10:31:07.293Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/9e/ee/a4cf96b8ce1e566ed238f0659ac2d3f007ed1d14b181bcb684e19561a69a/coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61", upload-time = "2026-03-17T10:33:15.691Z" }, ] [[package]] name = "cryptography" version = "47.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ef/b2/7ffa7fe8207a8c42147ffe70c3e360b228160c1d85dc3faff16aaa3244c0/cryptography-47.0.0.tar.gz", hash = "sha256:9f8e55fe4e63613a5e1cc5819030f27b97742d720203a087802ce4ce9ceb52bb", size = 830863, upload-time = "2026-04-24T19:54:57.056Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/98/40dfe932134bdcae4f6ab5927c87488754bf9eb79297d7e0070b78dd58e9/cryptography-47.0.0-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:160ad728f128972d362e714054f6ba0067cab7fb350c5202a9ae8ae4ce3ef1a0", size = 7912214, upload-time = "2026-04-24T19:53:03.864Z" }, - { url = "https://files.pythonhosted.org/packages/34/c6/2733531243fba725f58611b918056b277692f1033373dcc8bd01af1c05d4/cryptography-47.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b9a8943e359b7615db1a3ba587994618e094ff3d6fa5a390c73d079ce18b3973", size = 4644617, upload-time = "2026-04-24T19:53:06.909Z" }, - { url = "https://files.pythonhosted.org/packages/00/e3/b27be1a670a9b87f855d211cf0e1174a5d721216b7616bd52d8581d912ed/cryptography-47.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f5c15764f261394b22aef6b00252f5195f46f2ca300bec57149474e2538b31f8", size = 4668186, upload-time = "2026-04-24T19:53:09.053Z" }, - { url = "https://files.pythonhosted.org/packages/81/b9/8443cfe5d17d482d348cee7048acf502bb89a51b6382f06240fd290d4ca3/cryptography-47.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9c59ab0e0fa3a180a5a9c59f3a5abe3ef90d474bc56d7fadfbe80359491b615b", size = 4651244, upload-time = "2026-04-24T19:53:11.217Z" }, - { url = "https://files.pythonhosted.org/packages/5d/5e/13ed0cdd0eb88ba159d6dd5ebfece8cb901dbcf1ae5ac4072e28b55d3153/cryptography-47.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:34b4358b925a5ea3e14384ca781a2c0ef7ac219b57bb9eacc4457078e2b19f92", size = 5252906, upload-time = "2026-04-24T19:53:13.532Z" }, - { url = "https://files.pythonhosted.org/packages/64/16/ed058e1df0f33d440217cd120d41d5dda9dd215a80b8187f68483185af82/cryptography-47.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0024b87d47ae2399165a6bfb20d24888881eeab83ae2566d62467c5ff0030ce7", size = 4701842, upload-time = "2026-04-24T19:53:15.618Z" }, - { url = "https://files.pythonhosted.org/packages/02/e0/3d30986b30fdbd9e969abbdf8ba00ed0618615144341faeb57f395a084fe/cryptography-47.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:1e47422b5557bb82d3fff997e8d92cff4e28b9789576984f08c248d2b3535d93", size = 4289313, upload-time = "2026-04-24T19:53:17.755Z" }, - { url = "https://files.pythonhosted.org/packages/df/fd/32db38e3ad0cb331f0691cb4c7a8a6f176f679124dee746b3af6633db4d9/cryptography-47.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:6f29f36582e6151d9686235e586dd35bb67491f024767d10b842e520dc6a07ac", size = 4650964, upload-time = "2026-04-24T19:53:20.062Z" }, - { url = "https://files.pythonhosted.org/packages/86/53/5395d944dfd48cb1f67917f533c609c34347185ef15eb4308024c876f274/cryptography-47.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:a9b761f012a943b7de0e828843c5688d0de94a0578d44d6c85a1bae32f87791f", size = 5207817, upload-time = "2026-04-24T19:53:22.498Z" }, - { url = "https://files.pythonhosted.org/packages/34/4f/e5711b28e1901f7d480a2b1b688b645aa4c77c73f10731ed17e7f7db3f0d/cryptography-47.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4e1de79e047e25d6e9f8cea71c86b4a53aced64134f0f003bbcbf3655fd172c8", size = 4701544, upload-time = "2026-04-24T19:53:24.356Z" }, - { url = "https://files.pythonhosted.org/packages/22/22/c8ddc25de3010fc8da447648f5a092c40e7a8fadf01dd6d255d9c0b9373d/cryptography-47.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef6b3634087f18d2155b1e8ce264e5345a753da2c5fa9815e7d41315c90f8318", size = 4783536, upload-time = "2026-04-24T19:53:26.665Z" }, - { url = "https://files.pythonhosted.org/packages/66/b6/d4a68f4ea999c6d89e8498579cba1c5fcba4276284de7773b17e4fa69293/cryptography-47.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:11dbb9f50a0f1bb9757b3d8c27c1101780efb8f0bdecfb12439c22a74d64c001", size = 4926106, upload-time = "2026-04-24T19:53:28.686Z" }, - { url = "https://files.pythonhosted.org/packages/54/ed/5f524db1fade9c013aa618e1c99c6ed05e8ffc9ceee6cda22fed22dda3f4/cryptography-47.0.0-cp311-abi3-win32.whl", hash = "sha256:7fda2f02c9015db3f42bb8a22324a454516ed10a8c29ca6ece6cdbb5efe2a203", size = 3258581, upload-time = "2026-04-24T19:53:31.058Z" }, - { url = "https://files.pythonhosted.org/packages/b2/dc/1b901990b174786569029f67542b3edf72ac068b6c3c8683c17e6a2f5363/cryptography-47.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:f5c3296dab66202f1b18a91fa266be93d6aa0c2806ea3d67762c69f60adc71aa", size = 3775309, upload-time = "2026-04-24T19:53:33.054Z" }, - { url = "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:14432c8a9bcb37009784f9594a62fae211a2ae9543e96c92b2a8e4c3cd5cd0c4", size = 7904072, upload-time = "2026-04-24T19:54:06.411Z" }, - { url = "https://files.pythonhosted.org/packages/01/64/d7b1e54fdb69f22d24a64bb3e88dc718b31c7fb10ef0b9691a3cf7eeea6e/cryptography-47.0.0-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:07efe86201817e7d3c18781ca9770bc0db04e1e48c994be384e4602bc38f8f27", size = 4635767, upload-time = "2026-04-24T19:54:08.519Z" }, - { url = "https://files.pythonhosted.org/packages/8b/7b/cca826391fb2a94efdcdfe4631eb69306ee1cff0b22f664a412c90713877/cryptography-47.0.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2b45761c6ec22b7c726d6a829558777e32d0f1c8be7c3f3480f9c912d5ee8a10", size = 4654350, upload-time = "2026-04-24T19:54:10.795Z" }, - { url = "https://files.pythonhosted.org/packages/4c/65/4b57bcc823f42a991627c51c2f68c9fd6eb1393c1756aac876cba2accae2/cryptography-47.0.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:edd4da498015da5b9f26d38d3bfc2e90257bfa9cbed1f6767c282a0025ae649b", size = 4643394, upload-time = "2026-04-24T19:54:13.275Z" }, - { url = "https://files.pythonhosted.org/packages/f4/c4/2c5fbeea70adbbca2bbae865e1d605d6a4a7f8dbd9d33eaf69645087f06c/cryptography-47.0.0-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:9af828c0d5a65c70ec729cd7495a4bf1a67ecb66417b8f02ff125ab8a6326a74", size = 5225777, upload-time = "2026-04-24T19:54:15.18Z" }, - { url = "https://files.pythonhosted.org/packages/7e/b8/ac57107ef32749d2b244e36069bb688792a363aaaa3acc9e3cf84c130315/cryptography-47.0.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:256d07c78a04d6b276f5df935a9923275f53bd1522f214447fdf365494e2d515", size = 4688771, upload-time = "2026-04-24T19:54:17.835Z" }, - { url = "https://files.pythonhosted.org/packages/56/fc/9f1de22ff8be99d991f240a46863c52d475404c408886c5a38d2b5c3bb26/cryptography-47.0.0-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:5d0e362ff51041b0c0d219cc7d6924d7b8996f57ce5712bdcef71eb3c65a59cc", size = 4270753, upload-time = "2026-04-24T19:54:19.963Z" }, - { url = "https://files.pythonhosted.org/packages/00/68/d70c852797aa68e8e48d12e5a87170c43f67bb4a59403627259dd57d15de/cryptography-47.0.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:1581aef4219f7ca2849d0250edaa3866212fb74bf5667284f46aa92f9e65c1ca", size = 4642911, upload-time = "2026-04-24T19:54:21.818Z" }, - { url = "https://files.pythonhosted.org/packages/a5/51/661cbee74f594c5d97ff82d34f10d5551c085ca4668645f4606ebd22bd5d/cryptography-47.0.0-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:a49a3eb5341b9503fa3000a9a0db033161db90d47285291f53c2a9d2cd1b7f76", size = 5181411, upload-time = "2026-04-24T19:54:24.376Z" }, - { url = "https://files.pythonhosted.org/packages/94/87/f2b6c374a82cf076cfa1416992ac8e8ec94d79facc37aec87c1a5cb72352/cryptography-47.0.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:2207a498b03275d0051589e326b79d4cf59985c99031b05bb292ac52631c37fe", size = 4688262, upload-time = "2026-04-24T19:54:26.946Z" }, - { url = "https://files.pythonhosted.org/packages/14/e2/8b7462f4acf21ec509616f0245018bb197194ab0b65c2ea21a0bdd53c0eb/cryptography-47.0.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7a02675e2fabd0c0fc04c868b8781863cbf1967691543c22f5470500ff840b31", size = 4775506, upload-time = "2026-04-24T19:54:28.926Z" }, - { url = "https://files.pythonhosted.org/packages/70/75/158e494e4c08dc05e039da5bb48553826bd26c23930cf8d3cd5f21fa8921/cryptography-47.0.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80887c5cbd1774683cb126f0ab4184567f080071d5acf62205acb354b4b753b7", size = 4912060, upload-time = "2026-04-24T19:54:30.869Z" }, - { url = "https://files.pythonhosted.org/packages/06/bd/0a9d3edbf5eadbac926d7b9b3cd0c4be584eeeae4a003d24d9eda4affbbd/cryptography-47.0.0-cp38-abi3-win32.whl", hash = "sha256:ed67ea4e0cfb5faa5bc7ecb6e2b8838f3807a03758eec239d6c21c8769355310", size = 3248487, upload-time = "2026-04-24T19:54:33.494Z" }, - { url = "https://files.pythonhosted.org/packages/60/80/5681af756d0da3a599b7bdb586fac5a1540f1bcefd2717a20e611ddade45/cryptography-47.0.0-cp38-abi3-win_amd64.whl", hash = "sha256:835d2d7f47cdc53b3224e90810fb1d36ca94ea29cc1801fb4c1bc43876735769", size = 3755737, upload-time = "2026-04-24T19:54:35.408Z" }, +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/ef/b2/7ffa7fe8207a8c42147ffe70c3e360b228160c1d85dc3faff16aaa3244c0/cryptography-47.0.0.tar.gz", hash = "sha256:9f8e55fe4e63613a5e1cc5819030f27b97742d720203a087802ce4ce9ceb52bb", upload-time = "2026-04-24T19:54:57.056Z" } +wheels = [ + { url = "https://pypi-proxy.cloud.databricks.com/packages/a4/98/40dfe932134bdcae4f6ab5927c87488754bf9eb79297d7e0070b78dd58e9/cryptography-47.0.0-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:160ad728f128972d362e714054f6ba0067cab7fb350c5202a9ae8ae4ce3ef1a0", upload-time = "2026-04-24T19:53:03.864Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/34/c6/2733531243fba725f58611b918056b277692f1033373dcc8bd01af1c05d4/cryptography-47.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b9a8943e359b7615db1a3ba587994618e094ff3d6fa5a390c73d079ce18b3973", upload-time = "2026-04-24T19:53:06.909Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/00/e3/b27be1a670a9b87f855d211cf0e1174a5d721216b7616bd52d8581d912ed/cryptography-47.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f5c15764f261394b22aef6b00252f5195f46f2ca300bec57149474e2538b31f8", upload-time = "2026-04-24T19:53:09.053Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/81/b9/8443cfe5d17d482d348cee7048acf502bb89a51b6382f06240fd290d4ca3/cryptography-47.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9c59ab0e0fa3a180a5a9c59f3a5abe3ef90d474bc56d7fadfbe80359491b615b", upload-time = "2026-04-24T19:53:11.217Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/5d/5e/13ed0cdd0eb88ba159d6dd5ebfece8cb901dbcf1ae5ac4072e28b55d3153/cryptography-47.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:34b4358b925a5ea3e14384ca781a2c0ef7ac219b57bb9eacc4457078e2b19f92", upload-time = "2026-04-24T19:53:13.532Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/64/16/ed058e1df0f33d440217cd120d41d5dda9dd215a80b8187f68483185af82/cryptography-47.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0024b87d47ae2399165a6bfb20d24888881eeab83ae2566d62467c5ff0030ce7", upload-time = "2026-04-24T19:53:15.618Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/02/e0/3d30986b30fdbd9e969abbdf8ba00ed0618615144341faeb57f395a084fe/cryptography-47.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:1e47422b5557bb82d3fff997e8d92cff4e28b9789576984f08c248d2b3535d93", upload-time = "2026-04-24T19:53:17.755Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/df/fd/32db38e3ad0cb331f0691cb4c7a8a6f176f679124dee746b3af6633db4d9/cryptography-47.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:6f29f36582e6151d9686235e586dd35bb67491f024767d10b842e520dc6a07ac", upload-time = "2026-04-24T19:53:20.062Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/86/53/5395d944dfd48cb1f67917f533c609c34347185ef15eb4308024c876f274/cryptography-47.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:a9b761f012a943b7de0e828843c5688d0de94a0578d44d6c85a1bae32f87791f", upload-time = "2026-04-24T19:53:22.498Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/34/4f/e5711b28e1901f7d480a2b1b688b645aa4c77c73f10731ed17e7f7db3f0d/cryptography-47.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4e1de79e047e25d6e9f8cea71c86b4a53aced64134f0f003bbcbf3655fd172c8", upload-time = "2026-04-24T19:53:24.356Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/22/22/c8ddc25de3010fc8da447648f5a092c40e7a8fadf01dd6d255d9c0b9373d/cryptography-47.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef6b3634087f18d2155b1e8ce264e5345a753da2c5fa9815e7d41315c90f8318", upload-time = "2026-04-24T19:53:26.665Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/66/b6/d4a68f4ea999c6d89e8498579cba1c5fcba4276284de7773b17e4fa69293/cryptography-47.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:11dbb9f50a0f1bb9757b3d8c27c1101780efb8f0bdecfb12439c22a74d64c001", upload-time = "2026-04-24T19:53:28.686Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/54/ed/5f524db1fade9c013aa618e1c99c6ed05e8ffc9ceee6cda22fed22dda3f4/cryptography-47.0.0-cp311-abi3-win32.whl", hash = "sha256:7fda2f02c9015db3f42bb8a22324a454516ed10a8c29ca6ece6cdbb5efe2a203", upload-time = "2026-04-24T19:53:31.058Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/b2/dc/1b901990b174786569029f67542b3edf72ac068b6c3c8683c17e6a2f5363/cryptography-47.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:f5c3296dab66202f1b18a91fa266be93d6aa0c2806ea3d67762c69f60adc71aa", upload-time = "2026-04-24T19:53:33.054Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:14432c8a9bcb37009784f9594a62fae211a2ae9543e96c92b2a8e4c3cd5cd0c4", upload-time = "2026-04-24T19:54:06.411Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/01/64/d7b1e54fdb69f22d24a64bb3e88dc718b31c7fb10ef0b9691a3cf7eeea6e/cryptography-47.0.0-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:07efe86201817e7d3c18781ca9770bc0db04e1e48c994be384e4602bc38f8f27", upload-time = "2026-04-24T19:54:08.519Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/8b/7b/cca826391fb2a94efdcdfe4631eb69306ee1cff0b22f664a412c90713877/cryptography-47.0.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2b45761c6ec22b7c726d6a829558777e32d0f1c8be7c3f3480f9c912d5ee8a10", upload-time = "2026-04-24T19:54:10.795Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/4c/65/4b57bcc823f42a991627c51c2f68c9fd6eb1393c1756aac876cba2accae2/cryptography-47.0.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:edd4da498015da5b9f26d38d3bfc2e90257bfa9cbed1f6767c282a0025ae649b", upload-time = "2026-04-24T19:54:13.275Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/f4/c4/2c5fbeea70adbbca2bbae865e1d605d6a4a7f8dbd9d33eaf69645087f06c/cryptography-47.0.0-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:9af828c0d5a65c70ec729cd7495a4bf1a67ecb66417b8f02ff125ab8a6326a74", upload-time = "2026-04-24T19:54:15.18Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/7e/b8/ac57107ef32749d2b244e36069bb688792a363aaaa3acc9e3cf84c130315/cryptography-47.0.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:256d07c78a04d6b276f5df935a9923275f53bd1522f214447fdf365494e2d515", upload-time = "2026-04-24T19:54:17.835Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/56/fc/9f1de22ff8be99d991f240a46863c52d475404c408886c5a38d2b5c3bb26/cryptography-47.0.0-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:5d0e362ff51041b0c0d219cc7d6924d7b8996f57ce5712bdcef71eb3c65a59cc", upload-time = "2026-04-24T19:54:19.963Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/00/68/d70c852797aa68e8e48d12e5a87170c43f67bb4a59403627259dd57d15de/cryptography-47.0.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:1581aef4219f7ca2849d0250edaa3866212fb74bf5667284f46aa92f9e65c1ca", upload-time = "2026-04-24T19:54:21.818Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/a5/51/661cbee74f594c5d97ff82d34f10d5551c085ca4668645f4606ebd22bd5d/cryptography-47.0.0-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:a49a3eb5341b9503fa3000a9a0db033161db90d47285291f53c2a9d2cd1b7f76", upload-time = "2026-04-24T19:54:24.376Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/94/87/f2b6c374a82cf076cfa1416992ac8e8ec94d79facc37aec87c1a5cb72352/cryptography-47.0.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:2207a498b03275d0051589e326b79d4cf59985c99031b05bb292ac52631c37fe", upload-time = "2026-04-24T19:54:26.946Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/14/e2/8b7462f4acf21ec509616f0245018bb197194ab0b65c2ea21a0bdd53c0eb/cryptography-47.0.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7a02675e2fabd0c0fc04c868b8781863cbf1967691543c22f5470500ff840b31", upload-time = "2026-04-24T19:54:28.926Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/70/75/158e494e4c08dc05e039da5bb48553826bd26c23930cf8d3cd5f21fa8921/cryptography-47.0.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80887c5cbd1774683cb126f0ab4184567f080071d5acf62205acb354b4b753b7", upload-time = "2026-04-24T19:54:30.869Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/06/bd/0a9d3edbf5eadbac926d7b9b3cd0c4be584eeeae4a003d24d9eda4affbbd/cryptography-47.0.0-cp38-abi3-win32.whl", hash = "sha256:ed67ea4e0cfb5faa5bc7ecb6e2b8838f3807a03758eec239d6c21c8769355310", upload-time = "2026-04-24T19:54:33.494Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/60/80/5681af756d0da3a599b7bdb586fac5a1540f1bcefd2717a20e611ddade45/cryptography-47.0.0-cp38-abi3-win_amd64.whl", hash = "sha256:835d2d7f47cdc53b3224e90810fb1d36ca94ea29cc1801fb4c1bc43876735769", upload-time = "2026-04-24T19:54:35.408Z" }, ] [[package]] name = "cycler" version = "0.12.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", upload-time = "2023-10-07T05:32:18.335Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", upload-time = "2023-10-07T05:32:16.783Z" }, ] [[package]] name = "databind" version = "4.5.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "deprecated" }, { name = "nr-date" }, @@ -225,40 +274,39 @@ dependencies = [ { name = "typeapi" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/71/9e/835a5211eeb7228a0e3870d54def48dd7951dbd951f51b30900020a5f9fc/databind-4.5.4.tar.gz", hash = "sha256:342e170a219b1661e5c1b20778b532aecfa67e46560ba75beb7e2c6faa2150b5", size = 43193, upload-time = "2026-04-02T22:21:47.318Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/71/9e/835a5211eeb7228a0e3870d54def48dd7951dbd951f51b30900020a5f9fc/databind-4.5.4.tar.gz", hash = "sha256:342e170a219b1661e5c1b20778b532aecfa67e46560ba75beb7e2c6faa2150b5", upload-time = "2026-04-02T22:21:47.318Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/db/3b8eb860b5baef89b72c7aadcc5072e1648ca0c98d6ba4b9e4eabbdc2cf5/databind-4.5.4-py3-none-any.whl", hash = "sha256:78467f874a3e80bcd1d3de349167587a0d369831bc64c03798520be86074f96e", size = 52381, upload-time = "2026-04-02T22:21:45.389Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/e2/db/3b8eb860b5baef89b72c7aadcc5072e1648ca0c98d6ba4b9e4eabbdc2cf5/databind-4.5.4-py3-none-any.whl", hash = "sha256:78467f874a3e80bcd1d3de349167587a0d369831bc64c03798520be86074f96e", upload-time = "2026-04-02T22:21:45.389Z" }, ] [[package]] name = "databind-core" version = "4.5.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "databind" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9e/dc/b63a6f6a404146e8e3f1226c9243a5cb30784a1f75218d014cafce9a411f/databind_core-4.5.4.tar.gz", hash = "sha256:a7a47af183d4a8046c893fc19fa9c085f287a15e57a05e58345016086ce0f807", size = 974, upload-time = "2026-04-02T22:21:56.588Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/9e/dc/b63a6f6a404146e8e3f1226c9243a5cb30784a1f75218d014cafce9a411f/databind_core-4.5.4.tar.gz", hash = "sha256:a7a47af183d4a8046c893fc19fa9c085f287a15e57a05e58345016086ce0f807", upload-time = "2026-04-02T22:21:56.588Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/cf/1d1f4d37b4112f26ea5086d54200837d1dcbddaa536f3a70bb1d8b48ed9a/databind_core-4.5.4-py3-none-any.whl", hash = "sha256:25482c352f4f6fcade7c106c665553a18febeccda2972c00cf5af19f473960ab", size = 1666, upload-time = "2026-04-02T22:21:55.504Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/fa/cf/1d1f4d37b4112f26ea5086d54200837d1dcbddaa536f3a70bb1d8b48ed9a/databind_core-4.5.4-py3-none-any.whl", hash = "sha256:25482c352f4f6fcade7c106c665553a18febeccda2972c00cf5af19f473960ab", upload-time = "2026-04-02T22:21:55.504Z" }, ] [[package]] name = "databind-json" version = "4.5.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "databind" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ab/72/9af59950a23ff6a03062acd85879de289595168ec43d6cec57253d00497c/databind_json-4.5.4.tar.gz", hash = "sha256:2c714f9c3039a81e42fc3826e47d7826ef020d93131c34daf4c9ae0483108e4d", size = 966, upload-time = "2026-04-02T22:22:05.538Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/ab/72/9af59950a23ff6a03062acd85879de289595168ec43d6cec57253d00497c/databind_json-4.5.4.tar.gz", hash = "sha256:2c714f9c3039a81e42fc3826e47d7826ef020d93131c34daf4c9ae0483108e4d", upload-time = "2026-04-02T22:22:05.538Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/d4/e00d531202314e29d90c9496f6b4730e3647128b9866180b8ce8ebb79394/databind_json-4.5.4-py3-none-any.whl", hash = "sha256:22e6faaeb6f2ec5cf815fd597a539dfe1f4846b80b618760112f4fe59a0898cc", size = 1664, upload-time = "2026-04-02T22:22:04.204Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/b3/d4/e00d531202314e29d90c9496f6b4730e3647128b9866180b8ce8ebb79394/databind_json-4.5.4-py3-none-any.whl", hash = "sha256:22e6faaeb6f2ec5cf815fd597a539dfe1f4846b80b618760112f4fe59a0898cc", upload-time = "2026-04-02T22:22:04.204Z" }, ] [[package]] name = "databricks-impulse" source = { editable = "." } dependencies = [ - { name = "delta-spark" }, { name = "lz4" }, { name = "nptyping" }, ] @@ -266,6 +314,7 @@ dependencies = [ [package.optional-dependencies] local-dev = [ { name = "databricks-sdk" }, + { name = "delta-spark" }, { name = "matplotlib" }, { name = "pandas" }, { name = "pyarrow" }, @@ -286,11 +335,14 @@ dev = [ { name = "ruff" }, { name = "setuptools" }, ] +test = [ + { name = "asammdf" }, +] [package.metadata] requires-dist = [ { name = "databricks-sdk", marker = "extra == 'local-dev'", specifier = "==0.106.0" }, - { name = "delta-spark", specifier = "==4.0.1" }, + { name = "delta-spark", marker = "extra == 'local-dev'", specifier = "==4.0.1" }, { name = "lz4", specifier = "==4.4.5" }, { name = "matplotlib", marker = "extra == 'local-dev'", specifier = "==3.10.0" }, { name = "nptyping", specifier = "==2.5.0" }, @@ -314,245 +366,284 @@ dev = [ { name = "ruff", specifier = "==0.9.10" }, { name = "setuptools", specifier = "==75.8.2" }, ] +test = [{ name = "asammdf", specifier = "==8.0.1" }] [[package]] name = "databricks-sdk" version = "0.106.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "google-auth" }, { name = "protobuf" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b5/b7/ef86e7b8c3d135c844f972e06efb628e147eed0a7b9a0ecbf9511437a3c2/databricks_sdk-0.106.0.tar.gz", hash = "sha256:6bbd492cb8593747aced037b9186f8632e9d553fc358e6f3d83b7e959851d9d3", size = 930953, upload-time = "2026-04-30T12:33:19.601Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/b5/b7/ef86e7b8c3d135c844f972e06efb628e147eed0a7b9a0ecbf9511437a3c2/databricks_sdk-0.106.0.tar.gz", hash = "sha256:6bbd492cb8593747aced037b9186f8632e9d553fc358e6f3d83b7e959851d9d3", upload-time = "2026-04-30T12:33:19.601Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/a9/63b4f6ef3078e4d060faaad85c4e43667189c3429edd68d5cbddc45187ca/databricks_sdk-0.106.0-py3-none-any.whl", hash = "sha256:db9de5566279ae80dfea0ecd37231e8968523ef984e83cbe4bd77e50c59aa6a5", size = 879452, upload-time = "2026-04-30T12:33:18.116Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/07/a9/63b4f6ef3078e4d060faaad85c4e43667189c3429edd68d5cbddc45187ca/databricks_sdk-0.106.0-py3-none-any.whl", hash = "sha256:db9de5566279ae80dfea0ecd37231e8968523ef984e83cbe4bd77e50c59aa6a5", upload-time = "2026-04-30T12:33:18.116Z" }, ] [[package]] name = "delta-spark" version = "4.0.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "importlib-metadata" }, { name = "pyspark" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8f/4d/9670c5b109fb1c7a84814525cb116203cc36a6112eca546785d617f41a08/delta_spark-4.0.1.tar.gz", hash = "sha256:066512d723f615c9a900e1aa4d83bbc7d0f27a1703e1d5dc52606ea51b8733cc", size = 35521, upload-time = "2026-01-10T02:40:50.315Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/8f/4d/9670c5b109fb1c7a84814525cb116203cc36a6112eca546785d617f41a08/delta_spark-4.0.1.tar.gz", hash = "sha256:066512d723f615c9a900e1aa4d83bbc7d0f27a1703e1d5dc52606ea51b8733cc", upload-time = "2026-01-10T02:40:50.315Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/13/22/a3716bc5ea86786be5f0afd09f62b20e6a111fa2d78868e930b19367a88c/delta_spark-4.0.1-py3-none-any.whl", hash = "sha256:ae0707eda68f05c6ec20b841c8966bb1201d1a5f124d9e94e8c2232162139be8", size = 43002, upload-time = "2026-01-10T02:40:49.047Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/13/22/a3716bc5ea86786be5f0afd09f62b20e6a111fa2d78868e930b19367a88c/delta_spark-4.0.1-py3-none-any.whl", hash = "sha256:ae0707eda68f05c6ec20b841c8966bb1201d1a5f124d9e94e8c2232162139be8", upload-time = "2026-01-10T02:40:49.047Z" }, ] [[package]] name = "deprecated" version = "1.3.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", size = 2932523, upload-time = "2025-10-30T08:19:02.757Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", upload-time = "2025-10-30T08:19:02.757Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298, upload-time = "2025-10-30T08:19:00.758Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", upload-time = "2025-10-30T08:19:00.758Z" }, ] [[package]] name = "distlib" version = "0.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", upload-time = "2025-07-17T16:52:00.465Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", upload-time = "2025-07-17T16:51:58.613Z" }, ] [[package]] name = "docspec" version = "2.2.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "databind-core" }, { name = "databind-json" }, { name = "deprecated" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3c/39/7a71382107445b2cd50c67c6194e3e584f19748a817c3b29e8be8a14f00f/docspec-2.2.1.tar.gz", hash = "sha256:4854e77edc0e2de40e785e57e95880f7095a05fe978f8b54cef7a269586e15ff", size = 8646, upload-time = "2023-05-28T11:24:18.68Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/3c/39/7a71382107445b2cd50c67c6194e3e584f19748a817c3b29e8be8a14f00f/docspec-2.2.1.tar.gz", hash = "sha256:4854e77edc0e2de40e785e57e95880f7095a05fe978f8b54cef7a269586e15ff", upload-time = "2023-05-28T11:24:18.68Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/33/aa/0c9d71cc9d450afd3993d09835e2910810a45b0703f585e1aee1d9b78969/docspec-2.2.1-py3-none-any.whl", hash = "sha256:7538f750095a9688c6980ff9a4e029a823a500f64bd00b6b4bdb27951feb31cb", size = 9844, upload-time = "2023-05-28T11:24:15.419Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/33/aa/0c9d71cc9d450afd3993d09835e2910810a45b0703f585e1aee1d9b78969/docspec-2.2.1-py3-none-any.whl", hash = "sha256:7538f750095a9688c6980ff9a4e029a823a500f64bd00b6b4bdb27951feb31cb", upload-time = "2023-05-28T11:24:15.419Z" }, ] [[package]] name = "docspec-python" version = "2.2.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "black" }, { name = "docspec" }, { name = "nr-util" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ea/ea/e6d9d9c2f805c6ac8072d0e3ee5b1da2dd61886c662327df937dec9f282c/docspec_python-2.2.2.tar.gz", hash = "sha256:429be834d09549461b95bf45eb53c16859f3dfb3e9220408b3bfb12812ccb3fb", size = 22154, upload-time = "2025-05-06T12:40:33.286Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/ea/ea/e6d9d9c2f805c6ac8072d0e3ee5b1da2dd61886c662327df937dec9f282c/docspec_python-2.2.2.tar.gz", hash = "sha256:429be834d09549461b95bf45eb53c16859f3dfb3e9220408b3bfb12812ccb3fb", upload-time = "2025-05-06T12:40:33.286Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/03/c2/b3226746fb6b91893da270a60e77bb420d59cf33a7b9a4e719a236955971/docspec_python-2.2.2-py3-none-any.whl", hash = "sha256:caa32dc1e8c470af8a5ecad67cca614e68c1563ac01dab0c0486c4d7f709d6b1", size = 15988, upload-time = "2025-05-06T12:40:31.554Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/03/c2/b3226746fb6b91893da270a60e77bb420d59cf33a7b9a4e719a236955971/docspec_python-2.2.2-py3-none-any.whl", hash = "sha256:caa32dc1e8c470af8a5ecad67cca614e68c1563ac01dab0c0486c4d7f709d6b1", upload-time = "2025-05-06T12:40:31.554Z" }, ] [[package]] name = "docstring-parser" version = "0.11" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/ce/5d6a3782b9f88097ce3e579265015db3372ae78d12f67629b863a9208c96/docstring_parser-0.11.tar.gz", hash = "sha256:93b3f8f481c7d24e37c5d9f30293c89e2933fa209421c8abd731dd3ef0715ecb", size = 22775, upload-time = "2021-09-30T07:44:10.288Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/a2/ce/5d6a3782b9f88097ce3e579265015db3372ae78d12f67629b863a9208c96/docstring_parser-0.11.tar.gz", hash = "sha256:93b3f8f481c7d24e37c5d9f30293c89e2933fa209421c8abd731dd3ef0715ecb", upload-time = "2021-09-30T07:44:10.288Z" } [[package]] name = "filelock" version = "3.29.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/fe/997687a931ab51049acce6fa1f23e8f01216374ea81374ddee763c493db5/filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90", size = 57571, upload-time = "2026-04-19T15:39:10.068Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/b5/fe/997687a931ab51049acce6fa1f23e8f01216374ea81374ddee763c493db5/filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90", upload-time = "2026-04-19T15:39:10.068Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258", size = 39812, upload-time = "2026-04-19T15:39:08.752Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258", upload-time = "2026-04-19T15:39:08.752Z" }, ] [[package]] name = "fonttools" version = "4.62.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9a/08/7012b00a9a5874311b639c3920270c36ee0c445b69d9989a85e5c92ebcb0/fonttools-4.62.1.tar.gz", hash = "sha256:e54c75fd6041f1122476776880f7c3c3295ffa31962dc6ebe2543c00dca58b5d", size = 3580737, upload-time = "2026-03-13T13:54:25.52Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/9a/08/7012b00a9a5874311b639c3920270c36ee0c445b69d9989a85e5c92ebcb0/fonttools-4.62.1.tar.gz", hash = "sha256:e54c75fd6041f1122476776880f7c3c3295ffa31962dc6ebe2543c00dca58b5d", upload-time = "2026-03-13T13:54:25.52Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/47/d4/dbacced3953544b9a93088cc10ef2b596d348c983d5c67a404fa41ec51ba/fonttools-4.62.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:90365821debbd7db678809c7491ca4acd1e0779b9624cdc6ddaf1f31992bf974", size = 2870219, upload-time = "2026-03-13T13:52:53.664Z" }, - { url = "https://files.pythonhosted.org/packages/66/9e/a769c8e99b81e5a87ab7e5e7236684de4e96246aae17274e5347d11ebd78/fonttools-4.62.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12859ff0b47dd20f110804c3e0d0970f7b832f561630cd879969011541a464a9", size = 2414891, upload-time = "2026-03-13T13:52:56.493Z" }, - { url = "https://files.pythonhosted.org/packages/69/64/f19a9e3911968c37e1e620e14dfc5778299e1474f72f4e57c5ec771d9489/fonttools-4.62.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c125ffa00c3d9003cdaaf7f2c79e6e535628093e14b5de1dccb08859b680936", size = 5033197, upload-time = "2026-03-13T13:52:59.179Z" }, - { url = "https://files.pythonhosted.org/packages/9b/8a/99c8b3c3888c5c474c08dbfd7c8899786de9604b727fcefb055b42c84bba/fonttools-4.62.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:149f7d84afca659d1a97e39a4778794a2f83bf344c5ee5134e09995086cc2392", size = 4988768, upload-time = "2026-03-13T13:53:02.761Z" }, - { url = "https://files.pythonhosted.org/packages/d1/c6/0f904540d3e6ab463c1243a0d803504826a11604c72dd58c2949796a1762/fonttools-4.62.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0aa72c43a601cfa9273bb1ae0518f1acadc01ee181a6fc60cd758d7fdadffc04", size = 4971512, upload-time = "2026-03-13T13:53:05.678Z" }, - { url = "https://files.pythonhosted.org/packages/29/0b/5cbef6588dc9bd6b5c9ad6a4d5a8ca384d0cea089da31711bbeb4f9654a6/fonttools-4.62.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:19177c8d96c7c36359266e571c5173bcee9157b59cfc8cb0153c5673dc5a3a7d", size = 5122723, upload-time = "2026-03-13T13:53:08.662Z" }, - { url = "https://files.pythonhosted.org/packages/4a/47/b3a5342d381595ef439adec67848bed561ab7fdb1019fa522e82101b7d9c/fonttools-4.62.1-cp312-cp312-win32.whl", hash = "sha256:a24decd24d60744ee8b4679d38e88b8303d86772053afc29b19d23bb8207803c", size = 2281278, upload-time = "2026-03-13T13:53:10.998Z" }, - { url = "https://files.pythonhosted.org/packages/28/b1/0c2ab56a16f409c6c8a68816e6af707827ad5d629634691ff60a52879792/fonttools-4.62.1-cp312-cp312-win_amd64.whl", hash = "sha256:9e7863e10b3de72376280b515d35b14f5eeed639d1aa7824f4cf06779ec65e42", size = 2331414, upload-time = "2026-03-13T13:53:13.992Z" }, - { url = "https://files.pythonhosted.org/packages/fd/ba/56147c165442cc5ba7e82ecf301c9a68353cede498185869e6e02b4c264f/fonttools-4.62.1-py3-none-any.whl", hash = "sha256:7487782e2113861f4ddcc07c3436450659e3caa5e470b27dc2177cade2d8e7fd", size = 1152647, upload-time = "2026-03-13T13:54:22.735Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/47/d4/dbacced3953544b9a93088cc10ef2b596d348c983d5c67a404fa41ec51ba/fonttools-4.62.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:90365821debbd7db678809c7491ca4acd1e0779b9624cdc6ddaf1f31992bf974", upload-time = "2026-03-13T13:52:53.664Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/66/9e/a769c8e99b81e5a87ab7e5e7236684de4e96246aae17274e5347d11ebd78/fonttools-4.62.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12859ff0b47dd20f110804c3e0d0970f7b832f561630cd879969011541a464a9", upload-time = "2026-03-13T13:52:56.493Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/69/64/f19a9e3911968c37e1e620e14dfc5778299e1474f72f4e57c5ec771d9489/fonttools-4.62.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c125ffa00c3d9003cdaaf7f2c79e6e535628093e14b5de1dccb08859b680936", upload-time = "2026-03-13T13:52:59.179Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/9b/8a/99c8b3c3888c5c474c08dbfd7c8899786de9604b727fcefb055b42c84bba/fonttools-4.62.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:149f7d84afca659d1a97e39a4778794a2f83bf344c5ee5134e09995086cc2392", upload-time = "2026-03-13T13:53:02.761Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/d1/c6/0f904540d3e6ab463c1243a0d803504826a11604c72dd58c2949796a1762/fonttools-4.62.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0aa72c43a601cfa9273bb1ae0518f1acadc01ee181a6fc60cd758d7fdadffc04", upload-time = "2026-03-13T13:53:05.678Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/29/0b/5cbef6588dc9bd6b5c9ad6a4d5a8ca384d0cea089da31711bbeb4f9654a6/fonttools-4.62.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:19177c8d96c7c36359266e571c5173bcee9157b59cfc8cb0153c5673dc5a3a7d", upload-time = "2026-03-13T13:53:08.662Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/4a/47/b3a5342d381595ef439adec67848bed561ab7fdb1019fa522e82101b7d9c/fonttools-4.62.1-cp312-cp312-win32.whl", hash = "sha256:a24decd24d60744ee8b4679d38e88b8303d86772053afc29b19d23bb8207803c", upload-time = "2026-03-13T13:53:10.998Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/28/b1/0c2ab56a16f409c6c8a68816e6af707827ad5d629634691ff60a52879792/fonttools-4.62.1-cp312-cp312-win_amd64.whl", hash = "sha256:9e7863e10b3de72376280b515d35b14f5eeed639d1aa7824f4cf06779ec65e42", upload-time = "2026-03-13T13:53:13.992Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/fd/ba/56147c165442cc5ba7e82ecf301c9a68353cede498185869e6e02b4c264f/fonttools-4.62.1-py3-none-any.whl", hash = "sha256:7487782e2113861f4ddcc07c3436450659e3caa5e470b27dc2177cade2d8e7fd", upload-time = "2026-03-13T13:54:22.735Z" }, ] [[package]] name = "google-auth" version = "2.49.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "cryptography" }, { name = "pyasn1-modules" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c6/fc/e925290a1ad95c975c459e2df070fac2b90954e13a0370ac505dff78cb99/google_auth-2.49.2.tar.gz", hash = "sha256:c1ae38500e73065dcae57355adb6278cf8b5c8e391994ae9cbadbcb9631ab409", size = 333958, upload-time = "2026-04-10T00:41:21.888Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/c6/fc/e925290a1ad95c975c459e2df070fac2b90954e13a0370ac505dff78cb99/google_auth-2.49.2.tar.gz", hash = "sha256:c1ae38500e73065dcae57355adb6278cf8b5c8e391994ae9cbadbcb9631ab409", upload-time = "2026-04-10T00:41:21.888Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/76/d241a5c927433420507215df6cac1b1fa4ac0ba7a794df42a84326c68da8/google_auth-2.49.2-py3-none-any.whl", hash = "sha256:c2720924dfc82dedb962c9f52cabb2ab16714fd0a6a707e40561d217574ed6d5", size = 240638, upload-time = "2026-04-10T00:41:14.501Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/73/76/d241a5c927433420507215df6cac1b1fa4ac0ba7a794df42a84326c68da8/google_auth-2.49.2-py3-none-any.whl", hash = "sha256:c2720924dfc82dedb962c9f52cabb2ab16714fd0a6a707e40561d217574ed6d5", upload-time = "2026-04-10T00:41:14.501Z" }, ] [[package]] name = "identify" version = "2.6.19" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/52/63/51723b5f116cc04b061cb6f5a561790abf249d25931d515cd375e063e0f4/identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842", size = 99567, upload-time = "2026-04-17T18:39:50.265Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/52/63/51723b5f116cc04b061cb6f5a561790abf249d25931d515cd375e063e0f4/identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842", upload-time = "2026-04-17T18:39:50.265Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a", size = 99397, upload-time = "2026-04-17T18:39:49.221Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a", upload-time = "2026-04-17T18:39:49.221Z" }, ] [[package]] name = "idna" version = "3.13" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ce/cc/762dfb036166873f0059f3b7de4565e1b5bc3d6f28a414c13da27e442f99/idna-3.13.tar.gz", hash = "sha256:585ea8fe5d69b9181ec1afba340451fba6ba764af97026f92a91d4eef164a242", size = 194210, upload-time = "2026-04-22T16:42:42.314Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/ce/cc/762dfb036166873f0059f3b7de4565e1b5bc3d6f28a414c13da27e442f99/idna-3.13.tar.gz", hash = "sha256:585ea8fe5d69b9181ec1afba340451fba6ba764af97026f92a91d4eef164a242", upload-time = "2026-04-22T16:42:42.314Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/13/ad7d7ca3808a898b4612b6fe93cde56b53f3034dcde235acb1f0e1df24c6/idna-3.13-py3-none-any.whl", hash = "sha256:892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3", size = 68629, upload-time = "2026-04-22T16:42:40.909Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/5d/13/ad7d7ca3808a898b4612b6fe93cde56b53f3034dcde235acb1f0e1df24c6/idna-3.13-py3-none-any.whl", hash = "sha256:892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3", upload-time = "2026-04-22T16:42:40.909Z" }, ] [[package]] name = "importlib-metadata" version = "9.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "zipp" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a9/01/15bb152d77b21318514a96f43af312635eb2500c96b55398d020c93d86ea/importlib_metadata-9.0.0.tar.gz", hash = "sha256:a4f57ab599e6a2e3016d7595cfd72eb4661a5106e787a95bcc90c7105b831efc", size = 56405, upload-time = "2026-03-20T06:42:56.999Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/a9/01/15bb152d77b21318514a96f43af312635eb2500c96b55398d020c93d86ea/importlib_metadata-9.0.0.tar.gz", hash = "sha256:a4f57ab599e6a2e3016d7595cfd72eb4661a5106e787a95bcc90c7105b831efc", upload-time = "2026-03-20T06:42:56.999Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl", hash = "sha256:2d21d1cc5a017bd0559e36150c21c830ab1dc304dedd1b7ea85d20f45ef3edd7", size = 27789, upload-time = "2026-03-20T06:42:55.665Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl", hash = "sha256:2d21d1cc5a017bd0559e36150c21c830ab1dc304dedd1b7ea85d20f45ef3edd7", upload-time = "2026-03-20T06:42:55.665Z" }, ] [[package]] name = "iniconfig" version = "2.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", upload-time = "2025-10-18T21:55:43.219Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "isal" +version = "1.8.0" +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/9c/35/40ff3eabd401036f792cf55ba9cd19dcd5e3cb79aa5798332885ab0ff1b9/isal-1.8.0.tar.gz", hash = "sha256:124233e9a31a62030a07aafd48c26689561926f4e10417ed3ea46c211218f2b4", upload-time = "2025-09-10T08:47:12.653Z" } +wheels = [ + { url = "https://pypi-proxy.cloud.databricks.com/packages/58/6f/e170e758293712e4f7ac1d0cf92290a80816d0eea8eb0871d82877ca7372/isal-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3255b5dd6ac0238d410a6d630761e3826d4360400e88d6106e8ad85fe9042966", upload-time = "2025-09-10T08:47:31.57Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/29/92/c10343738c170c31a5e25f0a1d024f8160ec107c5a2935a1a07587821100/isal-1.8.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3c28ff61f2f300e498ea0f50cb1528d8c14631fce4cdfce191ed05775952de3", upload-time = "2025-09-10T08:47:01.294Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/9f/72/5cbc30d59821bcf93be44eab758ca999794fbd6e47b67954193d11e92000/isal-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ce55960f53603145d35188ca6363848b79675d81c95a3ff2cfb4b2cb806873e", upload-time = "2025-09-10T08:47:02.178Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/63/a0/3cdaac7caab7e5e2660afbf03d16616f8c3fb91ec3b75596e2388d42b90b/isal-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d376b7644434d50fedfb670483150ece64082212b6e1f23976f92a91fa1b99b", upload-time = "2025-09-10T08:49:15.206Z" }, ] [[package]] name = "jinja2" version = "3.1.6" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", upload-time = "2025-03-05T20:05:02.478Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", upload-time = "2025-03-05T20:05:00.369Z" }, ] [[package]] name = "kiwisolver" version = "1.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d0/67/9c61eccb13f0bdca9307614e782fec49ffdde0f7a2314935d489fa93cd9c/kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a", size = 103482, upload-time = "2026-03-09T13:15:53.382Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/b2/818b74ebea34dabe6d0c51cb1c572e046730e64844da6ed646d5298c40ce/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4e9750bc21b886308024f8a54ccb9a2cc38ac9fa813bf4348434e3d54f337ff9", size = 123158, upload-time = "2026-03-09T13:13:23.127Z" }, - { url = "https://files.pythonhosted.org/packages/bf/d9/405320f8077e8e1c5c4bd6adc45e1e6edf6d727b6da7f2e2533cf58bff71/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72ec46b7eba5b395e0a7b63025490d3214c11013f4aacb4f5e8d6c3041829588", size = 66388, upload-time = "2026-03-09T13:13:24.765Z" }, - { url = "https://files.pythonhosted.org/packages/99/9f/795fedf35634f746151ca8839d05681ceb6287fbed6cc1c9bf235f7887c2/kiwisolver-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ed3a984b31da7481b103f68776f7128a89ef26ed40f4dc41a2223cda7fb24819", size = 64068, upload-time = "2026-03-09T13:13:25.878Z" }, - { url = "https://files.pythonhosted.org/packages/c4/13/680c54afe3e65767bed7ec1a15571e1a2f1257128733851ade24abcefbcc/kiwisolver-1.5.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb5136fb5352d3f422df33f0c879a1b0c204004324150cc3b5e3c4f310c9049f", size = 1477934, upload-time = "2026-03-09T13:13:27.166Z" }, - { url = "https://files.pythonhosted.org/packages/c8/2f/cebfcdb60fd6a9b0f6b47a9337198bcbad6fbe15e68189b7011fd914911f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2af221f268f5af85e776a73d62b0845fc8baf8ef0abfae79d29c77d0e776aaf", size = 1278537, upload-time = "2026-03-09T13:13:28.707Z" }, - { url = "https://files.pythonhosted.org/packages/f2/0d/9b782923aada3fafb1d6b84e13121954515c669b18af0c26e7d21f579855/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b0f172dc8ffaccb8522d7c5d899de00133f2f1ca7b0a49b7da98e901de87bf2d", size = 1296685, upload-time = "2026-03-09T13:13:30.528Z" }, - { url = "https://files.pythonhosted.org/packages/27/70/83241b6634b04fe44e892688d5208332bde130f38e610c0418f9ede47ded/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6ab8ba9152203feec73758dad83af9a0bbe05001eb4639e547207c40cfb52083", size = 1346024, upload-time = "2026-03-09T13:13:32.818Z" }, - { url = "https://files.pythonhosted.org/packages/e4/db/30ed226fb271ae1a6431fc0fe0edffb2efe23cadb01e798caeb9f2ceae8f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:cdee07c4d7f6d72008d3f73b9bf027f4e11550224c7c50d8df1ae4a37c1402a6", size = 987241, upload-time = "2026-03-09T13:13:34.435Z" }, - { url = "https://files.pythonhosted.org/packages/ec/bd/c314595208e4c9587652d50959ead9e461995389664e490f4dce7ff0f782/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7c60d3c9b06fb23bd9c6139281ccbdc384297579ae037f08ae90c69f6845c0b1", size = 2227742, upload-time = "2026-03-09T13:13:36.4Z" }, - { url = "https://files.pythonhosted.org/packages/c1/43/0499cec932d935229b5543d073c2b87c9c22846aab48881e9d8d6e742a2d/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e315e5ec90d88e140f57696ff85b484ff68bb311e36f2c414aa4286293e6dee0", size = 2323966, upload-time = "2026-03-09T13:13:38.204Z" }, - { url = "https://files.pythonhosted.org/packages/3d/6f/79b0d760907965acfd9d61826a3d41f8f093c538f55cd2633d3f0db269f6/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:1465387ac63576c3e125e5337a6892b9e99e0627d52317f3ca79e6930d889d15", size = 1977417, upload-time = "2026-03-09T13:13:39.966Z" }, - { url = "https://files.pythonhosted.org/packages/ab/31/01d0537c41cb75a551a438c3c7a80d0c60d60b81f694dac83dd436aec0d0/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:530a3fd64c87cffa844d4b6b9768774763d9caa299e9b75d8eca6a4423b31314", size = 2491238, upload-time = "2026-03-09T13:13:41.698Z" }, - { url = "https://files.pythonhosted.org/packages/e4/34/8aefdd0be9cfd00a44509251ba864f5caf2991e36772e61c408007e7f417/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1d9daea4ea6b9be74fe2f01f7fbade8d6ffab263e781274cffca0dba9be9eec9", size = 2294947, upload-time = "2026-03-09T13:13:43.343Z" }, - { url = "https://files.pythonhosted.org/packages/ad/cf/0348374369ca588f8fe9c338fae49fa4e16eeb10ffb3d012f23a54578a9e/kiwisolver-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:f18c2d9782259a6dc132fdc7a63c168cbc74b35284b6d75c673958982a378384", size = 73569, upload-time = "2026-03-09T13:13:45.792Z" }, - { url = "https://files.pythonhosted.org/packages/28/26/192b26196e2316e2bd29deef67e37cdf9870d9af8e085e521afff0fed526/kiwisolver-1.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:f7c7553b13f69c1b29a5bde08ddc6d9d0c8bfb84f9ed01c30db25944aeb852a7", size = 64997, upload-time = "2026-03-09T13:13:46.878Z" }, - { url = "https://files.pythonhosted.org/packages/1c/fa/2910df836372d8761bb6eff7d8bdcb1613b5c2e03f260efe7abe34d388a7/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_10_13_x86_64.whl", hash = "sha256:5ae8e62c147495b01a0f4765c878e9bfdf843412446a247e28df59936e99e797", size = 130262, upload-time = "2026-03-09T13:15:35.629Z" }, - { url = "https://files.pythonhosted.org/packages/0f/41/c5f71f9f00aabcc71fee8b7475e3f64747282580c2fe748961ba29b18385/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f6764a4ccab3078db14a632420930f6186058750df066b8ea2a7106df91d3203", size = 138036, upload-time = "2026-03-09T13:15:36.894Z" }, - { url = "https://files.pythonhosted.org/packages/fa/06/7399a607f434119c6e1fdc8ec89a8d51ccccadf3341dee4ead6bd14caaf5/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c31c13da98624f957b0fb1b5bae5383b2333c2c3f6793d9825dd5ce79b525cb7", size = 194295, upload-time = "2026-03-09T13:15:38.22Z" }, - { url = "https://files.pythonhosted.org/packages/b5/91/53255615acd2a1eaca307ede3c90eb550bae9c94581f8c00081b6b1c8f44/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-win_amd64.whl", hash = "sha256:1f1489f769582498610e015a8ef2d36f28f505ab3096d0e16b4858a9ec214f57", size = 75987, upload-time = "2026-03-09T13:15:39.65Z" }, +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/d0/67/9c61eccb13f0bdca9307614e782fec49ffdde0f7a2314935d489fa93cd9c/kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a", upload-time = "2026-03-09T13:15:53.382Z" } +wheels = [ + { url = "https://pypi-proxy.cloud.databricks.com/packages/4d/b2/818b74ebea34dabe6d0c51cb1c572e046730e64844da6ed646d5298c40ce/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4e9750bc21b886308024f8a54ccb9a2cc38ac9fa813bf4348434e3d54f337ff9", upload-time = "2026-03-09T13:13:23.127Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/bf/d9/405320f8077e8e1c5c4bd6adc45e1e6edf6d727b6da7f2e2533cf58bff71/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72ec46b7eba5b395e0a7b63025490d3214c11013f4aacb4f5e8d6c3041829588", upload-time = "2026-03-09T13:13:24.765Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/99/9f/795fedf35634f746151ca8839d05681ceb6287fbed6cc1c9bf235f7887c2/kiwisolver-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ed3a984b31da7481b103f68776f7128a89ef26ed40f4dc41a2223cda7fb24819", upload-time = "2026-03-09T13:13:25.878Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/c4/13/680c54afe3e65767bed7ec1a15571e1a2f1257128733851ade24abcefbcc/kiwisolver-1.5.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb5136fb5352d3f422df33f0c879a1b0c204004324150cc3b5e3c4f310c9049f", upload-time = "2026-03-09T13:13:27.166Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/c8/2f/cebfcdb60fd6a9b0f6b47a9337198bcbad6fbe15e68189b7011fd914911f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2af221f268f5af85e776a73d62b0845fc8baf8ef0abfae79d29c77d0e776aaf", upload-time = "2026-03-09T13:13:28.707Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/f2/0d/9b782923aada3fafb1d6b84e13121954515c669b18af0c26e7d21f579855/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b0f172dc8ffaccb8522d7c5d899de00133f2f1ca7b0a49b7da98e901de87bf2d", upload-time = "2026-03-09T13:13:30.528Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/27/70/83241b6634b04fe44e892688d5208332bde130f38e610c0418f9ede47ded/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6ab8ba9152203feec73758dad83af9a0bbe05001eb4639e547207c40cfb52083", upload-time = "2026-03-09T13:13:32.818Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/e4/db/30ed226fb271ae1a6431fc0fe0edffb2efe23cadb01e798caeb9f2ceae8f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:cdee07c4d7f6d72008d3f73b9bf027f4e11550224c7c50d8df1ae4a37c1402a6", upload-time = "2026-03-09T13:13:34.435Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/ec/bd/c314595208e4c9587652d50959ead9e461995389664e490f4dce7ff0f782/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7c60d3c9b06fb23bd9c6139281ccbdc384297579ae037f08ae90c69f6845c0b1", upload-time = "2026-03-09T13:13:36.4Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/c1/43/0499cec932d935229b5543d073c2b87c9c22846aab48881e9d8d6e742a2d/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e315e5ec90d88e140f57696ff85b484ff68bb311e36f2c414aa4286293e6dee0", upload-time = "2026-03-09T13:13:38.204Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/3d/6f/79b0d760907965acfd9d61826a3d41f8f093c538f55cd2633d3f0db269f6/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:1465387ac63576c3e125e5337a6892b9e99e0627d52317f3ca79e6930d889d15", upload-time = "2026-03-09T13:13:39.966Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/ab/31/01d0537c41cb75a551a438c3c7a80d0c60d60b81f694dac83dd436aec0d0/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:530a3fd64c87cffa844d4b6b9768774763d9caa299e9b75d8eca6a4423b31314", upload-time = "2026-03-09T13:13:41.698Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/e4/34/8aefdd0be9cfd00a44509251ba864f5caf2991e36772e61c408007e7f417/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1d9daea4ea6b9be74fe2f01f7fbade8d6ffab263e781274cffca0dba9be9eec9", upload-time = "2026-03-09T13:13:43.343Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/ad/cf/0348374369ca588f8fe9c338fae49fa4e16eeb10ffb3d012f23a54578a9e/kiwisolver-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:f18c2d9782259a6dc132fdc7a63c168cbc74b35284b6d75c673958982a378384", upload-time = "2026-03-09T13:13:45.792Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/28/26/192b26196e2316e2bd29deef67e37cdf9870d9af8e085e521afff0fed526/kiwisolver-1.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:f7c7553b13f69c1b29a5bde08ddc6d9d0c8bfb84f9ed01c30db25944aeb852a7", upload-time = "2026-03-09T13:13:46.878Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/1c/fa/2910df836372d8761bb6eff7d8bdcb1613b5c2e03f260efe7abe34d388a7/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_10_13_x86_64.whl", hash = "sha256:5ae8e62c147495b01a0f4765c878e9bfdf843412446a247e28df59936e99e797", upload-time = "2026-03-09T13:15:35.629Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/0f/41/c5f71f9f00aabcc71fee8b7475e3f64747282580c2fe748961ba29b18385/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f6764a4ccab3078db14a632420930f6186058750df066b8ea2a7106df91d3203", upload-time = "2026-03-09T13:15:36.894Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/fa/06/7399a607f434119c6e1fdc8ec89a8d51ccccadf3341dee4ead6bd14caaf5/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c31c13da98624f957b0fb1b5bae5383b2333c2c3f6793d9825dd5ce79b525cb7", upload-time = "2026-03-09T13:15:38.22Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/b5/91/53255615acd2a1eaca307ede3c90eb550bae9c94581f8c00081b6b1c8f44/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-win_amd64.whl", hash = "sha256:1f1489f769582498610e015a8ef2d36f28f505ab3096d0e16b4858a9ec214f57", upload-time = "2026-03-09T13:15:39.65Z" }, +] + +[[package]] +name = "lxml" +version = "6.1.1" +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/05/3b/aab6728cae887456f409b4d75e8a01856e4f04bd510de38052a47768b680/lxml-6.1.1.tar.gz", hash = "sha256:ba96ae44888e0185281e937633a743ea90d5a196c6000f82565ebb0580012d40", upload-time = "2026-05-18T19:19:06.424Z" } +wheels = [ + { url = "https://pypi-proxy.cloud.databricks.com/packages/6a/6e/c4add832b6fc1e887125b96f880d7b9b70aae5248718e046b1704bcac4b9/lxml-6.1.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:104c09bda8d2a562824c0e319d0768ce26a779b7601e0931d33b09b53c392ef7", upload-time = "2026-05-18T19:17:42.068Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/22/00/ff3009c88e65de8011630acf8ab5a09cb2becd2aaf47fba2f3449f6224e9/lxml-6.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:25c6997a9a534e016695a0ba06b2f07945de682731ff01065b6d5a4474179da1", upload-time = "2026-05-18T19:17:47.897Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/42/95/bb63f0fd62e554fe078e1fb3c8fe9083c14ddc7ad7fa178d10e57e071ac7/lxml-6.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c921ba5c51e4e9f63b8b00267d06566e1f63407408a0496da2d1d0bfc819c7fc", upload-time = "2026-05-18T19:18:29.637Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/eb/99/0013e8d9b5960f4f041cf0b73e2f80c23eb5205b1f7bfb20203243651359/lxml-6.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:54a7f95e4de5fb94e2f9f4b9055c6ba33bf3d628fd77a1d647c5923caa2cdcdc", upload-time = "2026-05-18T19:18:34.168Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/29/91/317b332636bfc7bddcff828d41b3307f50043f4b237e40849c333d80fa1a/lxml-6.1.1-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f2ec43df44b1f76249ee0a615334f9b5b060e1c8bd90e706dad2d14d02f383", upload-time = "2026-05-18T19:18:39.798Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/42/2f/cc9bf06afe70f9c9093ae60855d9759da9db601ec4080f7473319666ffd7/lxml-6.1.1-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:70ef8a7e102a1508f8121aae5b0867abd663f72c14f0a9c937e6554cb4587b7b", upload-time = "2026-05-18T19:18:44.858Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/08/f6/af32e23e563971ffb0fb86be52bc5be5c2c118858ffc119bf6a9039b173d/lxml-6.1.1-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ebe6af670449830d6d9b752c256a983291c766a1365ba5d5460048f9e33a7818", upload-time = "2026-05-18T19:18:49.217Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/78/83/8555d40948b09ce86f1bd0c68a7ac31d07b1929f92cc1b074006c97ef2d2/lxml-6.1.1-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:27acc820660aaffa4f7c087f29120e12980f7779d56d8492d263170111284740", upload-time = "2026-05-18T19:18:52.779Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/63/75/5d92da93729b7bad783689e6496049fa40927b45bec7bf183c981de3ca70/lxml-6.1.1-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:1db753c9115ec7100d073b744d17e25e88a8f90f5c39b2f5dd878149af59671f", upload-time = "2026-05-18T19:18:55.139Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/c5/b5/3aad415a9a25b822e783f15deeb4dffccf5113030f1afa2222dd929313d9/lxml-6.1.1-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c4f469aebd783bb741c2ecb2a681008fd26bfe5c16a9a72ed5467f834e810df2", upload-time = "2026-05-18T19:19:01.28Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/f1/a1/5fcf7eb9904b80086aa47dcf0027de07b1bb990afad2e6823144c368ae04/lxml-6.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:766b010012d59470072c1816b5b6c69f1d243e5db36ea5968e94accf430a4635", upload-time = "2026-05-18T19:18:12.67Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/77/74/1f601b63c7a69fcdf10fa9b148c81da8442204194f6c55509cc485c786b9/lxml-6.1.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b8d812c6011c08b8111a15e54dd990b8923692d80adf35488bee34026c35accf", upload-time = "2026-05-18T19:18:15.928Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/a2/b9/7a78f51aec95b1bf780d78e12705a9f6533284f8693dc5c0e6724fa53d3f/lxml-6.1.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:fe0306bd29505a9177aac19f1877174b0e7422c222a59f70b2cd41633448c3dc", upload-time = "2026-05-18T19:18:23.223Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/a5/6e/98a7b7ad54e4e74fa1f20fff776913980619d0ebe5558232d7da6580bdd8/lxml-6.1.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:5ba186ad207446c65d3bb3d3e0412b032b1d9f595e59861e2354798c5703d955", upload-time = "2026-05-18T19:18:31.433Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/65/d1/bc0ed2427bf609f2ee10da303a6a226f9c8bce94f945dc29a32ce55de6e4/lxml-6.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aa366a1e55b8ebfe8ca8ddc3cfe75c8ebade181aeb0f661d0cb05986b647f72a", upload-time = "2026-05-18T19:18:37.091Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/69/8b/6772e1a4b513fc50a8d931f19edde0e13ae6918510a1e13ff67864f3e5ed/lxml-6.1.1-cp312-cp312-win32.whl", hash = "sha256:126c93f7f56f0eda92f6d8c619edc463a4f23d9252f1c9d0405a76f25fa9f11a", upload-time = "2026-05-18T19:17:18.37Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/1b/89/45198e9624762af2dfd2cb8782598477ceb29f6e59caab560388ae1f4ec1/lxml-6.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:26e6eda8d38c1fcab1090dd196ee87cbd13788e531937610e2589085de074e77", upload-time = "2026-05-18T19:17:56.781Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/90/a9/7a54b6834088d9ae528a7b780584ba6a39a9457b0ac330479f20ffbc9449/lxml-6.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:6540377fbd53fe1b629172288c464fb18db11ce1fa7dc15891da10aa9dcc3e7f", upload-time = "2026-05-19T19:22:50.843Z" }, ] [[package]] name = "lz4" version = "4.4.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/57/51/f1b86d93029f418033dddf9b9f79c8d2641e7454080478ee2aab5123173e/lz4-4.4.5.tar.gz", hash = "sha256:5f0b9e53c1e82e88c10d7c180069363980136b9d7a8306c4dca4f760d60c39f0", size = 172886, upload-time = "2025-11-03T13:02:36.061Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/57/51/f1b86d93029f418033dddf9b9f79c8d2641e7454080478ee2aab5123173e/lz4-4.4.5.tar.gz", hash = "sha256:5f0b9e53c1e82e88c10d7c180069363980136b9d7a8306c4dca4f760d60c39f0", upload-time = "2025-11-03T13:02:36.061Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1b/ac/016e4f6de37d806f7cc8f13add0a46c9a7cfc41a5ddc2bc831d7954cf1ce/lz4-4.4.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:df5aa4cead2044bab83e0ebae56e0944cc7fcc1505c7787e9e1057d6d549897e", size = 207163, upload-time = "2025-11-03T13:01:45.895Z" }, - { url = "https://files.pythonhosted.org/packages/8d/df/0fadac6e5bd31b6f34a1a8dbd4db6a7606e70715387c27368586455b7fc9/lz4-4.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d0bf51e7745484d2092b3a51ae6eb58c3bd3ce0300cf2b2c14f76c536d5697a", size = 207150, upload-time = "2025-11-03T13:01:47.205Z" }, - { url = "https://files.pythonhosted.org/packages/b7/17/34e36cc49bb16ca73fb57fbd4c5eaa61760c6b64bce91fcb4e0f4a97f852/lz4-4.4.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7b62f94b523c251cf32aa4ab555f14d39bd1a9df385b72443fd76d7c7fb051f5", size = 1292045, upload-time = "2025-11-03T13:01:48.667Z" }, - { url = "https://files.pythonhosted.org/packages/90/1c/b1d8e3741e9fc89ed3b5f7ef5f22586c07ed6bb04e8343c2e98f0fa7ff04/lz4-4.4.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c3ea562c3af274264444819ae9b14dbbf1ab070aff214a05e97db6896c7597e", size = 1279546, upload-time = "2025-11-03T13:01:50.159Z" }, - { url = "https://files.pythonhosted.org/packages/55/d9/e3867222474f6c1b76e89f3bd914595af69f55bf2c1866e984c548afdc15/lz4-4.4.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24092635f47538b392c4eaeff14c7270d2c8e806bf4be2a6446a378591c5e69e", size = 1368249, upload-time = "2025-11-03T13:01:51.273Z" }, - { url = "https://files.pythonhosted.org/packages/b2/e7/d667d337367686311c38b580d1ca3d5a23a6617e129f26becd4f5dc458df/lz4-4.4.5-cp312-cp312-win32.whl", hash = "sha256:214e37cfe270948ea7eb777229e211c601a3e0875541c1035ab408fbceaddf50", size = 88189, upload-time = "2025-11-03T13:01:52.605Z" }, - { url = "https://files.pythonhosted.org/packages/a5/0b/a54cd7406995ab097fceb907c7eb13a6ddd49e0b231e448f1a81a50af65c/lz4-4.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:713a777de88a73425cf08eb11f742cd2c98628e79a8673d6a52e3c5f0c116f33", size = 99497, upload-time = "2025-11-03T13:01:53.477Z" }, - { url = "https://files.pythonhosted.org/packages/6a/7e/dc28a952e4bfa32ca16fa2eb026e7a6ce5d1411fcd5986cd08c74ec187b9/lz4-4.4.5-cp312-cp312-win_arm64.whl", hash = "sha256:a88cbb729cc333334ccfb52f070463c21560fca63afcf636a9f160a55fac3301", size = 91279, upload-time = "2025-11-03T13:01:54.419Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/1b/ac/016e4f6de37d806f7cc8f13add0a46c9a7cfc41a5ddc2bc831d7954cf1ce/lz4-4.4.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:df5aa4cead2044bab83e0ebae56e0944cc7fcc1505c7787e9e1057d6d549897e", upload-time = "2025-11-03T13:01:45.895Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/8d/df/0fadac6e5bd31b6f34a1a8dbd4db6a7606e70715387c27368586455b7fc9/lz4-4.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d0bf51e7745484d2092b3a51ae6eb58c3bd3ce0300cf2b2c14f76c536d5697a", upload-time = "2025-11-03T13:01:47.205Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/b7/17/34e36cc49bb16ca73fb57fbd4c5eaa61760c6b64bce91fcb4e0f4a97f852/lz4-4.4.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7b62f94b523c251cf32aa4ab555f14d39bd1a9df385b72443fd76d7c7fb051f5", upload-time = "2025-11-03T13:01:48.667Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/90/1c/b1d8e3741e9fc89ed3b5f7ef5f22586c07ed6bb04e8343c2e98f0fa7ff04/lz4-4.4.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c3ea562c3af274264444819ae9b14dbbf1ab070aff214a05e97db6896c7597e", upload-time = "2025-11-03T13:01:50.159Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/55/d9/e3867222474f6c1b76e89f3bd914595af69f55bf2c1866e984c548afdc15/lz4-4.4.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24092635f47538b392c4eaeff14c7270d2c8e806bf4be2a6446a378591c5e69e", upload-time = "2025-11-03T13:01:51.273Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/b2/e7/d667d337367686311c38b580d1ca3d5a23a6617e129f26becd4f5dc458df/lz4-4.4.5-cp312-cp312-win32.whl", hash = "sha256:214e37cfe270948ea7eb777229e211c601a3e0875541c1035ab408fbceaddf50", upload-time = "2025-11-03T13:01:52.605Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/a5/0b/a54cd7406995ab097fceb907c7eb13a6ddd49e0b231e448f1a81a50af65c/lz4-4.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:713a777de88a73425cf08eb11f742cd2c98628e79a8673d6a52e3c5f0c116f33", upload-time = "2025-11-03T13:01:53.477Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/6a/7e/dc28a952e4bfa32ca16fa2eb026e7a6ce5d1411fcd5986cd08c74ec187b9/lz4-4.4.5-cp312-cp312-win_arm64.whl", hash = "sha256:a88cbb729cc333334ccfb52f070463c21560fca63afcf636a9f160a55fac3301", upload-time = "2025-11-03T13:01:54.419Z" }, ] [[package]] name = "markupsafe" version = "3.0.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", upload-time = "2025-09-27T18:37:40.426Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, - { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, - { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, - { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, - { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, - { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, - { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, - { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, - { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, - { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, - { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", upload-time = "2025-09-27T18:36:40.689Z" }, ] [[package]] name = "matplotlib" version = "3.10.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "contourpy" }, { name = "cycler" }, @@ -564,173 +655,192 @@ dependencies = [ { name = "pyparsing" }, { name = "python-dateutil" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/68/dd/fa2e1a45fce2d09f4aea3cee169760e672c8262325aa5796c49d543dc7e6/matplotlib-3.10.0.tar.gz", hash = "sha256:b886d02a581b96704c9d1ffe55709e49b4d2d52709ccebc4be42db856e511278", size = 36686418, upload-time = "2024-12-14T06:32:51.547Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/68/dd/fa2e1a45fce2d09f4aea3cee169760e672c8262325aa5796c49d543dc7e6/matplotlib-3.10.0.tar.gz", hash = "sha256:b886d02a581b96704c9d1ffe55709e49b4d2d52709ccebc4be42db856e511278", upload-time = "2024-12-14T06:32:51.547Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/44/c7/6b2d8cb7cc251d53c976799cacd3200add56351c175ba89ab9cbd7c1e68a/matplotlib-3.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4659665bc7c9b58f8c00317c3c2a299f7f258eeae5a5d56b4c64226fca2f7c59", size = 8172465, upload-time = "2024-12-14T06:31:24.727Z" }, - { url = "https://files.pythonhosted.org/packages/42/2a/6d66d0fba41e13e9ca6512a0a51170f43e7e7ed3a8dfa036324100775612/matplotlib-3.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d44cb942af1693cced2604c33a9abcef6205601c445f6d0dc531d813af8a2f5a", size = 8043300, upload-time = "2024-12-14T06:31:28.55Z" }, - { url = "https://files.pythonhosted.org/packages/90/60/2a60342b27b90a16bada939a85e29589902b41073f59668b904b15ea666c/matplotlib-3.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a994f29e968ca002b50982b27168addfd65f0105610b6be7fa515ca4b5307c95", size = 8448936, upload-time = "2024-12-14T06:31:32.223Z" }, - { url = "https://files.pythonhosted.org/packages/a7/b2/d872fc3d753516870d520595ddd8ce4dd44fa797a240999f125f58521ad7/matplotlib-3.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b0558bae37f154fffda54d779a592bc97ca8b4701f1c710055b609a3bac44c8", size = 8594151, upload-time = "2024-12-14T06:31:34.894Z" }, - { url = "https://files.pythonhosted.org/packages/f4/bd/b2f60cf7f57d014ab33e4f74602a2b5bdc657976db8196bbc022185f6f9c/matplotlib-3.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:503feb23bd8c8acc75541548a1d709c059b7184cde26314896e10a9f14df5f12", size = 9400347, upload-time = "2024-12-14T06:31:39.552Z" }, - { url = "https://files.pythonhosted.org/packages/9f/6e/264673e64001b99d747aff5a288eca82826c024437a3694e19aed1decf46/matplotlib-3.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:c40ba2eb08b3f5de88152c2333c58cee7edcead0a2a0d60fcafa116b17117adc", size = 8039144, upload-time = "2024-12-14T06:31:44.128Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/44/c7/6b2d8cb7cc251d53c976799cacd3200add56351c175ba89ab9cbd7c1e68a/matplotlib-3.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4659665bc7c9b58f8c00317c3c2a299f7f258eeae5a5d56b4c64226fca2f7c59", upload-time = "2024-12-14T06:31:24.727Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/42/2a/6d66d0fba41e13e9ca6512a0a51170f43e7e7ed3a8dfa036324100775612/matplotlib-3.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d44cb942af1693cced2604c33a9abcef6205601c445f6d0dc531d813af8a2f5a", upload-time = "2024-12-14T06:31:28.55Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/90/60/2a60342b27b90a16bada939a85e29589902b41073f59668b904b15ea666c/matplotlib-3.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a994f29e968ca002b50982b27168addfd65f0105610b6be7fa515ca4b5307c95", upload-time = "2024-12-14T06:31:32.223Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/a7/b2/d872fc3d753516870d520595ddd8ce4dd44fa797a240999f125f58521ad7/matplotlib-3.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b0558bae37f154fffda54d779a592bc97ca8b4701f1c710055b609a3bac44c8", upload-time = "2024-12-14T06:31:34.894Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/f4/bd/b2f60cf7f57d014ab33e4f74602a2b5bdc657976db8196bbc022185f6f9c/matplotlib-3.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:503feb23bd8c8acc75541548a1d709c059b7184cde26314896e10a9f14df5f12", upload-time = "2024-12-14T06:31:39.552Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/9f/6e/264673e64001b99d747aff5a288eca82826c024437a3694e19aed1decf46/matplotlib-3.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:c40ba2eb08b3f5de88152c2333c58cee7edcead0a2a0d60fcafa116b17117adc", upload-time = "2024-12-14T06:31:44.128Z" }, ] [[package]] name = "mypy-extensions" version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", upload-time = "2025-04-22T14:54:24.164Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", upload-time = "2025-04-22T14:54:22.983Z" }, ] [[package]] name = "nodeenv" version = "1.10.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", upload-time = "2025-12-20T14:08:54.006Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", upload-time = "2025-12-20T14:08:52.782Z" }, ] [[package]] name = "nptyping" version = "2.5.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e1/b7/ffe533358c32506b1708feec0fb04ba0a35a959a94163fff5333671909da/nptyping-2.5.0.tar.gz", hash = "sha256:e3d35b53af967e6fb407c3016ff9abae954d3a0568f7cc13a461084224e8e20a", size = 71623, upload-time = "2023-02-20T21:57:11.814Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/e1/b7/ffe533358c32506b1708feec0fb04ba0a35a959a94163fff5333671909da/nptyping-2.5.0.tar.gz", hash = "sha256:e3d35b53af967e6fb407c3016ff9abae954d3a0568f7cc13a461084224e8e20a", upload-time = "2023-02-20T21:57:11.814Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/28/92edc05378175de13a3d4986cee7531853634a22b7e5e21a988fa84fde3f/nptyping-2.5.0-py3-none-any.whl", hash = "sha256:764e51836faae33a7ae2e928af574cfb701355647accadcc89f2ad793630b7c8", size = 37602, upload-time = "2023-02-20T21:57:09.61Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/b1/28/92edc05378175de13a3d4986cee7531853634a22b7e5e21a988fa84fde3f/nptyping-2.5.0-py3-none-any.whl", hash = "sha256:764e51836faae33a7ae2e928af574cfb701355647accadcc89f2ad793630b7c8", upload-time = "2023-02-20T21:57:09.61Z" }, ] [[package]] name = "nr-date" version = "2.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a0/92/08110dd3d7ff5e2b852a220752eb6c40183839f5b7cc91f9f38dd2298e7d/nr_date-2.1.0.tar.gz", hash = "sha256:0643aea13bcdc2a8bc56af9d5e6a89ef244c9744a1ef00cdc735902ba7f7d2e6", size = 8789, upload-time = "2023-08-16T13:46:04.114Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/a0/92/08110dd3d7ff5e2b852a220752eb6c40183839f5b7cc91f9f38dd2298e7d/nr_date-2.1.0.tar.gz", hash = "sha256:0643aea13bcdc2a8bc56af9d5e6a89ef244c9744a1ef00cdc735902ba7f7d2e6", upload-time = "2023-08-16T13:46:04.114Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/10/1d2b00172537c1522fe64bbc6fb16b015632a02f7b3864e788ccbcb4dd85/nr_date-2.1.0-py3-none-any.whl", hash = "sha256:bd672a9dfbdcf7c4b9289fea6750c42490eaee08036a72059dcc78cb236ed568", size = 10496, upload-time = "2023-08-16T13:46:02.627Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/f9/10/1d2b00172537c1522fe64bbc6fb16b015632a02f7b3864e788ccbcb4dd85/nr_date-2.1.0-py3-none-any.whl", hash = "sha256:bd672a9dfbdcf7c4b9289fea6750c42490eaee08036a72059dcc78cb236ed568", upload-time = "2023-08-16T13:46:02.627Z" }, ] [[package]] name = "nr-stream" version = "1.1.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b7/37/e4d36d852c441233c306c5fbd98147685dce3ac9b0a8bbf4a587d0ea29ea/nr_stream-1.1.5.tar.gz", hash = "sha256:eb0216c6bfc61a46d4568dba3b588502c610ec8ddef4ac98f3932a2bd7264f65", size = 10053, upload-time = "2023-02-14T22:44:09.074Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/b7/37/e4d36d852c441233c306c5fbd98147685dce3ac9b0a8bbf4a587d0ea29ea/nr_stream-1.1.5.tar.gz", hash = "sha256:eb0216c6bfc61a46d4568dba3b588502c610ec8ddef4ac98f3932a2bd7264f65", upload-time = "2023-02-14T22:44:09.074Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/e1/f93485fe09aa36c0e1a3b76363efa1791241f7f863a010f725c95e8a74fe/nr_stream-1.1.5-py3-none-any.whl", hash = "sha256:47e12150b331ad2cb729cfd9d2abd281c9949809729ba461c6aa87dd9927b2d4", size = 10448, upload-time = "2023-02-14T22:44:07.72Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/1d/e1/f93485fe09aa36c0e1a3b76363efa1791241f7f863a010f725c95e8a74fe/nr_stream-1.1.5-py3-none-any.whl", hash = "sha256:47e12150b331ad2cb729cfd9d2abd281c9949809729ba461c6aa87dd9927b2d4", upload-time = "2023-02-14T22:44:07.72Z" }, ] [[package]] name = "nr-util" version = "0.8.12" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "deprecated" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/20/0c/078c567d95e25564bc1ede3c2cf6ce1c91f50648c83786354b47224326da/nr.util-0.8.12.tar.gz", hash = "sha256:a4549c2033d99d2f0379b3f3d233fd2a8ade286bbf0b3ad0cc7cea16022214f4", size = 63707, upload-time = "2022-06-20T13:29:29.192Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/20/0c/078c567d95e25564bc1ede3c2cf6ce1c91f50648c83786354b47224326da/nr.util-0.8.12.tar.gz", hash = "sha256:a4549c2033d99d2f0379b3f3d233fd2a8ade286bbf0b3ad0cc7cea16022214f4", upload-time = "2022-06-20T13:29:29.192Z" } +wheels = [ + { url = "https://pypi-proxy.cloud.databricks.com/packages/ba/58/eab08df9dbd69d9e21fc5e7be6f67454f386336ec71e6b64e378a2dddea4/nr.util-0.8.12-py3-none-any.whl", hash = "sha256:91da02ac9795eb8e015372275c1efe54bac9051231ee9b0e7e6f96b0b4e7d2bb", upload-time = "2022-06-20T13:29:27.312Z" }, +] + +[[package]] +name = "numexpr" +version = "2.14.1" +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/cb/2f/fdba158c9dbe5caca9c3eca3eaffffb251f2fb8674bf8e2d0aed5f38d319/numexpr-2.14.1.tar.gz", hash = "sha256:4be00b1086c7b7a5c32e31558122b7b80243fe098579b170967da83f3152b48b", upload-time = "2025-10-13T16:17:27.351Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/58/eab08df9dbd69d9e21fc5e7be6f67454f386336ec71e6b64e378a2dddea4/nr.util-0.8.12-py3-none-any.whl", hash = "sha256:91da02ac9795eb8e015372275c1efe54bac9051231ee9b0e7e6f96b0b4e7d2bb", size = 90319, upload-time = "2022-06-20T13:29:27.312Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/9d/20/c473fc04a371f5e2f8c5749e04505c13e7a8ede27c09e9f099b2ad6f43d6/numexpr-2.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ebae0ab18c799b0e6b8c5a8d11e1fa3848eb4011271d99848b297468a39430", upload-time = "2025-10-13T16:16:34.903Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/45/93/b6760dd1904c2a498e5f43d1bb436f59383c3ddea3815f1461dfaa259373/numexpr-2.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:47041f2f7b9e69498fb311af672ba914a60e6e6d804011caacb17d66f639e659", upload-time = "2025-10-13T16:16:36.593Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/72/94/cc921e35593b820521e464cbbeaf8212bbdb07f16dc79fe283168df38195/numexpr-2.14.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d686dfb2c1382d9e6e0ee0b7647f943c1886dba3adbf606c625479f35f1956c1", upload-time = "2025-10-13T16:13:29.531Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/d9/43/560e9ba23c02c904b5934496486d061bcb14cd3ebba2e3cf0e2dccb6c22b/numexpr-2.14.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eee6d4fbbbc368e6cdd0772734d6249128d957b3b8ad47a100789009f4de7083", upload-time = "2025-10-13T16:15:02.473Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/7b/6c/78f83b6219f61c2c22d71ab6e6c2d4e5d7381334c6c29b77204e59edb039/numexpr-2.14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3a2839efa25f3c8d4133252ea7342d8f81226c7c4dda81f97a57e090b9d87a48", upload-time = "2025-10-13T16:13:33.464Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/0e/bb/1ccc9dcaf46281568ce769888bf16294c40e98a5158e4b16c241de31d0d3/numexpr-2.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9f9137f1351b310436662b5dc6f4082a245efa8950c3b0d9008028df92fefb9b", upload-time = "2025-10-13T16:15:12.828Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/31/9f/203d82b9e39dadd91d64bca55b3c8ca432e981b822468dcef41a4418626b/numexpr-2.14.1-cp312-cp312-win32.whl", hash = "sha256:36f8d5c1bd1355df93b43d766790f9046cccfc1e32b7c6163f75bcde682cda07", upload-time = "2025-10-13T16:17:10.369Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/1f/67/ffe750b5452eb66de788c34e7d21ec6d886abb4d7c43ad1dc88ceb3d998f/numexpr-2.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:fdd886f4b7dbaf167633ee396478f0d0aa58ea2f9e7ccc3c6431019623e8d68f", upload-time = "2025-10-13T16:17:11.974Z" }, ] [[package]] name = "numpy" version = "1.26.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", upload-time = "2024-02-06T00:26:44.495Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/95/12/8f2020a8e8b8383ac0177dc9570aad031a3beb12e38847f7129bacd96228/numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218", size = 20335901, upload-time = "2024-02-05T23:55:32.801Z" }, - { url = "https://files.pythonhosted.org/packages/75/5b/ca6c8bd14007e5ca171c7c03102d17b4f4e0ceb53957e8c44343a9546dcc/numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b", size = 13685868, upload-time = "2024-02-05T23:55:56.28Z" }, - { url = "https://files.pythonhosted.org/packages/79/f8/97f10e6755e2a7d027ca783f63044d5b1bc1ae7acb12afe6a9b4286eac17/numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b", size = 13925109, upload-time = "2024-02-05T23:56:20.368Z" }, - { url = "https://files.pythonhosted.org/packages/0f/50/de23fde84e45f5c4fda2488c759b69990fd4512387a8632860f3ac9cd225/numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed", size = 17950613, upload-time = "2024-02-05T23:56:56.054Z" }, - { url = "https://files.pythonhosted.org/packages/4c/0c/9c603826b6465e82591e05ca230dfc13376da512b25ccd0894709b054ed0/numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a", size = 13572172, upload-time = "2024-02-05T23:57:21.56Z" }, - { url = "https://files.pythonhosted.org/packages/76/8c/2ba3902e1a0fc1c74962ea9bb33a534bb05984ad7ff9515bf8d07527cadd/numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0", size = 17786643, upload-time = "2024-02-05T23:57:56.585Z" }, - { url = "https://files.pythonhosted.org/packages/28/4a/46d9e65106879492374999e76eb85f87b15328e06bd1550668f79f7b18c6/numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110", size = 5677803, upload-time = "2024-02-05T23:58:08.963Z" }, - { url = "https://files.pythonhosted.org/packages/16/2e/86f24451c2d530c88daf997cb8d6ac622c1d40d19f5a031ed68a4b73a374/numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818", size = 15517754, upload-time = "2024-02-05T23:58:36.364Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/95/12/8f2020a8e8b8383ac0177dc9570aad031a3beb12e38847f7129bacd96228/numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218", upload-time = "2024-02-05T23:55:32.801Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/75/5b/ca6c8bd14007e5ca171c7c03102d17b4f4e0ceb53957e8c44343a9546dcc/numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b", upload-time = "2024-02-05T23:55:56.28Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/79/f8/97f10e6755e2a7d027ca783f63044d5b1bc1ae7acb12afe6a9b4286eac17/numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b", upload-time = "2024-02-05T23:56:20.368Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/0f/50/de23fde84e45f5c4fda2488c759b69990fd4512387a8632860f3ac9cd225/numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed", upload-time = "2024-02-05T23:56:56.054Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/4c/0c/9c603826b6465e82591e05ca230dfc13376da512b25ccd0894709b054ed0/numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a", upload-time = "2024-02-05T23:57:21.56Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/76/8c/2ba3902e1a0fc1c74962ea9bb33a534bb05984ad7ff9515bf8d07527cadd/numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0", upload-time = "2024-02-05T23:57:56.585Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/28/4a/46d9e65106879492374999e76eb85f87b15328e06bd1550668f79f7b18c6/numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110", upload-time = "2024-02-05T23:58:08.963Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/16/2e/86f24451c2d530c88daf997cb8d6ac622c1d40d19f5a031ed68a4b73a374/numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818", upload-time = "2024-02-05T23:58:36.364Z" }, ] [[package]] name = "packaging" version = "26.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", upload-time = "2026-04-24T20:15:23.917Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", upload-time = "2026-04-24T20:15:22.081Z" }, ] [[package]] name = "pandas" version = "2.2.3" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "numpy" }, { name = "python-dateutil" }, { name = "pytz" }, { name = "tzdata" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9c/d6/9f8431bacc2e19dca897724cd097b1bb224a6ad5433784a44b587c7c13af/pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667", size = 4399213, upload-time = "2024-09-20T13:10:04.827Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/9c/d6/9f8431bacc2e19dca897724cd097b1bb224a6ad5433784a44b587c7c13af/pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667", upload-time = "2024-09-20T13:10:04.827Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/17/a3/fb2734118db0af37ea7433f57f722c0a56687e14b14690edff0cdb4b7e58/pandas-2.2.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9", size = 12529893, upload-time = "2024-09-20T13:09:09.655Z" }, - { url = "https://files.pythonhosted.org/packages/e1/0c/ad295fd74bfac85358fd579e271cded3ac969de81f62dd0142c426b9da91/pandas-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4", size = 11363475, upload-time = "2024-09-20T13:09:14.718Z" }, - { url = "https://files.pythonhosted.org/packages/c6/2a/4bba3f03f7d07207481fed47f5b35f556c7441acddc368ec43d6643c5777/pandas-2.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3", size = 15188645, upload-time = "2024-09-20T19:02:03.88Z" }, - { url = "https://files.pythonhosted.org/packages/38/f8/d8fddee9ed0d0c0f4a2132c1dfcf0e3e53265055da8df952a53e7eaf178c/pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319", size = 12739445, upload-time = "2024-09-20T13:09:17.621Z" }, - { url = "https://files.pythonhosted.org/packages/20/e8/45a05d9c39d2cea61ab175dbe6a2de1d05b679e8de2011da4ee190d7e748/pandas-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8", size = 16359235, upload-time = "2024-09-20T19:02:07.094Z" }, - { url = "https://files.pythonhosted.org/packages/1d/99/617d07a6a5e429ff90c90da64d428516605a1ec7d7bea494235e1c3882de/pandas-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a", size = 14056756, upload-time = "2024-09-20T13:09:20.474Z" }, - { url = "https://files.pythonhosted.org/packages/29/d4/1244ab8edf173a10fd601f7e13b9566c1b525c4f365d6bee918e68381889/pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", size = 11504248, upload-time = "2024-09-20T13:09:23.137Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/17/a3/fb2734118db0af37ea7433f57f722c0a56687e14b14690edff0cdb4b7e58/pandas-2.2.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9", upload-time = "2024-09-20T13:09:09.655Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/e1/0c/ad295fd74bfac85358fd579e271cded3ac969de81f62dd0142c426b9da91/pandas-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4", upload-time = "2024-09-20T13:09:14.718Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/c6/2a/4bba3f03f7d07207481fed47f5b35f556c7441acddc368ec43d6643c5777/pandas-2.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3", upload-time = "2024-09-20T19:02:03.88Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/38/f8/d8fddee9ed0d0c0f4a2132c1dfcf0e3e53265055da8df952a53e7eaf178c/pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319", upload-time = "2024-09-20T13:09:17.621Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/20/e8/45a05d9c39d2cea61ab175dbe6a2de1d05b679e8de2011da4ee190d7e748/pandas-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8", upload-time = "2024-09-20T19:02:07.094Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/1d/99/617d07a6a5e429ff90c90da64d428516605a1ec7d7bea494235e1c3882de/pandas-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a", upload-time = "2024-09-20T13:09:20.474Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/29/d4/1244ab8edf173a10fd601f7e13b9566c1b525c4f365d6bee918e68381889/pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", upload-time = "2024-09-20T13:09:23.137Z" }, ] [[package]] name = "pathspec" version = "1.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", upload-time = "2026-04-27T01:46:08.907Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", upload-time = "2026-04-27T01:46:07.06Z" }, ] [[package]] name = "pillow" version = "12.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/21/c2bcdd5906101a30244eaffc1b6e6ce71a31bd0742a01eb89e660ebfac2d/pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5", size = 46987819, upload-time = "2026-04-01T14:46:17.687Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/8c/21/c2bcdd5906101a30244eaffc1b6e6ce71a31bd0742a01eb89e660ebfac2d/pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5", upload-time = "2026-04-01T14:46:17.687Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/58/be/7482c8a5ebebbc6470b3eb791812fff7d5e0216c2be3827b30b8bb6603ed/pillow-12.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2d192a155bbcec180f8564f693e6fd9bccff5a7af9b32e2e4bf8c9c69dbad6b5", size = 5308279, upload-time = "2026-04-01T14:43:13.246Z" }, - { url = "https://files.pythonhosted.org/packages/d8/95/0a351b9289c2b5cbde0bacd4a83ebc44023e835490a727b2a3bd60ddc0f4/pillow-12.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3f40b3c5a968281fd507d519e444c35f0ff171237f4fdde090dd60699458421", size = 4695490, upload-time = "2026-04-01T14:43:15.584Z" }, - { url = "https://files.pythonhosted.org/packages/de/af/4e8e6869cbed569d43c416fad3dc4ecb944cb5d9492defaed89ddd6fe871/pillow-12.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:03e7e372d5240cc23e9f07deca4d775c0817bffc641b01e9c3af208dbd300987", size = 6284462, upload-time = "2026-04-01T14:43:18.268Z" }, - { url = "https://files.pythonhosted.org/packages/e9/9e/c05e19657fd57841e476be1ab46c4d501bffbadbafdc31a6d665f8b737b6/pillow-12.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b86024e52a1b269467a802258c25521e6d742349d760728092e1bc2d135b4d76", size = 8094744, upload-time = "2026-04-01T14:43:20.716Z" }, - { url = "https://files.pythonhosted.org/packages/2b/54/1789c455ed10176066b6e7e6da1b01e50e36f94ba584dc68d9eebfe9156d/pillow-12.2.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7371b48c4fa448d20d2714c9a1f775a81155050d383333e0a6c15b1123dda005", size = 6398371, upload-time = "2026-04-01T14:43:23.443Z" }, - { url = "https://files.pythonhosted.org/packages/43/e3/fdc657359e919462369869f1c9f0e973f353f9a9ee295a39b1fea8ee1a77/pillow-12.2.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62f5409336adb0663b7caa0da5c7d9e7bdbaae9ce761d34669420c2a801b2780", size = 7087215, upload-time = "2026-04-01T14:43:26.758Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f8/2f6825e441d5b1959d2ca5adec984210f1ec086435b0ed5f52c19b3b8a6e/pillow-12.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:01afa7cf67f74f09523699b4e88c73fb55c13346d212a59a2db1f86b0a63e8c5", size = 6509783, upload-time = "2026-04-01T14:43:29.56Z" }, - { url = "https://files.pythonhosted.org/packages/67/f9/029a27095ad20f854f9dba026b3ea6428548316e057e6fc3545409e86651/pillow-12.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc3d34d4a8fbec3e88a79b92e5465e0f9b842b628675850d860b8bd300b159f5", size = 7212112, upload-time = "2026-04-01T14:43:32.091Z" }, - { url = "https://files.pythonhosted.org/packages/be/42/025cfe05d1be22dbfdb4f264fe9de1ccda83f66e4fc3aac94748e784af04/pillow-12.2.0-cp312-cp312-win32.whl", hash = "sha256:58f62cc0f00fd29e64b29f4fd923ffdb3859c9f9e6105bfc37ba1d08994e8940", size = 6378489, upload-time = "2026-04-01T14:43:34.601Z" }, - { url = "https://files.pythonhosted.org/packages/5d/7b/25a221d2c761c6a8ae21bfa3874988ff2583e19cf8a27bf2fee358df7942/pillow-12.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:7f84204dee22a783350679a0333981df803dac21a0190d706a50475e361c93f5", size = 7084129, upload-time = "2026-04-01T14:43:37.213Z" }, - { url = "https://files.pythonhosted.org/packages/10/e1/542a474affab20fd4a0f1836cb234e8493519da6b76899e30bcc5d990b8b/pillow-12.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:af73337013e0b3b46f175e79492d96845b16126ddf79c438d7ea7ff27783a414", size = 2463612, upload-time = "2026-04-01T14:43:39.421Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/58/be/7482c8a5ebebbc6470b3eb791812fff7d5e0216c2be3827b30b8bb6603ed/pillow-12.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2d192a155bbcec180f8564f693e6fd9bccff5a7af9b32e2e4bf8c9c69dbad6b5", upload-time = "2026-04-01T14:43:13.246Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/d8/95/0a351b9289c2b5cbde0bacd4a83ebc44023e835490a727b2a3bd60ddc0f4/pillow-12.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3f40b3c5a968281fd507d519e444c35f0ff171237f4fdde090dd60699458421", upload-time = "2026-04-01T14:43:15.584Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/de/af/4e8e6869cbed569d43c416fad3dc4ecb944cb5d9492defaed89ddd6fe871/pillow-12.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:03e7e372d5240cc23e9f07deca4d775c0817bffc641b01e9c3af208dbd300987", upload-time = "2026-04-01T14:43:18.268Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/e9/9e/c05e19657fd57841e476be1ab46c4d501bffbadbafdc31a6d665f8b737b6/pillow-12.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b86024e52a1b269467a802258c25521e6d742349d760728092e1bc2d135b4d76", upload-time = "2026-04-01T14:43:20.716Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/2b/54/1789c455ed10176066b6e7e6da1b01e50e36f94ba584dc68d9eebfe9156d/pillow-12.2.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7371b48c4fa448d20d2714c9a1f775a81155050d383333e0a6c15b1123dda005", upload-time = "2026-04-01T14:43:23.443Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/43/e3/fdc657359e919462369869f1c9f0e973f353f9a9ee295a39b1fea8ee1a77/pillow-12.2.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62f5409336adb0663b7caa0da5c7d9e7bdbaae9ce761d34669420c2a801b2780", upload-time = "2026-04-01T14:43:26.758Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/8b/f8/2f6825e441d5b1959d2ca5adec984210f1ec086435b0ed5f52c19b3b8a6e/pillow-12.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:01afa7cf67f74f09523699b4e88c73fb55c13346d212a59a2db1f86b0a63e8c5", upload-time = "2026-04-01T14:43:29.56Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/67/f9/029a27095ad20f854f9dba026b3ea6428548316e057e6fc3545409e86651/pillow-12.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc3d34d4a8fbec3e88a79b92e5465e0f9b842b628675850d860b8bd300b159f5", upload-time = "2026-04-01T14:43:32.091Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/be/42/025cfe05d1be22dbfdb4f264fe9de1ccda83f66e4fc3aac94748e784af04/pillow-12.2.0-cp312-cp312-win32.whl", hash = "sha256:58f62cc0f00fd29e64b29f4fd923ffdb3859c9f9e6105bfc37ba1d08994e8940", upload-time = "2026-04-01T14:43:34.601Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/5d/7b/25a221d2c761c6a8ae21bfa3874988ff2583e19cf8a27bf2fee358df7942/pillow-12.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:7f84204dee22a783350679a0333981df803dac21a0190d706a50475e361c93f5", upload-time = "2026-04-01T14:43:37.213Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/10/e1/542a474affab20fd4a0f1836cb234e8493519da6b76899e30bcc5d990b8b/pillow-12.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:af73337013e0b3b46f175e79492d96845b16126ddf79c438d7ea7ff27783a414", upload-time = "2026-04-01T14:43:39.421Z" }, ] [[package]] name = "platformdirs" version = "4.9.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9f/4a/0883b8e3802965322523f0b200ecf33d31f10991d0401162f4b23c698b42/platformdirs-4.9.6.tar.gz", hash = "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a", size = 29400, upload-time = "2026-04-09T00:04:10.812Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/9f/4a/0883b8e3802965322523f0b200ecf33d31f10991d0401162f4b23c698b42/platformdirs-4.9.6.tar.gz", hash = "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a", upload-time = "2026-04-09T00:04:10.812Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/75/a6/a0a304dc33b49145b21f4808d763822111e67d1c3a32b524a1baf947b6e1/platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917", size = 21348, upload-time = "2026-04-09T00:04:09.463Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/75/a6/a0a304dc33b49145b21f4808d763822111e67d1c3a32b524a1baf947b6e1/platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917", upload-time = "2026-04-09T00:04:09.463Z" }, ] [[package]] name = "pluggy" version = "1.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", upload-time = "2025-05-15T12:30:07.975Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", upload-time = "2025-05-15T12:30:06.134Z" }, ] [[package]] name = "pre-commit" version = "4.1.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "cfgv" }, { name = "identify" }, @@ -738,133 +848,133 @@ dependencies = [ { name = "pyyaml" }, { name = "virtualenv" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2a/13/b62d075317d8686071eb843f0bb1f195eb332f48869d3c31a4c6f1e063ac/pre_commit-4.1.0.tar.gz", hash = "sha256:ae3f018575a588e30dfddfab9a05448bfbd6b73d78709617b5a2b853549716d4", size = 193330, upload-time = "2025-01-20T18:31:48.681Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/2a/13/b62d075317d8686071eb843f0bb1f195eb332f48869d3c31a4c6f1e063ac/pre_commit-4.1.0.tar.gz", hash = "sha256:ae3f018575a588e30dfddfab9a05448bfbd6b73d78709617b5a2b853549716d4", upload-time = "2025-01-20T18:31:48.681Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/43/b3/df14c580d82b9627d173ceea305ba898dca135feb360b6d84019d0803d3b/pre_commit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d29e7cb346295bcc1cc75fc3e92e343495e3ea0196c9ec6ba53f49f10ab6ae7b", size = 220560, upload-time = "2025-01-20T18:31:47.319Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/43/b3/df14c580d82b9627d173ceea305ba898dca135feb360b6d84019d0803d3b/pre_commit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d29e7cb346295bcc1cc75fc3e92e343495e3ea0196c9ec6ba53f49f10ab6ae7b", upload-time = "2025-01-20T18:31:47.319Z" }, ] [[package]] name = "protobuf" version = "6.33.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/66/70/e908e9c5e52ef7c3a6c7902c9dfbb34c7e29c25d2f81ade3856445fd5c94/protobuf-6.33.6.tar.gz", hash = "sha256:a6768d25248312c297558af96a9f9c929e8c4cee0659cb07e780731095f38135", size = 444531, upload-time = "2026-03-18T19:05:00.988Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/66/70/e908e9c5e52ef7c3a6c7902c9dfbb34c7e29c25d2f81ade3856445fd5c94/protobuf-6.33.6.tar.gz", hash = "sha256:a6768d25248312c297558af96a9f9c929e8c4cee0659cb07e780731095f38135", upload-time = "2026-03-18T19:05:00.988Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/9f/2f509339e89cfa6f6a4c4ff50438db9ca488dec341f7e454adad60150b00/protobuf-6.33.6-cp310-abi3-win32.whl", hash = "sha256:7d29d9b65f8afef196f8334e80d6bc1d5d4adedb449971fefd3723824e6e77d3", size = 425739, upload-time = "2026-03-18T19:04:48.373Z" }, - { url = "https://files.pythonhosted.org/packages/76/5d/683efcd4798e0030c1bab27374fd13a89f7c2515fb1f3123efdfaa5eab57/protobuf-6.33.6-cp310-abi3-win_amd64.whl", hash = "sha256:0cd27b587afca21b7cfa59a74dcbd48a50f0a6400cfb59391340ad729d91d326", size = 437089, upload-time = "2026-03-18T19:04:50.381Z" }, - { url = "https://files.pythonhosted.org/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:9720e6961b251bde64edfdab7d500725a2af5280f3f4c87e57c0208376aa8c3a", size = 427737, upload-time = "2026-03-18T19:04:51.866Z" }, - { url = "https://files.pythonhosted.org/packages/ee/90/b3c01fdec7d2f627b3a6884243ba328c1217ed2d978def5c12dc50d328a3/protobuf-6.33.6-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:e2afbae9b8e1825e3529f88d514754e094278bb95eadc0e199751cdd9a2e82a2", size = 324610, upload-time = "2026-03-18T19:04:53.096Z" }, - { url = "https://files.pythonhosted.org/packages/9b/ca/25afc144934014700c52e05103c2421997482d561f3101ff352e1292fb81/protobuf-6.33.6-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:c96c37eec15086b79762ed265d59ab204dabc53056e3443e702d2681f4b39ce3", size = 339381, upload-time = "2026-03-18T19:04:54.616Z" }, - { url = "https://files.pythonhosted.org/packages/16/92/d1e32e3e0d894fe00b15ce28ad4944ab692713f2e7f0a99787405e43533a/protobuf-6.33.6-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:e9db7e292e0ab79dd108d7f1a94fe31601ce1ee3f7b79e0692043423020b0593", size = 323436, upload-time = "2026-03-18T19:04:55.768Z" }, - { url = "https://files.pythonhosted.org/packages/c4/72/02445137af02769918a93807b2b7890047c32bfb9f90371cbc12688819eb/protobuf-6.33.6-py3-none-any.whl", hash = "sha256:77179e006c476e69bf8e8ce866640091ec42e1beb80b213c3900006ecfba6901", size = 170656, upload-time = "2026-03-18T19:04:59.826Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/fc/9f/2f509339e89cfa6f6a4c4ff50438db9ca488dec341f7e454adad60150b00/protobuf-6.33.6-cp310-abi3-win32.whl", hash = "sha256:7d29d9b65f8afef196f8334e80d6bc1d5d4adedb449971fefd3723824e6e77d3", upload-time = "2026-03-18T19:04:48.373Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/76/5d/683efcd4798e0030c1bab27374fd13a89f7c2515fb1f3123efdfaa5eab57/protobuf-6.33.6-cp310-abi3-win_amd64.whl", hash = "sha256:0cd27b587afca21b7cfa59a74dcbd48a50f0a6400cfb59391340ad729d91d326", upload-time = "2026-03-18T19:04:50.381Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:9720e6961b251bde64edfdab7d500725a2af5280f3f4c87e57c0208376aa8c3a", upload-time = "2026-03-18T19:04:51.866Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/ee/90/b3c01fdec7d2f627b3a6884243ba328c1217ed2d978def5c12dc50d328a3/protobuf-6.33.6-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:e2afbae9b8e1825e3529f88d514754e094278bb95eadc0e199751cdd9a2e82a2", upload-time = "2026-03-18T19:04:53.096Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/9b/ca/25afc144934014700c52e05103c2421997482d561f3101ff352e1292fb81/protobuf-6.33.6-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:c96c37eec15086b79762ed265d59ab204dabc53056e3443e702d2681f4b39ce3", upload-time = "2026-03-18T19:04:54.616Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/16/92/d1e32e3e0d894fe00b15ce28ad4944ab692713f2e7f0a99787405e43533a/protobuf-6.33.6-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:e9db7e292e0ab79dd108d7f1a94fe31601ce1ee3f7b79e0692043423020b0593", upload-time = "2026-03-18T19:04:55.768Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/c4/72/02445137af02769918a93807b2b7890047c32bfb9f90371cbc12688819eb/protobuf-6.33.6-py3-none-any.whl", hash = "sha256:77179e006c476e69bf8e8ce866640091ec42e1beb80b213c3900006ecfba6901", upload-time = "2026-03-18T19:04:59.826Z" }, ] [[package]] name = "py-cpuinfo" version = "9.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/37/a8/d832f7293ebb21690860d2e01d8115e5ff6f2ae8bbdc953f0eb0fa4bd2c7/py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690", size = 104716, upload-time = "2022-10-25T20:38:06.303Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/37/a8/d832f7293ebb21690860d2e01d8115e5ff6f2ae8bbdc953f0eb0fa4bd2c7/py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690", upload-time = "2022-10-25T20:38:06.303Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/a9/023730ba63db1e494a271cb018dcd361bd2c917ba7004c3e49d5daf795a2/py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5", size = 22335, upload-time = "2022-10-25T20:38:27.636Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/e0/a9/023730ba63db1e494a271cb018dcd361bd2c917ba7004c3e49d5daf795a2/py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5", upload-time = "2022-10-25T20:38:27.636Z" }, ] [[package]] name = "py4j" version = "0.10.9.9" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/38/31/0b210511177070c8d5d3059556194352e5753602fa64b85b7ab81ec1a009/py4j-0.10.9.9.tar.gz", hash = "sha256:f694cad19efa5bd1dee4f3e5270eb406613c974394035e5bfc4ec1aba870b879", size = 761089, upload-time = "2025-01-15T03:53:18.624Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/38/31/0b210511177070c8d5d3059556194352e5753602fa64b85b7ab81ec1a009/py4j-0.10.9.9.tar.gz", hash = "sha256:f694cad19efa5bd1dee4f3e5270eb406613c974394035e5bfc4ec1aba870b879", upload-time = "2025-01-15T03:53:18.624Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl", hash = "sha256:c7c26e4158defb37b0bb124933163641a2ff6e3a3913f7811b0ddbe07ed61533", size = 203008, upload-time = "2025-01-15T03:53:15.648Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl", hash = "sha256:c7c26e4158defb37b0bb124933163641a2ff6e3a3913f7811b0ddbe07ed61533", upload-time = "2025-01-15T03:53:15.648Z" }, ] [[package]] name = "pyarrow" version = "19.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7f/09/a9046344212690f0632b9c709f9bf18506522feb333c894d0de81d62341a/pyarrow-19.0.1.tar.gz", hash = "sha256:3bf266b485df66a400f282ac0b6d1b500b9d2ae73314a153dbe97d6d5cc8a99e", size = 1129437, upload-time = "2025-02-18T18:55:57.027Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/7f/09/a9046344212690f0632b9c709f9bf18506522feb333c894d0de81d62341a/pyarrow-19.0.1.tar.gz", hash = "sha256:3bf266b485df66a400f282ac0b6d1b500b9d2ae73314a153dbe97d6d5cc8a99e", upload-time = "2025-02-18T18:55:57.027Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b4/94e828704b050e723f67d67c3535cf7076c7432cd4cf046e4bb3b96a9c9d/pyarrow-19.0.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:80b2ad2b193e7d19e81008a96e313fbd53157945c7be9ac65f44f8937a55427b", size = 30670749, upload-time = "2025-02-18T18:53:00.062Z" }, - { url = "https://files.pythonhosted.org/packages/7e/3b/4692965e04bb1df55e2c314c4296f1eb12b4f3052d4cf43d29e076aedf66/pyarrow-19.0.1-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:ee8dec072569f43835932a3b10c55973593abc00936c202707a4ad06af7cb294", size = 32128007, upload-time = "2025-02-18T18:53:06.581Z" }, - { url = "https://files.pythonhosted.org/packages/22/f7/2239af706252c6582a5635c35caa17cb4d401cd74a87821ef702e3888957/pyarrow-19.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d5d1ec7ec5324b98887bdc006f4d2ce534e10e60f7ad995e7875ffa0ff9cb14", size = 41144566, upload-time = "2025-02-18T18:53:11.958Z" }, - { url = "https://files.pythonhosted.org/packages/fb/e3/c9661b2b2849cfefddd9fd65b64e093594b231b472de08ff658f76c732b2/pyarrow-19.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3ad4c0eb4e2a9aeb990af6c09e6fa0b195c8c0e7b272ecc8d4d2b6574809d34", size = 42202991, upload-time = "2025-02-18T18:53:17.678Z" }, - { url = "https://files.pythonhosted.org/packages/fe/4f/a2c0ed309167ef436674782dfee4a124570ba64299c551e38d3fdaf0a17b/pyarrow-19.0.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:d383591f3dcbe545f6cc62daaef9c7cdfe0dff0fb9e1c8121101cabe9098cfa6", size = 40507986, upload-time = "2025-02-18T18:53:26.263Z" }, - { url = "https://files.pythonhosted.org/packages/27/2e/29bb28a7102a6f71026a9d70d1d61df926887e36ec797f2e6acfd2dd3867/pyarrow-19.0.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b4c4156a625f1e35d6c0b2132635a237708944eb41df5fbe7d50f20d20c17832", size = 42087026, upload-time = "2025-02-18T18:53:33.063Z" }, - { url = "https://files.pythonhosted.org/packages/16/33/2a67c0f783251106aeeee516f4806161e7b481f7d744d0d643d2f30230a5/pyarrow-19.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:5bd1618ae5e5476b7654c7b55a6364ae87686d4724538c24185bbb2952679960", size = 25250108, upload-time = "2025-02-18T18:53:38.462Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/78/b4/94e828704b050e723f67d67c3535cf7076c7432cd4cf046e4bb3b96a9c9d/pyarrow-19.0.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:80b2ad2b193e7d19e81008a96e313fbd53157945c7be9ac65f44f8937a55427b", upload-time = "2025-02-18T18:53:00.062Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/7e/3b/4692965e04bb1df55e2c314c4296f1eb12b4f3052d4cf43d29e076aedf66/pyarrow-19.0.1-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:ee8dec072569f43835932a3b10c55973593abc00936c202707a4ad06af7cb294", upload-time = "2025-02-18T18:53:06.581Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/22/f7/2239af706252c6582a5635c35caa17cb4d401cd74a87821ef702e3888957/pyarrow-19.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d5d1ec7ec5324b98887bdc006f4d2ce534e10e60f7ad995e7875ffa0ff9cb14", upload-time = "2025-02-18T18:53:11.958Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/fb/e3/c9661b2b2849cfefddd9fd65b64e093594b231b472de08ff658f76c732b2/pyarrow-19.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3ad4c0eb4e2a9aeb990af6c09e6fa0b195c8c0e7b272ecc8d4d2b6574809d34", upload-time = "2025-02-18T18:53:17.678Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/fe/4f/a2c0ed309167ef436674782dfee4a124570ba64299c551e38d3fdaf0a17b/pyarrow-19.0.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:d383591f3dcbe545f6cc62daaef9c7cdfe0dff0fb9e1c8121101cabe9098cfa6", upload-time = "2025-02-18T18:53:26.263Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/27/2e/29bb28a7102a6f71026a9d70d1d61df926887e36ec797f2e6acfd2dd3867/pyarrow-19.0.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b4c4156a625f1e35d6c0b2132635a237708944eb41df5fbe7d50f20d20c17832", upload-time = "2025-02-18T18:53:33.063Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/16/33/2a67c0f783251106aeeee516f4806161e7b481f7d744d0d643d2f30230a5/pyarrow-19.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:5bd1618ae5e5476b7654c7b55a6364ae87686d4724538c24185bbb2952679960", upload-time = "2025-02-18T18:53:38.462Z" }, ] [[package]] name = "pyasn1" version = "0.6.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5c/5f/6583902b6f79b399c9c40674ac384fd9cd77805f9e6205075f828ef11fb2/pyasn1-0.6.3.tar.gz", hash = "sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf", size = 148685, upload-time = "2026-03-17T01:06:53.382Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/5c/5f/6583902b6f79b399c9c40674ac384fd9cd77805f9e6205075f828ef11fb2/pyasn1-0.6.3.tar.gz", hash = "sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf", upload-time = "2026-03-17T01:06:53.382Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl", hash = "sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde", size = 83997, upload-time = "2026-03-17T01:06:52.036Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl", hash = "sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde", upload-time = "2026-03-17T01:06:52.036Z" }, ] [[package]] name = "pyasn1-modules" version = "0.4.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "pyasn1" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", upload-time = "2025-03-28T02:41:22.17Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", upload-time = "2025-03-28T02:41:19.028Z" }, ] [[package]] name = "pycparser" version = "3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", upload-time = "2026-01-21T14:26:51.89Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", upload-time = "2026-01-21T14:26:50.693Z" }, ] [[package]] name = "pydantic" version = "2.11.7" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "annotated-types" }, { name = "pydantic-core" }, { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350, upload-time = "2025-06-14T08:33:17.137Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", upload-time = "2025-06-14T08:33:17.137Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782, upload-time = "2025-06-14T08:33:14.905Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", upload-time = "2025-06-14T08:33:14.905Z" }, ] [[package]] name = "pydantic-core" version = "2.33.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", upload-time = "2025-04-23T18:33:52.104Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" }, - { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" }, - { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" }, - { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" }, - { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" }, - { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" }, - { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" }, - { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" }, - { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" }, - { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" }, - { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" }, - { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" }, - { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" }, - { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", upload-time = "2025-04-23T18:31:25.863Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", upload-time = "2025-04-23T18:31:27.341Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", upload-time = "2025-04-23T18:31:28.956Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", upload-time = "2025-04-23T18:31:31.025Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", upload-time = "2025-04-23T18:31:32.514Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", upload-time = "2025-04-23T18:31:33.958Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", upload-time = "2025-04-23T18:31:39.095Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", upload-time = "2025-04-23T18:31:41.034Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", upload-time = "2025-04-23T18:31:42.757Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", upload-time = "2025-04-23T18:31:44.304Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", upload-time = "2025-04-23T18:31:45.891Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", upload-time = "2025-04-23T18:31:47.819Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", upload-time = "2025-04-23T18:31:49.635Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", upload-time = "2025-04-23T18:31:51.609Z" }, ] [[package]] name = "pydoc-markdown" version = "4.8.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "click" }, { name = "databind-core" }, @@ -881,376 +991,376 @@ dependencies = [ { name = "watchdog" }, { name = "yapf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e1/8a/2c7f7ad656d22371a596d232fc140327b958d7f1d491b889632ea0cb7e87/pydoc_markdown-4.8.2.tar.gz", hash = "sha256:fb6c927e31386de17472d42f9bd3d3be2905977d026f6216881c65145aa67f0b", size = 44506, upload-time = "2023-06-26T12:37:01.152Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/e1/8a/2c7f7ad656d22371a596d232fc140327b958d7f1d491b889632ea0cb7e87/pydoc_markdown-4.8.2.tar.gz", hash = "sha256:fb6c927e31386de17472d42f9bd3d3be2905977d026f6216881c65145aa67f0b", upload-time = "2023-06-26T12:37:01.152Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/5a/ce0b056d9a95fd0c06a6cfa5972477d79353392d19230c748a7ba5a9df04/pydoc_markdown-4.8.2-py3-none-any.whl", hash = "sha256:203f74119e6bb2f9deba43d452422de7c8ec31955b61e0620fa4dd8c2611715f", size = 67830, upload-time = "2023-06-26T12:36:59.502Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/83/5a/ce0b056d9a95fd0c06a6cfa5972477d79353392d19230c748a7ba5a9df04/pydoc_markdown-4.8.2-py3-none-any.whl", hash = "sha256:203f74119e6bb2f9deba43d452422de7c8ec31955b61e0620fa4dd8c2611715f", upload-time = "2023-06-26T12:36:59.502Z" }, ] [[package]] name = "pyparsing" version = "3.3.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", upload-time = "2026-01-21T03:57:59.36Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", upload-time = "2026-01-21T03:57:55.912Z" }, ] [[package]] name = "pyspark" version = "4.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "py4j" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9d/0e/5b38d51f1b1c2618cccfbf35093268665af9a3bdb493e5a3ecd991def633/pyspark-4.0.0.tar.gz", hash = "sha256:38db1b4f6095a080d7605e578d775528990e66dc326311d93e94a71cfc24e5a5", size = 434132212, upload-time = "2025-05-23T03:29:33.916Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/9d/0e/5b38d51f1b1c2618cccfbf35093268665af9a3bdb493e5a3ecd991def633/pyspark-4.0.0.tar.gz", hash = "sha256:38db1b4f6095a080d7605e578d775528990e66dc326311d93e94a71cfc24e5a5", upload-time = "2025-05-23T03:29:33.916Z" } [[package]] name = "pytest" version = "8.3.5" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "iniconfig" }, { name = "packaging" }, { name = "pluggy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891, upload-time = "2025-03-02T12:54:54.503Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", upload-time = "2025-03-02T12:54:54.503Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634, upload-time = "2025-03-02T12:54:52.069Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", upload-time = "2025-03-02T12:54:52.069Z" }, ] [[package]] name = "pytest-benchmark" version = "5.1.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "py-cpuinfo" }, { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/39/d0/a8bd08d641b393db3be3819b03e2d9bb8760ca8479080a26a5f6e540e99c/pytest-benchmark-5.1.0.tar.gz", hash = "sha256:9ea661cdc292e8231f7cd4c10b0319e56a2118e2c09d9f50e1b3d150d2aca105", size = 337810, upload-time = "2024-10-30T11:51:48.521Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/39/d0/a8bd08d641b393db3be3819b03e2d9bb8760ca8479080a26a5f6e540e99c/pytest-benchmark-5.1.0.tar.gz", hash = "sha256:9ea661cdc292e8231f7cd4c10b0319e56a2118e2c09d9f50e1b3d150d2aca105", upload-time = "2024-10-30T11:51:48.521Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/d6/b41653199ea09d5969d4e385df9bbfd9a100f28ca7e824ce7c0a016e3053/pytest_benchmark-5.1.0-py3-none-any.whl", hash = "sha256:922de2dfa3033c227c96da942d1878191afa135a29485fb942e85dff1c592c89", size = 44259, upload-time = "2024-10-30T11:51:45.94Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/9e/d6/b41653199ea09d5969d4e385df9bbfd9a100f28ca7e824ce7c0a016e3053/pytest_benchmark-5.1.0-py3-none-any.whl", hash = "sha256:922de2dfa3033c227c96da942d1878191afa135a29485fb942e85dff1c592c89", upload-time = "2024-10-30T11:51:45.94Z" }, ] [[package]] name = "pytest-cov" version = "6.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "coverage" }, { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", size = 66945, upload-time = "2024-10-29T20:13:35.363Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", upload-time = "2024-10-29T20:13:35.363Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", size = 22949, upload-time = "2024-10-29T20:13:33.215Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", upload-time = "2024-10-29T20:13:33.215Z" }, ] [[package]] name = "pytest-mock" version = "3.15.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/68/14/eb014d26be205d38ad5ad20d9a80f7d201472e08167f0bb4361e251084a9/pytest_mock-3.15.1.tar.gz", hash = "sha256:1849a238f6f396da19762269de72cb1814ab44416fa73a8686deac10b0d87a0f", size = 34036, upload-time = "2025-09-16T16:37:27.081Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/68/14/eb014d26be205d38ad5ad20d9a80f7d201472e08167f0bb4361e251084a9/pytest_mock-3.15.1.tar.gz", hash = "sha256:1849a238f6f396da19762269de72cb1814ab44416fa73a8686deac10b0d87a0f", upload-time = "2025-09-16T16:37:27.081Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5a/cc/06253936f4a7fa2e0f48dfe6d851d9c56df896a9ab09ac019d70b760619c/pytest_mock-3.15.1-py3-none-any.whl", hash = "sha256:0a25e2eb88fe5168d535041d09a4529a188176ae608a6d249ee65abc0949630d", size = 10095, upload-time = "2025-09-16T16:37:25.734Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/5a/cc/06253936f4a7fa2e0f48dfe6d851d9c56df896a9ab09ac019d70b760619c/pytest_mock-3.15.1-py3-none-any.whl", hash = "sha256:0a25e2eb88fe5168d535041d09a4529a188176ae608a6d249ee65abc0949630d", upload-time = "2025-09-16T16:37:25.734Z" }, ] [[package]] name = "python-dateutil" version = "2.9.0.post0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", upload-time = "2024-03-01T18:36:20.211Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", upload-time = "2024-03-01T18:36:18.57Z" }, ] [[package]] name = "python-discovery" version = "1.2.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "filelock" }, { name = "platformdirs" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/de/ef/3bae0e537cfe91e8431efcba4434463d2c5a65f5a89edd47c6cf2f03c55f/python_discovery-1.2.2.tar.gz", hash = "sha256:876e9c57139eb757cb5878cbdd9ae5379e5d96266c99ef731119e04fffe533bb", size = 58872, upload-time = "2026-04-07T17:28:49.249Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/de/ef/3bae0e537cfe91e8431efcba4434463d2c5a65f5a89edd47c6cf2f03c55f/python_discovery-1.2.2.tar.gz", hash = "sha256:876e9c57139eb757cb5878cbdd9ae5379e5d96266c99ef731119e04fffe533bb", upload-time = "2026-04-07T17:28:49.249Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d8/db/795879cc3ddfe338599bddea6388cc5100b088db0a4caf6e6c1af1c27e04/python_discovery-1.2.2-py3-none-any.whl", hash = "sha256:e1ae95d9af875e78f15e19aed0c6137ab1bb49c200f21f5061786490c9585c7a", size = 31894, upload-time = "2026-04-07T17:28:48.09Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/d8/db/795879cc3ddfe338599bddea6388cc5100b088db0a4caf6e6c1af1c27e04/python_discovery-1.2.2-py3-none-any.whl", hash = "sha256:e1ae95d9af875e78f15e19aed0c6137ab1bb49c200f21f5061786490c9585c7a", upload-time = "2026-04-07T17:28:48.09Z" }, ] [[package]] name = "pytokens" version = "0.4.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b6/34/b4e015b99031667a7b960f888889c5bd34ef585c85e1cb56a594b92836ac/pytokens-0.4.1.tar.gz", hash = "sha256:292052fe80923aae2260c073f822ceba21f3872ced9a68bb7953b348e561179a", size = 23015, upload-time = "2026-01-30T01:03:45.924Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/b6/34/b4e015b99031667a7b960f888889c5bd34ef585c85e1cb56a594b92836ac/pytokens-0.4.1.tar.gz", hash = "sha256:292052fe80923aae2260c073f822ceba21f3872ced9a68bb7953b348e561179a", upload-time = "2026-01-30T01:03:45.924Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/5d/e44573011401fb82e9d51e97f1290ceb377800fb4eed650b96f4753b499c/pytokens-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:140709331e846b728475786df8aeb27d24f48cbcf7bcd449f8de75cae7a45083", size = 160663, upload-time = "2026-01-30T01:03:06.473Z" }, - { url = "https://files.pythonhosted.org/packages/f0/e6/5bbc3019f8e6f21d09c41f8b8654536117e5e211a85d89212d59cbdab381/pytokens-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d6c4268598f762bc8e91f5dbf2ab2f61f7b95bdc07953b602db879b3c8c18e1", size = 255626, upload-time = "2026-01-30T01:03:08.177Z" }, - { url = "https://files.pythonhosted.org/packages/bf/3c/2d5297d82286f6f3d92770289fd439956b201c0a4fc7e72efb9b2293758e/pytokens-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24afde1f53d95348b5a0eb19488661147285ca4dd7ed752bbc3e1c6242a304d1", size = 269779, upload-time = "2026-01-30T01:03:09.756Z" }, - { url = "https://files.pythonhosted.org/packages/20/01/7436e9ad693cebda0551203e0bf28f7669976c60ad07d6402098208476de/pytokens-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5ad948d085ed6c16413eb5fec6b3e02fa00dc29a2534f088d3302c47eb59adf9", size = 268076, upload-time = "2026-01-30T01:03:10.957Z" }, - { url = "https://files.pythonhosted.org/packages/2e/df/533c82a3c752ba13ae7ef238b7f8cdd272cf1475f03c63ac6cf3fcfb00b6/pytokens-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:3f901fe783e06e48e8cbdc82d631fca8f118333798193e026a50ce1b3757ea68", size = 103552, upload-time = "2026-01-30T01:03:12.066Z" }, - { url = "https://files.pythonhosted.org/packages/c6/78/397db326746f0a342855b81216ae1f0a32965deccfd7c830a2dbc66d2483/pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de", size = 13729, upload-time = "2026-01-30T01:03:45.029Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/41/5d/e44573011401fb82e9d51e97f1290ceb377800fb4eed650b96f4753b499c/pytokens-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:140709331e846b728475786df8aeb27d24f48cbcf7bcd449f8de75cae7a45083", upload-time = "2026-01-30T01:03:06.473Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/f0/e6/5bbc3019f8e6f21d09c41f8b8654536117e5e211a85d89212d59cbdab381/pytokens-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d6c4268598f762bc8e91f5dbf2ab2f61f7b95bdc07953b602db879b3c8c18e1", upload-time = "2026-01-30T01:03:08.177Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/bf/3c/2d5297d82286f6f3d92770289fd439956b201c0a4fc7e72efb9b2293758e/pytokens-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24afde1f53d95348b5a0eb19488661147285ca4dd7ed752bbc3e1c6242a304d1", upload-time = "2026-01-30T01:03:09.756Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/20/01/7436e9ad693cebda0551203e0bf28f7669976c60ad07d6402098208476de/pytokens-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5ad948d085ed6c16413eb5fec6b3e02fa00dc29a2534f088d3302c47eb59adf9", upload-time = "2026-01-30T01:03:10.957Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/2e/df/533c82a3c752ba13ae7ef238b7f8cdd272cf1475f03c63ac6cf3fcfb00b6/pytokens-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:3f901fe783e06e48e8cbdc82d631fca8f118333798193e026a50ce1b3757ea68", upload-time = "2026-01-30T01:03:12.066Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/c6/78/397db326746f0a342855b81216ae1f0a32965deccfd7c830a2dbc66d2483/pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de", upload-time = "2026-01-30T01:03:45.029Z" }, ] [[package]] name = "pytz" version = "2026.1.post1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/56/db/b8721d71d945e6a8ac63c0fc900b2067181dbb50805958d4d4661cf7d277/pytz-2026.1.post1.tar.gz", hash = "sha256:3378dde6a0c3d26719182142c56e60c7f9af7e968076f31aae569d72a0358ee1", size = 321088, upload-time = "2026-03-03T07:47:50.683Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/56/db/b8721d71d945e6a8ac63c0fc900b2067181dbb50805958d4d4661cf7d277/pytz-2026.1.post1.tar.gz", hash = "sha256:3378dde6a0c3d26719182142c56e60c7f9af7e968076f31aae569d72a0358ee1", upload-time = "2026-03-03T07:47:50.683Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/99/781fe0c827be2742bcc775efefccb3b048a3a9c6ce9aec0cbf4a101677e5/pytz-2026.1.post1-py2.py3-none-any.whl", hash = "sha256:f2fd16142fda348286a75e1a524be810bb05d444e5a081f37f7affc635035f7a", size = 510489, upload-time = "2026-03-03T07:47:49.167Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/10/99/781fe0c827be2742bcc775efefccb3b048a3a9c6ce9aec0cbf4a101677e5/pytz-2026.1.post1-py2.py3-none-any.whl", hash = "sha256:f2fd16142fda348286a75e1a524be810bb05d444e5a081f37f7affc635035f7a", upload-time = "2026-03-03T07:47:49.167Z" }, ] [[package]] name = "pyyaml" version = "6.0.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", upload-time = "2025-09-25T21:33:16.546Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, - { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, - { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, - { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, - { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, - { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, - { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, - { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, - { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, - { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", upload-time = "2025-09-25T21:32:22.617Z" }, ] [[package]] name = "requests" version = "2.33.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "certifi" }, { name = "charset-normalizer" }, { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517", size = 134120, upload-time = "2026-03-30T16:09:15.531Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517", upload-time = "2026-03-30T16:09:15.531Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a", size = 64947, upload-time = "2026-03-30T16:09:13.83Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a", upload-time = "2026-03-30T16:09:13.83Z" }, ] [[package]] name = "ruff" version = "0.9.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/8e/fafaa6f15c332e73425d9c44ada85360501045d5ab0b81400076aff27cf6/ruff-0.9.10.tar.gz", hash = "sha256:9bacb735d7bada9cfb0f2c227d3658fc443d90a727b47f206fb33f52f3c0eac7", size = 3759776, upload-time = "2025-03-07T15:27:44.363Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/73/b2/af7c2cc9e438cbc19fafeec4f20bfcd72165460fe75b2b6e9a0958c8c62b/ruff-0.9.10-py3-none-linux_armv6l.whl", hash = "sha256:eb4d25532cfd9fe461acc83498361ec2e2252795b4f40b17e80692814329e42d", size = 10049494, upload-time = "2025-03-07T15:26:51.268Z" }, - { url = "https://files.pythonhosted.org/packages/6d/12/03f6dfa1b95ddd47e6969f0225d60d9d7437c91938a310835feb27927ca0/ruff-0.9.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:188a6638dab1aa9bb6228a7302387b2c9954e455fb25d6b4470cb0641d16759d", size = 10853584, upload-time = "2025-03-07T15:26:56.104Z" }, - { url = "https://files.pythonhosted.org/packages/02/49/1c79e0906b6ff551fb0894168763f705bf980864739572b2815ecd3c9df0/ruff-0.9.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5284dcac6b9dbc2fcb71fdfc26a217b2ca4ede6ccd57476f52a587451ebe450d", size = 10155692, upload-time = "2025-03-07T15:27:01.385Z" }, - { url = "https://files.pythonhosted.org/packages/5b/01/85e8082e41585e0e1ceb11e41c054e9e36fed45f4b210991052d8a75089f/ruff-0.9.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47678f39fa2a3da62724851107f438c8229a3470f533894b5568a39b40029c0c", size = 10369760, upload-time = "2025-03-07T15:27:04.023Z" }, - { url = "https://files.pythonhosted.org/packages/a1/90/0bc60bd4e5db051f12445046d0c85cc2c617095c0904f1aa81067dc64aea/ruff-0.9.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99713a6e2766b7a17147b309e8c915b32b07a25c9efd12ada79f217c9c778b3e", size = 9912196, upload-time = "2025-03-07T15:27:06.93Z" }, - { url = "https://files.pythonhosted.org/packages/66/ea/0b7e8c42b1ec608033c4d5a02939c82097ddcb0b3e393e4238584b7054ab/ruff-0.9.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:524ee184d92f7c7304aa568e2db20f50c32d1d0caa235d8ddf10497566ea1a12", size = 11434985, upload-time = "2025-03-07T15:27:10.082Z" }, - { url = "https://files.pythonhosted.org/packages/d5/86/3171d1eff893db4f91755175a6e1163c5887be1f1e2f4f6c0c59527c2bfd/ruff-0.9.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:df92aeac30af821f9acf819fc01b4afc3dfb829d2782884f8739fb52a8119a16", size = 12155842, upload-time = "2025-03-07T15:27:12.727Z" }, - { url = "https://files.pythonhosted.org/packages/89/9e/700ca289f172a38eb0bca752056d0a42637fa17b81649b9331786cb791d7/ruff-0.9.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de42e4edc296f520bb84954eb992a07a0ec5a02fecb834498415908469854a52", size = 11613804, upload-time = "2025-03-07T15:27:15.944Z" }, - { url = "https://files.pythonhosted.org/packages/f2/92/648020b3b5db180f41a931a68b1c8575cca3e63cec86fd26807422a0dbad/ruff-0.9.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d257f95b65806104b6b1ffca0ea53f4ef98454036df65b1eda3693534813ecd1", size = 13823776, upload-time = "2025-03-07T15:27:18.996Z" }, - { url = "https://files.pythonhosted.org/packages/5e/a6/cc472161cd04d30a09d5c90698696b70c169eeba2c41030344194242db45/ruff-0.9.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60dec7201c0b10d6d11be00e8f2dbb6f40ef1828ee75ed739923799513db24c", size = 11302673, upload-time = "2025-03-07T15:27:21.655Z" }, - { url = "https://files.pythonhosted.org/packages/6c/db/d31c361c4025b1b9102b4d032c70a69adb9ee6fde093f6c3bf29f831c85c/ruff-0.9.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d838b60007da7a39c046fcdd317293d10b845001f38bcb55ba766c3875b01e43", size = 10235358, upload-time = "2025-03-07T15:27:24.72Z" }, - { url = "https://files.pythonhosted.org/packages/d1/86/d6374e24a14d4d93ebe120f45edd82ad7dcf3ef999ffc92b197d81cdc2a5/ruff-0.9.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ccaf903108b899beb8e09a63ffae5869057ab649c1e9231c05ae354ebc62066c", size = 9886177, upload-time = "2025-03-07T15:27:27.282Z" }, - { url = "https://files.pythonhosted.org/packages/00/62/a61691f6eaaac1e945a1f3f59f1eea9a218513139d5b6c2b8f88b43b5b8f/ruff-0.9.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f9567d135265d46e59d62dc60c0bfad10e9a6822e231f5b24032dba5a55be6b5", size = 10864747, upload-time = "2025-03-07T15:27:30.637Z" }, - { url = "https://files.pythonhosted.org/packages/ee/94/2c7065e1d92a8a8a46d46d9c3cf07b0aa7e0a1e0153d74baa5e6620b4102/ruff-0.9.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5f202f0d93738c28a89f8ed9eaba01b7be339e5d8d642c994347eaa81c6d75b8", size = 11360441, upload-time = "2025-03-07T15:27:33.356Z" }, - { url = "https://files.pythonhosted.org/packages/a7/8f/1f545ea6f9fcd7bf4368551fb91d2064d8f0577b3079bb3f0ae5779fb773/ruff-0.9.10-py3-none-win32.whl", hash = "sha256:bfb834e87c916521ce46b1788fbb8484966e5113c02df216680102e9eb960029", size = 10247401, upload-time = "2025-03-07T15:27:35.994Z" }, - { url = "https://files.pythonhosted.org/packages/4f/18/fb703603ab108e5c165f52f5b86ee2aa9be43bb781703ec87c66a5f5d604/ruff-0.9.10-py3-none-win_amd64.whl", hash = "sha256:f2160eeef3031bf4b17df74e307d4c5fb689a6f3a26a2de3f7ef4044e3c484f1", size = 11366360, upload-time = "2025-03-07T15:27:38.66Z" }, - { url = "https://files.pythonhosted.org/packages/35/85/338e603dc68e7d9994d5d84f24adbf69bae760ba5efd3e20f5ff2cec18da/ruff-0.9.10-py3-none-win_arm64.whl", hash = "sha256:5fd804c0327a5e5ea26615550e706942f348b197d5475ff34c19733aee4b2e69", size = 10436892, upload-time = "2025-03-07T15:27:41.687Z" }, +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/20/8e/fafaa6f15c332e73425d9c44ada85360501045d5ab0b81400076aff27cf6/ruff-0.9.10.tar.gz", hash = "sha256:9bacb735d7bada9cfb0f2c227d3658fc443d90a727b47f206fb33f52f3c0eac7", upload-time = "2025-03-07T15:27:44.363Z" } +wheels = [ + { url = "https://pypi-proxy.cloud.databricks.com/packages/73/b2/af7c2cc9e438cbc19fafeec4f20bfcd72165460fe75b2b6e9a0958c8c62b/ruff-0.9.10-py3-none-linux_armv6l.whl", hash = "sha256:eb4d25532cfd9fe461acc83498361ec2e2252795b4f40b17e80692814329e42d", upload-time = "2025-03-07T15:26:51.268Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/6d/12/03f6dfa1b95ddd47e6969f0225d60d9d7437c91938a310835feb27927ca0/ruff-0.9.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:188a6638dab1aa9bb6228a7302387b2c9954e455fb25d6b4470cb0641d16759d", upload-time = "2025-03-07T15:26:56.104Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/02/49/1c79e0906b6ff551fb0894168763f705bf980864739572b2815ecd3c9df0/ruff-0.9.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5284dcac6b9dbc2fcb71fdfc26a217b2ca4ede6ccd57476f52a587451ebe450d", upload-time = "2025-03-07T15:27:01.385Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/5b/01/85e8082e41585e0e1ceb11e41c054e9e36fed45f4b210991052d8a75089f/ruff-0.9.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47678f39fa2a3da62724851107f438c8229a3470f533894b5568a39b40029c0c", upload-time = "2025-03-07T15:27:04.023Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/a1/90/0bc60bd4e5db051f12445046d0c85cc2c617095c0904f1aa81067dc64aea/ruff-0.9.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99713a6e2766b7a17147b309e8c915b32b07a25c9efd12ada79f217c9c778b3e", upload-time = "2025-03-07T15:27:06.93Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/66/ea/0b7e8c42b1ec608033c4d5a02939c82097ddcb0b3e393e4238584b7054ab/ruff-0.9.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:524ee184d92f7c7304aa568e2db20f50c32d1d0caa235d8ddf10497566ea1a12", upload-time = "2025-03-07T15:27:10.082Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/d5/86/3171d1eff893db4f91755175a6e1163c5887be1f1e2f4f6c0c59527c2bfd/ruff-0.9.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:df92aeac30af821f9acf819fc01b4afc3dfb829d2782884f8739fb52a8119a16", upload-time = "2025-03-07T15:27:12.727Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/89/9e/700ca289f172a38eb0bca752056d0a42637fa17b81649b9331786cb791d7/ruff-0.9.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de42e4edc296f520bb84954eb992a07a0ec5a02fecb834498415908469854a52", upload-time = "2025-03-07T15:27:15.944Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/f2/92/648020b3b5db180f41a931a68b1c8575cca3e63cec86fd26807422a0dbad/ruff-0.9.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d257f95b65806104b6b1ffca0ea53f4ef98454036df65b1eda3693534813ecd1", upload-time = "2025-03-07T15:27:18.996Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/5e/a6/cc472161cd04d30a09d5c90698696b70c169eeba2c41030344194242db45/ruff-0.9.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60dec7201c0b10d6d11be00e8f2dbb6f40ef1828ee75ed739923799513db24c", upload-time = "2025-03-07T15:27:21.655Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/6c/db/d31c361c4025b1b9102b4d032c70a69adb9ee6fde093f6c3bf29f831c85c/ruff-0.9.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d838b60007da7a39c046fcdd317293d10b845001f38bcb55ba766c3875b01e43", upload-time = "2025-03-07T15:27:24.72Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/d1/86/d6374e24a14d4d93ebe120f45edd82ad7dcf3ef999ffc92b197d81cdc2a5/ruff-0.9.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ccaf903108b899beb8e09a63ffae5869057ab649c1e9231c05ae354ebc62066c", upload-time = "2025-03-07T15:27:27.282Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/00/62/a61691f6eaaac1e945a1f3f59f1eea9a218513139d5b6c2b8f88b43b5b8f/ruff-0.9.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f9567d135265d46e59d62dc60c0bfad10e9a6822e231f5b24032dba5a55be6b5", upload-time = "2025-03-07T15:27:30.637Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/ee/94/2c7065e1d92a8a8a46d46d9c3cf07b0aa7e0a1e0153d74baa5e6620b4102/ruff-0.9.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5f202f0d93738c28a89f8ed9eaba01b7be339e5d8d642c994347eaa81c6d75b8", upload-time = "2025-03-07T15:27:33.356Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/a7/8f/1f545ea6f9fcd7bf4368551fb91d2064d8f0577b3079bb3f0ae5779fb773/ruff-0.9.10-py3-none-win32.whl", hash = "sha256:bfb834e87c916521ce46b1788fbb8484966e5113c02df216680102e9eb960029", upload-time = "2025-03-07T15:27:35.994Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/4f/18/fb703603ab108e5c165f52f5b86ee2aa9be43bb781703ec87c66a5f5d604/ruff-0.9.10-py3-none-win_amd64.whl", hash = "sha256:f2160eeef3031bf4b17df74e307d4c5fb689a6f3a26a2de3f7ef4044e3c484f1", upload-time = "2025-03-07T15:27:38.66Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/35/85/338e603dc68e7d9994d5d84f24adbf69bae760ba5efd3e20f5ff2cec18da/ruff-0.9.10-py3-none-win_arm64.whl", hash = "sha256:5fd804c0327a5e5ea26615550e706942f348b197d5475ff34c19733aee4b2e69", upload-time = "2025-03-07T15:27:41.687Z" }, ] [[package]] name = "scipy" version = "1.15.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/76/c6/8eb0654ba0c7d0bb1bf67bf8fbace101a8e4f250f7722371105e8b6f68fc/scipy-1.15.1.tar.gz", hash = "sha256:033a75ddad1463970c96a88063a1df87ccfddd526437136b6ee81ff0312ebdf6", size = 59407493, upload-time = "2025-01-11T00:06:16.883Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/76/c6/8eb0654ba0c7d0bb1bf67bf8fbace101a8e4f250f7722371105e8b6f68fc/scipy-1.15.1.tar.gz", hash = "sha256:033a75ddad1463970c96a88063a1df87ccfddd526437136b6ee81ff0312ebdf6", upload-time = "2025-01-11T00:06:16.883Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d8/6e/a9c42d0d39e09ed7fd203d0ac17adfea759cba61ab457671fe66e523dbec/scipy-1.15.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c09aa9d90f3500ea4c9b393ee96f96b0ccb27f2f350d09a47f533293c78ea776", size = 41478318, upload-time = "2025-01-11T00:01:53.571Z" }, - { url = "https://files.pythonhosted.org/packages/04/ee/e3e535c81828618878a7433992fecc92fa4df79393f31a8fea1d05615091/scipy-1.15.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:0ac102ce99934b162914b1e4a6b94ca7da0f4058b6d6fd65b0cef330c0f3346f", size = 32596696, upload-time = "2025-01-11T00:02:03.859Z" }, - { url = "https://files.pythonhosted.org/packages/c4/5e/b1b0124be8e76f87115f16b8915003eec4b7060298117715baf13f51942c/scipy-1.15.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:09c52320c42d7f5c7748b69e9f0389266fd4f82cf34c38485c14ee976cb8cb04", size = 24870366, upload-time = "2025-01-11T00:02:12.434Z" }, - { url = "https://files.pythonhosted.org/packages/14/36/c00cb73eefda85946172c27913ab995c6ad4eee00fa4f007572e8c50cd51/scipy-1.15.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:cdde8414154054763b42b74fe8ce89d7f3d17a7ac5dd77204f0e142cdc9239e9", size = 28007461, upload-time = "2025-01-11T00:02:20.237Z" }, - { url = "https://files.pythonhosted.org/packages/68/94/aff5c51b3799349a9d1e67a056772a0f8a47db371e83b498d43467806557/scipy-1.15.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c9d8fc81d6a3b6844235e6fd175ee1d4c060163905a2becce8e74cb0d7554ce", size = 38068174, upload-time = "2025-01-11T00:02:30.21Z" }, - { url = "https://files.pythonhosted.org/packages/b0/3c/0de11ca154e24a57b579fb648151d901326d3102115bc4f9a7a86526ce54/scipy-1.15.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fb57b30f0017d4afa5fe5f5b150b8f807618819287c21cbe51130de7ccdaed2", size = 40249869, upload-time = "2025-01-11T00:02:41.811Z" }, - { url = "https://files.pythonhosted.org/packages/15/09/472e8d0a6b33199d1bb95e49bedcabc0976c3724edd9b0ef7602ccacf41e/scipy-1.15.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:491d57fe89927fa1aafbe260f4cfa5ffa20ab9f1435025045a5315006a91b8f5", size = 42629068, upload-time = "2025-01-11T00:02:53.118Z" }, - { url = "https://files.pythonhosted.org/packages/ff/ba/31c7a8131152822b3a2cdeba76398ffb404d81d640de98287d236da90c49/scipy-1.15.1-cp312-cp312-win_amd64.whl", hash = "sha256:900f3fa3db87257510f011c292a5779eb627043dd89731b9c461cd16ef76ab3d", size = 43621992, upload-time = "2025-01-11T00:03:04.53Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/d8/6e/a9c42d0d39e09ed7fd203d0ac17adfea759cba61ab457671fe66e523dbec/scipy-1.15.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c09aa9d90f3500ea4c9b393ee96f96b0ccb27f2f350d09a47f533293c78ea776", upload-time = "2025-01-11T00:01:53.571Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/04/ee/e3e535c81828618878a7433992fecc92fa4df79393f31a8fea1d05615091/scipy-1.15.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:0ac102ce99934b162914b1e4a6b94ca7da0f4058b6d6fd65b0cef330c0f3346f", upload-time = "2025-01-11T00:02:03.859Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/c4/5e/b1b0124be8e76f87115f16b8915003eec4b7060298117715baf13f51942c/scipy-1.15.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:09c52320c42d7f5c7748b69e9f0389266fd4f82cf34c38485c14ee976cb8cb04", upload-time = "2025-01-11T00:02:12.434Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/14/36/c00cb73eefda85946172c27913ab995c6ad4eee00fa4f007572e8c50cd51/scipy-1.15.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:cdde8414154054763b42b74fe8ce89d7f3d17a7ac5dd77204f0e142cdc9239e9", upload-time = "2025-01-11T00:02:20.237Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/68/94/aff5c51b3799349a9d1e67a056772a0f8a47db371e83b498d43467806557/scipy-1.15.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c9d8fc81d6a3b6844235e6fd175ee1d4c060163905a2becce8e74cb0d7554ce", upload-time = "2025-01-11T00:02:30.21Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/b0/3c/0de11ca154e24a57b579fb648151d901326d3102115bc4f9a7a86526ce54/scipy-1.15.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fb57b30f0017d4afa5fe5f5b150b8f807618819287c21cbe51130de7ccdaed2", upload-time = "2025-01-11T00:02:41.811Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/15/09/472e8d0a6b33199d1bb95e49bedcabc0976c3724edd9b0ef7602ccacf41e/scipy-1.15.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:491d57fe89927fa1aafbe260f4cfa5ffa20ab9f1435025045a5315006a91b8f5", upload-time = "2025-01-11T00:02:53.118Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/ff/ba/31c7a8131152822b3a2cdeba76398ffb404d81d640de98287d236da90c49/scipy-1.15.1-cp312-cp312-win_amd64.whl", hash = "sha256:900f3fa3db87257510f011c292a5779eb627043dd89731b9c461cd16ef76ab3d", upload-time = "2025-01-11T00:03:04.53Z" }, ] [[package]] name = "setuptools" version = "75.8.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d1/53/43d99d7687e8cdef5ab5f9ec5eaf2c0423c2b35133a2b7e7bc276fc32b21/setuptools-75.8.2.tar.gz", hash = "sha256:4880473a969e5f23f2a2be3646b2dfd84af9028716d398e46192f84bc36900d2", size = 1344083, upload-time = "2025-02-26T20:45:19.103Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/d1/53/43d99d7687e8cdef5ab5f9ec5eaf2c0423c2b35133a2b7e7bc276fc32b21/setuptools-75.8.2.tar.gz", hash = "sha256:4880473a969e5f23f2a2be3646b2dfd84af9028716d398e46192f84bc36900d2", upload-time = "2025-02-26T20:45:19.103Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/38/7d7362e031bd6dc121e5081d8cb6aa6f6fedf2b67bf889962134c6da4705/setuptools-75.8.2-py3-none-any.whl", hash = "sha256:558e47c15f1811c1fa7adbd0096669bf76c1d3f433f58324df69f3f5ecac4e8f", size = 1229385, upload-time = "2025-02-26T20:45:17.259Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/a9/38/7d7362e031bd6dc121e5081d8cb6aa6f6fedf2b67bf889962134c6da4705/setuptools-75.8.2-py3-none-any.whl", hash = "sha256:558e47c15f1811c1fa7adbd0096669bf76c1d3f433f58324df69f3f5ecac4e8f", upload-time = "2025-02-26T20:45:17.259Z" }, ] [[package]] name = "six" version = "1.17.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", upload-time = "2024-12-04T17:35:28.174Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", upload-time = "2024-12-04T17:35:26.475Z" }, ] [[package]] name = "tomli" version = "2.4.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543, upload-time = "2026-03-25T20:22:03.828Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", upload-time = "2026-03-25T20:22:03.828Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", size = 155924, upload-time = "2026-03-25T20:21:21.626Z" }, - { url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", size = 150018, upload-time = "2026-03-25T20:21:23.002Z" }, - { url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", size = 244948, upload-time = "2026-03-25T20:21:24.04Z" }, - { url = "https://files.pythonhosted.org/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", size = 253341, upload-time = "2026-03-25T20:21:25.177Z" }, - { url = "https://files.pythonhosted.org/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", size = 248159, upload-time = "2026-03-25T20:21:26.364Z" }, - { url = "https://files.pythonhosted.org/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", size = 253290, upload-time = "2026-03-25T20:21:27.46Z" }, - { url = "https://files.pythonhosted.org/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", size = 98141, upload-time = "2026-03-25T20:21:28.492Z" }, - { url = "https://files.pythonhosted.org/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", size = 108847, upload-time = "2026-03-25T20:21:29.386Z" }, - { url = "https://files.pythonhosted.org/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", size = 95088, upload-time = "2026-03-25T20:21:30.677Z" }, - { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", upload-time = "2026-03-25T20:21:21.626Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", upload-time = "2026-03-25T20:21:23.002Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", upload-time = "2026-03-25T20:21:24.04Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", upload-time = "2026-03-25T20:21:25.177Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", upload-time = "2026-03-25T20:21:26.364Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", upload-time = "2026-03-25T20:21:27.46Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", upload-time = "2026-03-25T20:21:28.492Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", upload-time = "2026-03-25T20:21:29.386Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", upload-time = "2026-03-25T20:21:30.677Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", upload-time = "2026-03-25T20:22:03.012Z" }, ] [[package]] name = "tomli-w" version = "1.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/19/75/241269d1da26b624c0d5e110e8149093c759b7a286138f4efd61a60e75fe/tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021", size = 7184, upload-time = "2025-01-15T12:07:24.262Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/19/75/241269d1da26b624c0d5e110e8149093c759b7a286138f4efd61a60e75fe/tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021", upload-time = "2025-01-15T12:07:24.262Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", size = 6675, upload-time = "2025-01-15T12:07:22.074Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", upload-time = "2025-01-15T12:07:22.074Z" }, ] [[package]] name = "typeapi" version = "2.3.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d5/92/5a23ad34aa877edf00906166e339bfdc571543ea183ea7ab727bb01516c7/typeapi-2.3.0.tar.gz", hash = "sha256:a60d11f72c5ec27338cfd1c807f035b0b16ed2e3b798fb1c1d34fc5589f544be", size = 122687, upload-time = "2025-10-23T13:44:11.26Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/d5/92/5a23ad34aa877edf00906166e339bfdc571543ea183ea7ab727bb01516c7/typeapi-2.3.0.tar.gz", hash = "sha256:a60d11f72c5ec27338cfd1c807f035b0b16ed2e3b798fb1c1d34fc5589f544be", upload-time = "2025-10-23T13:44:11.26Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/84/021bbeb7edb990dd6875cb6ab08d32faaa49fec63453d863730260a01f9e/typeapi-2.3.0-py3-none-any.whl", hash = "sha256:576b7dcb94412e91c5cae107a393674f8f99c10a24beb8be2302e3fed21d5cc2", size = 26858, upload-time = "2025-10-23T13:44:09.833Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/d4/84/021bbeb7edb990dd6875cb6ab08d32faaa49fec63453d863730260a01f9e/typeapi-2.3.0-py3-none-any.whl", hash = "sha256:576b7dcb94412e91c5cae107a393674f8f99c10a24beb8be2302e3fed21d5cc2", upload-time = "2025-10-23T13:44:09.833Z" }, ] [[package]] name = "typing-extensions" version = "4.15.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", upload-time = "2025-08-25T13:49:26.313Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", upload-time = "2025-08-25T13:49:24.86Z" }, ] [[package]] name = "typing-inspection" version = "0.4.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", upload-time = "2025-10-01T02:14:41.687Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", upload-time = "2025-10-01T02:14:40.154Z" }, ] [[package]] name = "tzdata" version = "2026.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/19/1b9b0e29f30c6d35cb345486df41110984ea67ae69dddbc0e8a100999493/tzdata-2026.2.tar.gz", hash = "sha256:9173fde7d80d9018e02a662e168e5a2d04f87c41ea174b139fbef642eda62d10", size = 198254, upload-time = "2026-04-24T15:22:08.651Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/ba/19/1b9b0e29f30c6d35cb345486df41110984ea67ae69dddbc0e8a100999493/tzdata-2026.2.tar.gz", hash = "sha256:9173fde7d80d9018e02a662e168e5a2d04f87c41ea174b139fbef642eda62d10", upload-time = "2026-04-24T15:22:08.651Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl", hash = "sha256:bbe9af844f658da81a5f95019480da3a89415801f6cc966806612cc7169bffe7", size = 349321, upload-time = "2026-04-24T15:22:05.876Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl", hash = "sha256:bbe9af844f658da81a5f95019480da3a89415801f6cc966806612cc7169bffe7", upload-time = "2026-04-24T15:22:05.876Z" }, ] [[package]] name = "urllib3" version = "2.6.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", upload-time = "2026-01-07T16:24:43.925Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", upload-time = "2026-01-07T16:24:42.685Z" }, ] [[package]] name = "virtualenv" version = "21.3.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "distlib" }, { name = "filelock" }, { name = "platformdirs" }, { name = "python-discovery" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3f/8b/6331f7a7fe70131c301106ec1e7cf23e2501bf7d4ca3636805801ca191bb/virtualenv-21.3.0.tar.gz", hash = "sha256:733750db978ec95c2d8eb4feadaa57091002bce404cb39ba69899cf7bd28944e", size = 7614069, upload-time = "2026-04-27T17:05:58.927Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/3f/8b/6331f7a7fe70131c301106ec1e7cf23e2501bf7d4ca3636805801ca191bb/virtualenv-21.3.0.tar.gz", hash = "sha256:733750db978ec95c2d8eb4feadaa57091002bce404cb39ba69899cf7bd28944e", upload-time = "2026-04-27T17:05:58.927Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/eb/03bfb1299d4c4510329e470f13f9a4ce793df7fcb5a2fd3510f911066f61/virtualenv-21.3.0-py3-none-any.whl", hash = "sha256:4d28ee41f6d9ec8f1f00cd472b9ffbcedda1b3d3b9a575b5c94a2d004fd51bd7", size = 7594690, upload-time = "2026-04-27T17:05:55.468Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/4b/eb/03bfb1299d4c4510329e470f13f9a4ce793df7fcb5a2fd3510f911066f61/virtualenv-21.3.0-py3-none-any.whl", hash = "sha256:4d28ee41f6d9ec8f1f00cd472b9ffbcedda1b3d3b9a575b5c94a2d004fd51bd7", upload-time = "2026-04-27T17:05:55.468Z" }, ] [[package]] name = "watchdog" version = "6.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", upload-time = "2024-11-01T14:07:13.037Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471, upload-time = "2024-11-01T14:06:37.745Z" }, - { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449, upload-time = "2024-11-01T14:06:39.748Z" }, - { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054, upload-time = "2024-11-01T14:06:41.009Z" }, - { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, - { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, - { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, - { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, - { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, - { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, - { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, - { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, - { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, - { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", upload-time = "2024-11-01T14:06:37.745Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", upload-time = "2024-11-01T14:06:39.748Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", upload-time = "2024-11-01T14:06:41.009Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", upload-time = "2024-11-01T14:06:59.472Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", upload-time = "2024-11-01T14:07:01.431Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", upload-time = "2024-11-01T14:07:02.568Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", upload-time = "2024-11-01T14:07:03.893Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", upload-time = "2024-11-01T14:07:05.189Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", upload-time = "2024-11-01T14:07:06.376Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", upload-time = "2024-11-01T14:07:07.547Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", upload-time = "2024-11-01T14:07:09.525Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", upload-time = "2024-11-01T14:07:10.686Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", upload-time = "2024-11-01T14:07:11.845Z" }, ] [[package]] name = "wrapt" version = "2.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2e/64/925f213fdcbb9baeb1530449ac71a4d57fc361c053d06bf78d0c5c7cd80c/wrapt-2.1.2.tar.gz", hash = "sha256:3996a67eecc2c68fd47b4e3c564405a5777367adfd9b8abb58387b63ee83b21e", size = 81678, upload-time = "2026-03-06T02:53:25.134Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/2e/64/925f213fdcbb9baeb1530449ac71a4d57fc361c053d06bf78d0c5c7cd80c/wrapt-2.1.2.tar.gz", hash = "sha256:3996a67eecc2c68fd47b4e3c564405a5777367adfd9b8abb58387b63ee83b21e", upload-time = "2026-03-06T02:53:25.134Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4c/b6/1db817582c49c7fcbb7df6809d0f515af29d7c2fbf57eb44c36e98fb1492/wrapt-2.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ff2aad9c4cda28a8f0653fc2d487596458c2a3f475e56ba02909e950a9efa6a9", size = 61255, upload-time = "2026-03-06T02:52:45.663Z" }, - { url = "https://files.pythonhosted.org/packages/a2/16/9b02a6b99c09227c93cd4b73acc3678114154ec38da53043c0ddc1fba0dc/wrapt-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6433ea84e1cfacf32021d2a4ee909554ade7fd392caa6f7c13f1f4bf7b8e8748", size = 61848, upload-time = "2026-03-06T02:53:48.728Z" }, - { url = "https://files.pythonhosted.org/packages/af/aa/ead46a88f9ec3a432a4832dfedb84092fc35af2d0ba40cd04aea3889f247/wrapt-2.1.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c20b757c268d30d6215916a5fa8461048d023865d888e437fab451139cad6c8e", size = 121433, upload-time = "2026-03-06T02:54:40.328Z" }, - { url = "https://files.pythonhosted.org/packages/3a/9f/742c7c7cdf58b59085a1ee4b6c37b013f66ac33673a7ef4aaed5e992bc33/wrapt-2.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79847b83eb38e70d93dc392c7c5b587efe65b3e7afcc167aa8abd5d60e8761c8", size = 123013, upload-time = "2026-03-06T02:53:26.58Z" }, - { url = "https://files.pythonhosted.org/packages/e8/44/2c3dd45d53236b7ed7c646fcf212251dc19e48e599debd3926b52310fafb/wrapt-2.1.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f8fba1bae256186a83d1875b2b1f4e2d1242e8fac0f58ec0d7e41b26967b965c", size = 117326, upload-time = "2026-03-06T02:53:11.547Z" }, - { url = "https://files.pythonhosted.org/packages/74/e2/b17d66abc26bd96f89dec0ecd0ef03da4a1286e6ff793839ec431b9fae57/wrapt-2.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e3d3b35eedcf5f7d022291ecd7533321c4775f7b9cd0050a31a68499ba45757c", size = 121444, upload-time = "2026-03-06T02:54:09.5Z" }, - { url = "https://files.pythonhosted.org/packages/3c/62/e2977843fdf9f03daf1586a0ff49060b1b2fc7ff85a7ea82b6217c1ae36e/wrapt-2.1.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:6f2c5390460de57fa9582bc8a1b7a6c86e1a41dfad74c5225fc07044c15cc8d1", size = 116237, upload-time = "2026-03-06T02:54:03.884Z" }, - { url = "https://files.pythonhosted.org/packages/88/dd/27fc67914e68d740bce512f11734aec08696e6b17641fef8867c00c949fc/wrapt-2.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7dfa9f2cf65d027b951d05c662cc99ee3bd01f6e4691ed39848a7a5fffc902b2", size = 120563, upload-time = "2026-03-06T02:53:20.412Z" }, - { url = "https://files.pythonhosted.org/packages/ec/9f/b750b3692ed2ef4705cb305bd68858e73010492b80e43d2a4faa5573cbe7/wrapt-2.1.2-cp312-cp312-win32.whl", hash = "sha256:eba8155747eb2cae4a0b913d9ebd12a1db4d860fc4c829d7578c7b989bd3f2f0", size = 58198, upload-time = "2026-03-06T02:53:37.732Z" }, - { url = "https://files.pythonhosted.org/packages/8e/b2/feecfe29f28483d888d76a48f03c4c4d8afea944dbee2b0cd3380f9df032/wrapt-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:1c51c738d7d9faa0b3601708e7e2eda9bf779e1b601dce6c77411f2a1b324a63", size = 60441, upload-time = "2026-03-06T02:52:47.138Z" }, - { url = "https://files.pythonhosted.org/packages/44/e1/e328f605d6e208547ea9fd120804fcdec68536ac748987a68c47c606eea8/wrapt-2.1.2-cp312-cp312-win_arm64.whl", hash = "sha256:c8e46ae8e4032792eb2f677dbd0d557170a8e5524d22acc55199f43efedd39bf", size = 58836, upload-time = "2026-03-06T02:53:22.053Z" }, - { url = "https://files.pythonhosted.org/packages/1a/c7/8528ac2dfa2c1e6708f647df7ae144ead13f0a31146f43c7264b4942bf12/wrapt-2.1.2-py3-none-any.whl", hash = "sha256:b8fd6fa2b2c4e7621808f8c62e8317f4aae56e59721ad933bac5239d913cf0e8", size = 43993, upload-time = "2026-03-06T02:53:12.905Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/4c/b6/1db817582c49c7fcbb7df6809d0f515af29d7c2fbf57eb44c36e98fb1492/wrapt-2.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ff2aad9c4cda28a8f0653fc2d487596458c2a3f475e56ba02909e950a9efa6a9", upload-time = "2026-03-06T02:52:45.663Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/a2/16/9b02a6b99c09227c93cd4b73acc3678114154ec38da53043c0ddc1fba0dc/wrapt-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6433ea84e1cfacf32021d2a4ee909554ade7fd392caa6f7c13f1f4bf7b8e8748", upload-time = "2026-03-06T02:53:48.728Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/af/aa/ead46a88f9ec3a432a4832dfedb84092fc35af2d0ba40cd04aea3889f247/wrapt-2.1.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c20b757c268d30d6215916a5fa8461048d023865d888e437fab451139cad6c8e", upload-time = "2026-03-06T02:54:40.328Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/3a/9f/742c7c7cdf58b59085a1ee4b6c37b013f66ac33673a7ef4aaed5e992bc33/wrapt-2.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79847b83eb38e70d93dc392c7c5b587efe65b3e7afcc167aa8abd5d60e8761c8", upload-time = "2026-03-06T02:53:26.58Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/e8/44/2c3dd45d53236b7ed7c646fcf212251dc19e48e599debd3926b52310fafb/wrapt-2.1.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f8fba1bae256186a83d1875b2b1f4e2d1242e8fac0f58ec0d7e41b26967b965c", upload-time = "2026-03-06T02:53:11.547Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/74/e2/b17d66abc26bd96f89dec0ecd0ef03da4a1286e6ff793839ec431b9fae57/wrapt-2.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e3d3b35eedcf5f7d022291ecd7533321c4775f7b9cd0050a31a68499ba45757c", upload-time = "2026-03-06T02:54:09.5Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/3c/62/e2977843fdf9f03daf1586a0ff49060b1b2fc7ff85a7ea82b6217c1ae36e/wrapt-2.1.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:6f2c5390460de57fa9582bc8a1b7a6c86e1a41dfad74c5225fc07044c15cc8d1", upload-time = "2026-03-06T02:54:03.884Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/88/dd/27fc67914e68d740bce512f11734aec08696e6b17641fef8867c00c949fc/wrapt-2.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7dfa9f2cf65d027b951d05c662cc99ee3bd01f6e4691ed39848a7a5fffc902b2", upload-time = "2026-03-06T02:53:20.412Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/ec/9f/b750b3692ed2ef4705cb305bd68858e73010492b80e43d2a4faa5573cbe7/wrapt-2.1.2-cp312-cp312-win32.whl", hash = "sha256:eba8155747eb2cae4a0b913d9ebd12a1db4d860fc4c829d7578c7b989bd3f2f0", upload-time = "2026-03-06T02:53:37.732Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/8e/b2/feecfe29f28483d888d76a48f03c4c4d8afea944dbee2b0cd3380f9df032/wrapt-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:1c51c738d7d9faa0b3601708e7e2eda9bf779e1b601dce6c77411f2a1b324a63", upload-time = "2026-03-06T02:52:47.138Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/44/e1/e328f605d6e208547ea9fd120804fcdec68536ac748987a68c47c606eea8/wrapt-2.1.2-cp312-cp312-win_arm64.whl", hash = "sha256:c8e46ae8e4032792eb2f677dbd0d557170a8e5524d22acc55199f43efedd39bf", upload-time = "2026-03-06T02:53:22.053Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/1a/c7/8528ac2dfa2c1e6708f647df7ae144ead13f0a31146f43c7264b4942bf12/wrapt-2.1.2-py3-none-any.whl", hash = "sha256:b8fd6fa2b2c4e7621808f8c62e8317f4aae56e59721ad933bac5239d913cf0e8", upload-time = "2026-03-06T02:53:12.905Z" }, ] [[package]] name = "yapf" version = "0.43.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } dependencies = [ { name = "platformdirs" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/23/97/b6f296d1e9cc1ec25c7604178b48532fa5901f721bcf1b8d8148b13e5588/yapf-0.43.0.tar.gz", hash = "sha256:00d3aa24bfedff9420b2e0d5d9f5ab6d9d4268e72afbf59bb3fa542781d5218e", size = 254907, upload-time = "2024-11-14T00:11:41.584Z" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/23/97/b6f296d1e9cc1ec25c7604178b48532fa5901f721bcf1b8d8148b13e5588/yapf-0.43.0.tar.gz", hash = "sha256:00d3aa24bfedff9420b2e0d5d9f5ab6d9d4268e72afbf59bb3fa542781d5218e", upload-time = "2024-11-14T00:11:41.584Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/37/81/6acd6601f61e31cfb8729d3da6d5df966f80f374b78eff83760714487338/yapf-0.43.0-py3-none-any.whl", hash = "sha256:224faffbc39c428cb095818cf6ef5511fdab6f7430a10783fdfb292ccf2852ca", size = 256158, upload-time = "2024-11-14T00:11:39.37Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/37/81/6acd6601f61e31cfb8729d3da6d5df966f80f374b78eff83760714487338/yapf-0.43.0-py3-none-any.whl", hash = "sha256:224faffbc39c428cb095818cf6ef5511fdab6f7430a10783fdfb292ccf2852ca", upload-time = "2024-11-14T00:11:39.37Z" }, ] [[package]] name = "zipp" version = "3.23.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/21/093488dfc7cc8964ded15ab726fad40f25fd3d788fd741cc1c5a17d78ee8/zipp-3.23.1.tar.gz", hash = "sha256:32120e378d32cd9714ad503c1d024619063ec28aad2248dc6672ad13edfa5110", size = 25965, upload-time = "2026-04-13T23:21:46.6Z" } +source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/30/21/093488dfc7cc8964ded15ab726fad40f25fd3d788fd741cc1c5a17d78ee8/zipp-3.23.1.tar.gz", hash = "sha256:32120e378d32cd9714ad503c1d024619063ec28aad2248dc6672ad13edfa5110", upload-time = "2026-04-13T23:21:46.6Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/08/8a/0861bec20485572fbddf3dfba2910e38fe249796cb73ecdeb74e07eeb8d3/zipp-3.23.1-py3-none-any.whl", hash = "sha256:0b3596c50a5c700c9cb40ba8d86d9f2cc4807e9bedb06bcdf7fac85633e444dc", size = 10378, upload-time = "2026-04-13T23:21:45.386Z" }, + { url = "https://pypi-proxy.cloud.databricks.com/packages/08/8a/0861bec20485572fbddf3dfba2910e38fe249796cb73ecdeb74e07eeb8d3/zipp-3.23.1-py3-none-any.whl", hash = "sha256:0b3596c50a5c700c9cb40ba8d86d9f2cc4807e9bedb06bcdf7fac85633e444dc", upload-time = "2026-04-13T23:21:45.386Z" }, ] From 41bd77c602922be362877de05009358c225a5314 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Br=C3=A4uer?= Date: Wed, 22 Jul 2026 13:24:14 +0200 Subject: [PATCH 2/8] added tests and documentation for mdf data sources --- Makefile | 6 + src/impulse_ds/mdf/QUICKSTART.md | 261 +++ src/impulse_ds/mdf/README.md | 175 +- src/impulse_ds/mdf/arrow_emit.py | 177 +- src/impulse_ds/mdf/bin_packer.py | 120 +- src/impulse_ds/mdf/converter.py | 26 +- src/impulse_ds/mdf/datasources.py | 2 + src/impulse_ds/mdf/mdf4_reader.py | 62 +- src/impulse_ds/mdf/mdf_blocks.py | 22 +- src/impulse_ds/mdf/mdf_decode.py | 108 ++ src/impulse_ds/mdf/udf_helpers.py | 5 + tests/impulse_ds/mdf/_block_fixtures.py | 171 ++ tests/impulse_ds/mdf/_mdf_samples.py | 46 +- tests/impulse_ds/mdf/test_arrow_emit.py | 150 ++ tests/impulse_ds/mdf/test_bin_packer.py | 129 ++ tests/impulse_ds/mdf/test_datasources.py | 106 ++ tests/impulse_ds/mdf/test_mdf4_reader.py | 95 +- tests/impulse_ds/mdf/test_mdf_blocks.py | 200 +++ .../impulse_ds/mdf/test_mdf_coverage_gaps.py | 1512 +++++++++++++++++ tests/impulse_ds/mdf/test_mdf_decode.py | 206 +++ tests/impulse_ds/mdf/test_mdf_package.py | 12 + tests/impulse_ds/mdf/test_unsorted_dg.py | 205 +++ 22 files changed, 3614 insertions(+), 182 deletions(-) create mode 100644 src/impulse_ds/mdf/QUICKSTART.md create mode 100644 tests/impulse_ds/mdf/_block_fixtures.py create mode 100644 tests/impulse_ds/mdf/test_arrow_emit.py create mode 100644 tests/impulse_ds/mdf/test_bin_packer.py create mode 100644 tests/impulse_ds/mdf/test_mdf_blocks.py create mode 100644 tests/impulse_ds/mdf/test_mdf_coverage_gaps.py create mode 100644 tests/impulse_ds/mdf/test_mdf_decode.py create mode 100644 tests/impulse_ds/mdf/test_mdf_package.py create mode 100644 tests/impulse_ds/mdf/test_unsorted_dg.py diff --git a/Makefile b/Makefile index 491a50e4..6b6f2687 100644 --- a/Makefile +++ b/Makefile @@ -34,6 +34,12 @@ coverage: $(UV_RUN) pytest tests/ --cov=src --cov-branch --cov-report=html open htmlcov/index.html +mdf-coverage: + $(UV_RUN) coverage run -m pytest tests/impulse_ds/mdf -q --no-cov + $(UV_RUN) coverage report --include='src/impulse_ds/mdf/*' \ + --omit='src/impulse_ds/mdf/converter.py' \ + --fail-under=95 --precision=1 + build: uv build --require-hashes --build-constraints=.build-constraints.txt diff --git a/src/impulse_ds/mdf/QUICKSTART.md b/src/impulse_ds/mdf/QUICKSTART.md new file mode 100644 index 00000000..1664e1aa --- /dev/null +++ b/src/impulse_ds/mdf/QUICKSTART.md @@ -0,0 +1,261 @@ +# MDF data sources — quickstart + +Read ASAM MDF4 files as Spark DataFrames. Install the `impulse_ds` package on the +cluster, then register the three data sources once per session. + +## Setup + +```python +from databricks.sdk import WorkspaceClient +from impulse_ds.mdf import register_mdf_datasources + +register_mdf_datasources(spark, WorkspaceClient()) +``` + +Set `path` to the directory that contains your `.mf4` files (discovered +recursively). To read specific files only, add `files` as a comma-separated list +(relative to `path`, or absolute paths). + +--- + +## `mdf_signals` — time-series samples + +One row per sample: `(file_uri, channel_id, time, value)`. + +```python +signals = ( + spark.read.format("mdf_signals") + .option("path", "/Volumes/catalog/schema/mdf_data") + .load() +) + +signals.select("file_uri", "channel_id", "time", "value").show(5) +``` + +Read a single file and use smaller on-disk types: + +```python +signals = ( + spark.read.format("mdf_signals") + .option("path", "/Volumes/catalog/schema/mdf_data") + .option("files", "run_001.mf4") + .option("time_dtype", "float32") + .option("value_dtype", "float32") + .load() +) +``` + +--- + + + +## `mdf_metadata` — channel catalog + +One row per signal channel: names, units, group indices, and comments. + +```python +metadata = ( + spark.read.format("mdf_metadata") + .option("path", "/Volumes/catalog/schema/mdf_data") + .load() +) + +metadata.select( + "file_uri", "channel_id", "channel_name", "unit", "header_datetime" +).show(5) +``` + +Join signals to metadata on `(file_uri, channel_id)` to get human-readable names: + +```python +( + signals.join(metadata, on=["file_uri", "channel_id"]) + .select("channel_name", "unit", "time", "value") + .show(5) +) +``` + +--- + + + +## `mdf_masters` — per-group time base + +One row per original master-channel sample: `(file_uri, group_idx, timestamp)`. +Use with run-length-encoded signals to recover the full per-sample grid (see +[README.md](README.md) for the join predicate). + +```python +masters = ( + spark.read.format("mdf_masters") + .option("path", "/Volumes/catalog/schema/mdf_data") + .load() +) + +masters.select("file_uri", "group_idx", "timestamp").show(5) +``` + +RLE signals plus masters (use the same `time_dtype` / `absolute_time` on both): + +```python +rle = ( + spark.read.format("mdf_signals") + .option("path", "/Volumes/catalog/schema/mdf_data") + .option("run_length_encoding", "true") + .load() +) + +masters = ( + spark.read.format("mdf_masters") + .option("path", "/Volumes/catalog/schema/mdf_data") + .load() +) + +# Expand intervals onto the master time grid (simplified; see README for full predicate). +from pyspark.sql import functions as F + +expanded = ( + rle.join(masters, on=["file_uri"]) + .where( + (F.col("timestamp") >= F.col("tstart")) + & ( + (F.col("timestamp") < F.col("tend")) + | ((F.col("tstart") == F.col("tend")) & (F.col("timestamp") == F.col("tstart"))) + ) + ) + .select("file_uri", "channel_id", "timestamp", "value") +) +``` + +--- + + + +## Write to Impulse silver layer + +Impulse's query engine expects five Delta tables defined in +`[impulse_query_engine/schema.py](../../impulse_query_engine/schema.py)`: + + +| Table | Role | +| ------------------- | ----------------------------------------------------------------------------------------------- | +| `container_tags` | Optional EAV tags per recording (`container_id`, `key`, `value`) | +| `container_metrics` | One row per recording (`container_id`, `start_dt`, `stop_dt`, …) | +| `channel_tags` | Optional EAV tags per channel (`container_id`, `channel_id`, `key`, `value`) | +| `channel_metrics` | Per-channel summary stats (`container_id`, `channel_id`, `min`, `max`, …) | +| `channels` | Sample data — RLE `(container_id, channel_id, tstart, tend, value)` or raw `(timestamp, value)` | + + +Assign one `container_id` per `.mf4` file. Keep all time columns in **seconds +since epoch** as floats — the same unit the MDF reader returns with +`absolute_time=true` (`tstart`, `tend`, `begin_s`, `end_s`). + +```python +from pyspark.sql import functions as F +import impulse_query_engine.schema as impulse_schema + +CATALOG = "my_catalog" +SCHEMA = "silver" +MDF_PATH = "/Volumes/catalog/schema/mdf_data" +CONTAINER_ID = 1 # one recording; use a mapping table when ingesting many files + +rle = ( + spark.read.format("mdf_signals") + .option("path", MDF_PATH) + .option("files", "run_001.mf4") + .option("run_length_encoding", "true") + .option("absolute_time", "true") + .load() + .withColumn("container_id", F.lit(CONTAINER_ID)) +) + +metadata = ( + spark.read.format("mdf_metadata") + .option("path", MDF_PATH) + .option("files", "run_001.mf4") + .load() + .withColumn("container_id", F.lit(CONTAINER_ID)) +) + +channels = rle.select( + "container_id", + F.col("channel_id").cast("int"), + F.col("tstart").cast("double"), + F.col("tend").cast("double"), + F.col("value").cast("double"), +) + +bounds = channels.agg( + F.min("tstart").alias("start_s"), + F.max("tend").alias("end_s"), + F.countDistinct("channel_id").alias("num_channels"), +) +container_metrics = bounds.select( + F.lit(CONTAINER_ID).alias("container_id"), + F.to_timestamp("start_s").alias("start_dt"), + F.to_timestamp("end_s").alias("stop_dt"), + ((F.col("end_s") - F.col("start_s")) * 1000).cast("int").alias("duration_ms"), + F.col("num_channels").cast("int"), +) + +container_tags = spark.createDataFrame( + [(CONTAINER_ID, "file_uri", f"{MDF_PATH}/run_001.mf4")], + schema=impulse_schema.CONTAINER_TAGS, +) + +channel_tags = metadata.select( + "container_id", + F.col("channel_id").cast("int"), + F.lit("channel_name").alias("key"), + F.col("channel_name").alias("value"), +) + +channel_metrics = ( + channels.groupBy("container_id", "channel_id") + .agg( + F.count("*").cast("int").alias("sample_count"), + F.min("value").cast("float").alias("min"), + F.max("value").cast("float").alias("max"), + F.avg("value").cast("float").alias("mean"), + F.min("tstart").cast("float").alias("begin_s"), + F.max("tend").cast("float").alias("end_s"), + ) + .withColumn("value_type", F.lit("numerical")) + .select( + "container_id", + F.col("channel_id").cast("int"), + "value_type", + "sample_count", + F.lit(None).cast("float").alias("nan_ratio"), + "begin_s", + "end_s", + F.lit(None).cast("int").alias("duration_ms"), + F.lit(None).cast("int").alias("original_sample_count"), + F.lit(None).cast("float").alias("original_sr"), + "min", + "max", + "mean", + F.lit(None).cast("float").alias("std"), + F.lit(None).cast("float").alias("pz1"), + F.lit(None).cast("float").alias("pz10"), + F.lit(None).cast("float").alias("pz90"), + F.lit(None).cast("float").alias("pz99"), + ) +) + +for name, df in [ + ("container_tags", container_tags), + ("container_metrics", container_metrics), + ("channel_tags", channel_tags), + ("channel_metrics", channel_metrics), + ("channels", channels), +]: + df.write.format("delta").mode("append").saveAsTable(f"{CATALOG}.{SCHEMA}.{name}") +``` + +Point a `MeasurementDB` at these tables (see the +[Impulse ingestion guide](../../../docs/impulse/docs/data_model/ingestion.md)) +and run reports with `DefaultSolver`. + +--- + diff --git a/src/impulse_ds/mdf/README.md b/src/impulse_ds/mdf/README.md index 0dd4d9e3..3d74e500 100644 --- a/src/impulse_ds/mdf/README.md +++ b/src/impulse_ds/mdf/README.md @@ -5,12 +5,21 @@ Databricks. The reader parses MDF4 binary blocks directly (no `asammdf` at runtime), so conversion parallelises across Spark workers, each reading only the bytes for its partition. -Every output row is identified by **`file_uri`** — the source file path. +Every output row is identified by `file_uri` — the source file path. + +**New to the data sources?** See [QUICKSTART.md](QUICKSTART.md) for minimal +examples of `mdf_signals`, `mdf_metadata`, and `mdf_masters`. + +## Solution Accelerator + +An end-to-end solution accelerator to convert mf4 files into the impulse schema will be available soon. ## Two ways to use it ### 1. Custom Spark data sources (read MDF4 as DataFrames) +See [QUICKSTART.md](QUICKSTART.md) for copy-paste examples of all three formats. + Requires the wheel installed on the cluster (the registered data-source workers import the package). @@ -26,17 +35,21 @@ signals = spark.read.format("mdf_signals").option("path", "/Volumes/.../mdf").lo **File selection** (`path` / `files` — shared by all three formats): -| behaviour | example | -|---|---| -| Recursive scan (default) | `.option("path", "/Volumes/.../mdf").load()` | -| Relative paths under `path` | `.option("path", "/data").option("files", "batch_a/run.mf4,run_b/other.mf4")` | -| Absolute file URIs (no scan) | `.option("path", "/data").option("files", "/mnt/a.mf4,/mnt/b.mf4")` | + +| behaviour | example | +| ---------------------------- | ----------------------------------------------------------------------------- | +| Recursive scan (default) | `.option("path", "/Volumes/.../mdf").load()` | +| Relative paths under `path` | `.option("path", "/data").option("files", "batch_a/run.mf4,run_b/other.mf4")` | +| Absolute file URIs (no scan) | `.option("path", "/data").option("files", "/mnt/a.mf4,/mnt/b.mf4")` | + When `files` is set, only the listed paths are read. Each entry may be absolute or relative to `path`; a mix of both in one list is allowed. #### Output schemas + + ##### `mdf_signals` One row per sample (default), or one row per constant-value interval when @@ -44,34 +57,44 @@ One row per sample (default), or one row per constant-value interval when (`float64` or `float32`); `absolute_time=true` forces time columns to `float64`. `value` follows `value_dtype` independently. -| column | Spark type | nullable | notes | -|---|---|---|---| -| `file_uri` | `string` | no | source `.mf4` path | -| `channel_id` | `int` | no | sequential signal id within the file | -| `time` | `double` or `float` | no | sample timestamp (relative seconds, or epoch seconds with `absolute_time`) | -| `value` | `double` or `float` | yes | decoded channel value | + +| column | Spark type | nullable | notes | +| ------------ | ------------------- | -------- | -------------------------------------------------------------------------- | +| `file_uri` | `string` | no | source `.mf4` path | +| `channel_id` | `int` | no | sequential signal id within the file | +| `time` | `double` or `float` | no | sample timestamp (relative seconds, or epoch seconds with `absolute_time`) | +| `value` | `double` or `float` | yes | decoded channel value | + With `run_length_encoding=true`, `time` is replaced by: -| column | Spark type | nullable | notes | -|---|---|---|---| -| `tstart` | `double` or `float` | no | start of a constant-value interval (inclusive) | -| `tend` | `double` or `float` | no | end of the interval (exclusive), except the terminal point row where `tstart = tend` | + +| column | Spark type | nullable | notes | +| -------- | ------------------- | -------- | ------------------------------------------------------------------------------------ | +| `tstart` | `double` or `float` | no | start of a constant-value interval (inclusive) | +| `tend` | `double` or `float` | no | end of the interval (exclusive), except the terminal point row where `tstart = tend` | + + + ##### `mdf_metadata` One row per signal channel. Schema is fixed (not affected by `time_dtype` / RLE options). -| column | Spark type | nullable | notes | -|---|---|---|---| -| `file_uri` | `string` | no | source `.mf4` path | -| `channel_id` | `int` | no | sequential signal id within the file | -| `group_idx` | `int` | no | MDF channel-group index | -| `channel_idx` | `int` | no | channel index within the group | -| `channel_name` | `string` | no | CN block name | -| `unit` | `string` | yes | physical unit, if present | -| `header_datetime` | `timestamp` | yes | measurement start time from the HD block (UTC) | -| `md_comment` | `string` | yes | CN comment block (`##MD` XML or `##TX` text), if present | + +| column | Spark type | nullable | notes | +| ----------------- | ----------- | -------- | -------------------------------------------------------- | +| `file_uri` | `string` | no | source `.mf4` path | +| `channel_id` | `int` | no | sequential signal id within the file | +| `group_idx` | `int` | no | MDF channel-group index | +| `channel_idx` | `int` | no | channel index within the group | +| `channel_name` | `string` | no | CN block name | +| `unit` | `string` | yes | physical unit, if present | +| `header_datetime` | `timestamp` | yes | measurement start time from the HD block (UTC) | +| `md_comment` | `string` | yes | CN comment block (`##MD` XML or `##TX` text), if present | + + + ##### `mdf_masters` @@ -80,35 +103,43 @@ group. Used with RLE-encoded `mdf_signals` to recover the full per-sample grid. `timestamp` follows `time_dtype` (`float64` or `float32`); `absolute_time=true` forces `float64`. -| column | Spark type | nullable | notes | -|---|---|---|---| -| `file_uri` | `string` | no | source `.mf4` path | -| `group_idx` | `int` | no | MDF channel-group index (matches `mdf_metadata.group_idx`) | -| `timestamp` | `double` or `float` | no | master time for one sample (relative seconds, or epoch seconds with `absolute_time`) | + +| column | Spark type | nullable | notes | +| ----------- | ------------------- | -------- | ------------------------------------------------------------------------------------ | +| `file_uri` | `string` | no | source `.mf4` path | +| `group_idx` | `int` | no | MDF channel-group index (matches `mdf_metadata.group_idx`) | +| `timestamp` | `double` or `float` | no | master time for one sample (relative seconds, or epoch seconds with `absolute_time`) | + **Shared options** (`mdf_signals`, `mdf_metadata`, `mdf_masters`): -| option | default | meaning | -|---|---|---| -| `path` | — (required) | root directory; used for recursive discovery and as the base for relative `files` entries | + +| option | default | meaning | +| ------- | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | +| `path` | — (required) | root directory; used for recursive discovery and as the base for relative `files` entries | | `files` | all `*.mf4` under `path` | comma-separated file list; each entry may be an absolute path or relative to `path`. When set, only these files are read (no directory scan) | -**`mdf_signals` / `mdf_masters` options** (in addition to the shared options above): -| option | default | meaning | -|---|---|---| -| `target_partition_mb` | 64 | target output size per Spark task | -| `partitioning` | `group` | `group` (per-channel-group) or `stripe` (byte-offset; reads each file once to build a block map) | -| `stripe_target_mb` | 128 | compressed bytes per stripe (stripe mode) | -| `max_groups_per_partition` | 64 | cap on small groups coalesced into one task | -| `time_dtype` / `value_dtype` | `float64` | `float32` halves a column's on-disk size | -| `run_length_encoding` | `false` | collapse constant runs into `[tstart, tend)` intervals (+ a terminal point row per channel) | -| `absolute_time` | `false` | add the MDF start time so timestamps are UTC epoch seconds (forces the time columns to `float64`) | +`mdf_signals` **/** `mdf_masters` **options** (in addition to the shared options above): + + +| option | default | meaning | +| ---------------------------- | --------- | ------------------------------------------------------------------------------------------------- | +| `target_partition_mb` | 64 | target output size per Spark task | +| `partitioning` | `group` | `group` (per-channel-group) or `stripe` (byte-offset; reads each file once to build a block map) | +| `stripe_target_mb` | 128 | compressed bytes per stripe (stripe mode) | +| `max_groups_per_partition` | 64 | cap on small groups coalesced into one task | +| `time_dtype` / `value_dtype` | `float64` | `float32` halves a column's on-disk size | +| `run_length_encoding` | `false` | collapse constant runs into `[tstart, tend)` intervals (+ a terminal point row per channel) | +| `absolute_time` | `false` | add the MDF start time so timestamps are UTC epoch seconds (forces the time columns to `float64`) | + > Reverse RLE: join RLE intervals against `mdf_masters` timestamps — > `t >= tstart AND (t < tend OR (tstart = tend AND t = tstart))` — using the same > `time_dtype`/`absolute_time` on both sources. + + #### Telemetry Call `register_mdf_datasources(spark, ws)` instead of registering the three data @@ -137,6 +168,8 @@ conv.convert("/Volumes/.../drive.mf4") # one file conv.convert_batch(["/Volumes/.../a.mf4", ...]) # many files, sequential ``` + + ### Low-level reader ```python @@ -146,39 +179,55 @@ org = r.scan_channels_organized() # masters / signals / channel_id_ma r.read_header_datetime() # measurement start (UTC) ``` + + ## Module layout Package path: `src/impulse_ds/mdf/` -| module | responsibility | -|---|---| -| `mdf4_reader.py` | parse MDF4 structure (HD/DG/CG/CN) → `ChannelInfo`; header datetime | -| `mdf_blocks.py` | low-level data-block I/O (`##DT`/`##DZ`/`##DL`/`##HL`, sub-blocks) | -| `mdf_decode.py` | raw-bytes → values/timestamps (data types, CC conversion, invalidation) | -| `arrow_emit.py` | build Arrow batches (per-group, stripe, master) + run-length encoding | -| `udf_helpers.py` | re-export shim over the three modules above (stable import surface) | -| `bin_packer.py` | partition planning (`plan_partitions`, `plan_stripes_for_file`, `plan_master_partitions`) | -| `converter.py` | `MDFToDeltaConverter` orchestration + Delta writes | -| `datasources.py` | the three Spark data sources | -| `schemas.py` | shared Spark schemas (`SIGNALS_SCHEMA`, `METADATA_SCHEMA`) | + +| module | responsibility | +| ---------------- | ----------------------------------------------------------------------------------------- | +| `mdf4_reader.py` | parse MDF4 structure (HD/DG/CG/CN) → `ChannelInfo`; header datetime | +| `mdf_blocks.py` | low-level data-block I/O (`##DT`/`##DZ`/`##DL`/`##HL`, sub-blocks) | +| `mdf_decode.py` | raw-bytes → values/timestamps (data types, CC conversion, invalidation) | +| `arrow_emit.py` | build Arrow batches (per-group, stripe, master) + run-length encoding | +| `udf_helpers.py` | re-export shim over the three modules above (stable import surface) | +| `bin_packer.py` | partition planning (`plan_partitions`, `plan_stripes_for_file`, `plan_master_partitions`) | +| `converter.py` | `MDFToDeltaConverter` orchestration + Delta writes | +| `datasources.py` | the three Spark data sources | +| `schemas.py` | shared Spark schemas (`SIGNALS_SCHEMA`, `METADATA_SCHEMA`) | + + + ## Limitations (backlog) Known gaps in the numeric-first reader/converter. **Sorted** data groups (`rec_id_size = 0`) -and CC types 0–2, 4–6 work as expected. +and CC types 0–2, 4–6 work as expected. **Unsorted** data groups (`rec_id_size > 0`) +with interleaved channel groups are supported via per-CG record filtering on read. + + +| area | severity | status | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------- | --------------------------- | +| **VLSD channels** — variable-length signals store an offset in the fixed record; payload in SDBLOCK is not followed. Channels currently emit NaN. String/byte output would need schema changes. | MEDIUM | not implemented | +| **CC type 3 (algebraic / formula)** — formula text in `cc_ref[0]` (TXBLOCK) is not read or evaluated; `apply_cc_conversion` has no handler for type 3. | LOW–MEDIUM | not implemented | +| **CC types 7–10 (text conversions)** — require TXBLOCK / `cc_ref` resolution. Unsupported by design for the numeric-only `value` column; `_parse_cc_block` returns `(-1, ())` for `cc_type > 6`. | LOW | not implemented (by design) | -| area | severity | status | -|---|---|---| -| **Unsorted data groups** — metadata scan records `rec_id_size` / `record_id` and offsets channel fields past the record-id prefix, but read paths (`read_channel_pair`, `arrow_emit`, converter UDF) still treat every record in a shared data block as belonging to one CG. For `rec_id_size > 0`, interleaved records are not filtered → wrong values. `rec_id_size` / `record_id` are also not passed through partition specs today. | MEDIUM | metadata only | -| **VLSD channels** — variable-length signals store an offset in the fixed record; payload in SDBLOCK is not followed. Channels currently emit NaN. String/byte output would need schema changes. | MEDIUM | not implemented | -| **CC type 3 (algebraic / formula)** — formula text in `cc_ref[0]` (TXBLOCK) is not read or evaluated; `apply_cc_conversion` has no handler for type 3. | LOW–MEDIUM | not implemented | -| **CC types 7–10 (text conversions)** — require TXBLOCK / `cc_ref` resolution. Unsupported by design for the numeric-only `value` column; `_parse_cc_block` returns `(-1, ())` for `cc_type > 6`. | LOW | not implemented (by design) | **CC types 7–10:** types 7, 8, 10 produce text (need a string extraction path / separate table); type 9 (text→value) could stay numeric but needs reference-text matching. -**Unsorted DGs:** fix requires per-CG record filtering in `mdf_decode` / `arrow_emit` / converter UDF, plus `rec_id_size`, `record_id`, and per-DG CG record sizes in partition specs. +**Unsorted DGs:** reads filter interleaved records by `record_id` before decode (`filter_unsorted_records` in `mdf_decode.py`). Stripe mode concatenates sub-blocks, then filters once per channel group. + +## Acknowledgments + +The MDF data sources and low-level reader were implemented with reference to +[asammdf](https://github.com/danielhrisca/asammdf) by [Daniel Hrisca](https://github.com/danielhrisca). +`asammdf` is not a runtime dependency of this package; it is listed under test +dependencies only (see below) for synthesising small MDF4 fixtures. ## Dependencies - Runtime: `numpy`, `pyarrow` (`pyspark` is provided by the Databricks runtime). - Tests: `pytest`, `asammdf` (dev/test dependency only — synthesises small MDF4 files on the fly). + diff --git a/src/impulse_ds/mdf/arrow_emit.py b/src/impulse_ds/mdf/arrow_emit.py index 5b721043..0c11a7c4 100644 --- a/src/impulse_ds/mdf/arrow_emit.py +++ b/src/impulse_ds/mdf/arrow_emit.py @@ -15,7 +15,7 @@ dt_data_extent, resolve_dl_addr, read_data_list_range, read_raw_data, _decompress_subblock_blob, _read_block_chunks, ) -from .mdf_decode import extract_signal, extract_timestamps +from .mdf_decode import extract_signal, extract_timestamps, prepare_cg_records def _pa_float(dtype): @@ -27,6 +27,56 @@ def _np_float(dtype): return np.float32 if str(dtype) == "float32" else np.float64 +def _unsorted_kwargs(ch_spec): + return { + "rec_id_size": ch_spec.get("rec_id_size", 0), + "record_id": ch_spec.get("record_id", 0), + "cg_record_sizes": ch_spec.get("cg_record_sizes"), + } + + +def _emit_prepared_signal_group( + raw_data, + group_channels, + record_size, + master_info, + time_offset, + emit_fn, + prof, + log, + data_block_addr, + _now, + index_offset=0, +): + """Decode one prepared (filtered/sliced) raw block for all channels in a CG.""" + actual = len(raw_data) // record_size if record_size else 0 + if actual == 0: + return + t0 = _now() + if master_info is not None: + timestamps = extract_timestamps( + raw_data, record_size, master_info, index_offset=index_offset, + ) + else: + timestamps = np.arange(index_offset, index_offset + actual, dtype=np.float64) + if time_offset: + timestamps = timestamps + time_offset + prof["decode"] += _now() - t0 + for ch_spec in group_channels: + try: + t0 = _now() + values = extract_signal(raw_data, record_size, ch_spec) + prof["decode"] += _now() - t0 + if values is None: + continue + yield from emit_fn(timestamps, values, ch_spec["channel_id"]) + except Exception as e: + log.warning( + "extract failed ch=%s block=%d: %s", + ch_spec.get("channel_id"), data_block_addr, e, + ) + + def _eq_nan(a, b): """Value equality for run-length encoding, treating NaN == NaN as equal so consecutive invalid samples collapse into a single run.""" @@ -329,13 +379,40 @@ def convert_spec_to_arrow_batches(spec, prof=None, time_dtype="float64", value_d for ch_spec in channels_spec: if ch_spec["sample_count"] == 0: continue - block_groups.setdefault(ch_spec["data_block_addr"], []).append(ch_spec) + block_groups.setdefault(ch_spec["group_idx"], []).append(ch_spec) with open(file_path, "rb") as f: - for data_block_addr, group_channels in block_groups.items(): - record_size = group_channels[0]["record_size"] - sample_count = group_channels[0]["sample_count"] - master_info = group_channels[0].get("master_info") + for _group_idx, group_channels in block_groups.items(): + ch0 = group_channels[0] + data_block_addr = ch0["data_block_addr"] + record_size = ch0["record_size"] + sample_count = ch0["sample_count"] + master_info = ch0.get("master_info") + rec_id_size = ch0.get("rec_id_size", 0) + us = _unsorted_kwargs(ch0) + + if rec_id_size > 0: + try: + t0 = _now() + raw_data = read_raw_data(f, data_block_addr, record_size, sample_count) + prof["read"] += _now() - t0 + except Exception as e: + log.warning("read_raw_data failed at %d in %s: %s", + data_block_addr, file_path, e) + continue + raw_data, index_offset = prepare_cg_records( + raw_data, + record_size=record_size, + row_start=spec_row_start, + row_end=spec_row_end, + **us, + ) + yield from _emit_prepared_signal_group( + raw_data, group_channels, record_size, master_info, + time_offset, emit_fn, prof, log, data_block_addr, _now, + index_offset=index_offset, + ) + continue try: extent = dt_data_extent(f, data_block_addr) @@ -451,36 +528,21 @@ def convert_spec_to_arrow_batches(spec, prof=None, time_dtype="float64", value_d if spec_row_start is not None: lo = max(0, min(spec_row_start, total)) hi = total if spec_row_end is None else max(lo, min(spec_row_end, total)) - raw_data = raw_data[lo * record_size:hi * record_size] - start_rec = lo - else: - start_rec = 0 - actual = len(raw_data) // record_size - if actual == 0: - continue - t0 = _now() - if master_info is not None: - timestamps = extract_timestamps( - raw_data, record_size, master_info, index_offset=start_rec) + raw_data, start_rec = prepare_cg_records( + raw_data, + record_size=record_size, + row_start=lo, + row_end=hi, + ) else: - timestamps = np.arange(start_rec, start_rec + actual, dtype=np.float64) - if time_offset: - timestamps = timestamps + time_offset - prof["decode"] += _now() - t0 - for ch_spec in group_channels: - try: - t0 = _now() - values = extract_signal(raw_data, record_size, ch_spec) - prof["decode"] += _now() - t0 - if values is None: - continue - yield from emit_fn( - timestamps, values, ch_spec["channel_id"], - ) - except Exception as e: - log.warning("extract failed ch=%s block=%d: %s", - ch_spec.get("channel_id"), data_block_addr, e) - continue + raw_data, start_rec = prepare_cg_records( + raw_data, record_size=record_size, + ) + yield from _emit_prepared_signal_group( + raw_data, group_channels, record_size, master_info, + time_offset, emit_fn, prof, log, data_block_addr, _now, + index_offset=start_rec, + ) # Drain state held across read chunks (RLE keeps one open trailing run # per channel; the per-sample path holds nothing, so this is a no-op). @@ -575,7 +637,11 @@ def _emit(ts, group_idx): continue for raw, start in _read_block_chunks( - f, mspec["data_block_addr"], rs, sc, r0, r1, prof, log): + f, mspec["data_block_addr"], rs, sc, r0, r1, prof, log, + rec_id_size=mspec.get("rec_id_size", 0), + record_id=mspec.get("record_id", 0), + cg_record_sizes=mspec.get("cg_record_sizes"), + ): t0 = _now() ts = extract_timestamps(raw, rs, minfo, index_offset=start) if time_offset: @@ -630,15 +696,44 @@ def convert_stripe_spec_to_arrow_batches(spec, prof=None, time_dtype="float64", blob = f.read(byte_end - byte_start) prof["read"] += _now() - t0 - by_grp = {} + by_gidx = {} for sb in subblocks: - by_grp.setdefault(sb["grp"], []).append(sb) + by_gidx.setdefault(sb["group_idx"], []).append(sb) - for grp, subs in by_grp.items(): - meta = groups[str(grp)] + for gidx, subs in by_gidx.items(): + meta = groups[str(gidx)] record_size = meta["record_size"] master_info = meta["master_info"] channels = meta["channels"] + rec_id_size = meta.get("rec_id_size", 0) + us = { + "rec_id_size": rec_id_size, + "record_id": meta.get("record_id", 0), + "cg_record_sizes": meta.get("cg_record_sizes"), + } + + if rec_id_size > 0: + parts = [] + for sb in sorted(subs, key=lambda x: x["abs_off"]): + rel = sb["abs_off"] - byte_start + try: + t0 = _now() + parts.append(_decompress_subblock_blob(blob, rel)) + prof["decode"] += _now() - t0 + except Exception as e: + log.warning("stripe decompress failed gidx=%s off=%d: %s", + gidx, sb["abs_off"], e) + if not parts: + continue + raw = b"".join(parts) + raw, index_offset = prepare_cg_records(raw, record_size=record_size, **us) + yield from _emit_prepared_signal_group( + raw, channels, record_size, master_info, time_offset, + emit_fn, prof, log, meta.get("data_block_addr", 0), _now, + index_offset=index_offset, + ) + continue + for sb in sorted(subs, key=lambda x: x["rec_start"]): rel = sb["abs_off"] - byte_start try: @@ -646,7 +741,7 @@ def convert_stripe_spec_to_arrow_batches(spec, prof=None, time_dtype="float64", raw = _decompress_subblock_blob(blob, rel) prof["decode"] += _now() - t0 except Exception as e: - log.warning("stripe decompress failed grp=%s off=%d: %s", grp, sb["abs_off"], e) + log.warning("stripe decompress failed gidx=%s off=%d: %s", gidx, sb["abs_off"], e) continue actual = len(raw) // record_size if record_size else 0 if actual == 0: diff --git a/src/impulse_ds/mdf/bin_packer.py b/src/impulse_ds/mdf/bin_packer.py index 184e3b28..46b00edd 100644 --- a/src/impulse_ds/mdf/bin_packer.py +++ b/src/impulse_ds/mdf/bin_packer.py @@ -10,6 +10,9 @@ from typing import Dict, List +from .mdf4_reader import MDF4Reader + + def plan_partitions( file_path: str, master_channels: dict, @@ -22,6 +25,7 @@ def plan_partitions( run_length_encoding: bool = False, max_groups_per_partition: int = 64, time_offset: float = 0.0, + unsorted_dg_ctx: dict = None, ) -> List[dict]: """ Plan Spark partitions for one MDF file, decoupling parallelism from channel @@ -63,36 +67,23 @@ def plan_partitions( signal_channels: [ChannelInfo], channel_id_map: {(group_idx, channel_idx): id}). """ target_rows = max(1, int(target_partition_mb * 1024 * 1024 / 16)) + ctx = unsorted_dg_ctx or {} groups: Dict[int, list] = {} for ch in signal_channels: - groups.setdefault(ch.data_block_addr, []).append(ch) + groups.setdefault(ch.group_idx, []).append(ch) def _master_info(group_idx): m = master_channels.get(group_idx) if not m: return None - return { - "byte_offset": m.byte_offset, "bit_offset": m.bit_offset, - "bit_count": m.bit_count, "data_type": m.data_type, - "channel_type": m.channel_type, "cc_type": m.cc_type, - "cc_params": list(m.cc_params) if m.cc_params else [], - } + return MDF4Reader.master_to_dict(m, ctx) def _ch_dict(ch): - return { - "channel_id": channel_id_map.get((ch.group_idx, ch.channel_idx), -1), - "group_idx": ch.group_idx, "channel_idx": ch.channel_idx, - "sample_count": ch.sample_count, "data_type": ch.data_type, - "bit_offset": ch.bit_offset, "byte_offset": ch.byte_offset, - "bit_count": ch.bit_count, "channel_type": ch.channel_type, - "data_block_addr": ch.data_block_addr, "record_size": ch.record_size, - "master_info": _master_info(ch.group_idx), "cn_flags": ch.cn_flags, - "invalidation_bit_pos": ch.invalidation_bit_pos, - "invalidation_bytes": ch.invalidation_bytes, "data_bytes": ch.data_bytes, - "cc_type": ch.cc_type, - "cc_params": list(ch.cc_params) if ch.cc_params else [], - } + d = MDF4Reader.channel_to_dict(ch, ctx) + d["channel_id"] = channel_id_map.get((ch.group_idx, ch.channel_idx), -1) + d["master_info"] = _master_info(ch.group_idx) + return d def _spec(ch_dicts, r0=None, r1=None): s = {"file_path": file_path, "channels": ch_dicts, @@ -124,7 +115,7 @@ def _flush_small(): pending_rows = 0 pending_groups = 0 - for chans in groups.values(): + for chans in sorted(groups.values(), key=lambda cs: cs[0].data_block_addr): c = len(chans) group_records = chans[0].sample_count if c == 0 or group_records == 0: @@ -167,6 +158,7 @@ def plan_master_partitions( time_dtype: str = "float64", max_groups_per_partition: int = 64, time_offset: float = 0.0, + unsorted_dg_ctx: dict = None, ) -> List[dict]: """ Plan Spark partitions for the MASTER channels of one MDF file — the time @@ -186,20 +178,20 @@ def plan_master_partitions( row_start/row_end). Groups without a master are simply absent from the input. """ target_rows = max(1, int(target_partition_mb * 1024 * 1024 / 16)) + ctx = unsorted_dg_ctx or {} def _master_entry(group_idx, m): - return { + from .mdf_decode import unsorted_fields_from_ctx + + entry = { "group_idx": group_idx, "data_block_addr": m.data_block_addr, "record_size": m.record_size, "sample_count": m.sample_count, - "master_info": { - "byte_offset": m.byte_offset, "bit_offset": m.bit_offset, - "bit_count": m.bit_count, "data_type": m.data_type, - "channel_type": m.channel_type, "cc_type": m.cc_type, - "cc_params": list(m.cc_params) if m.cc_params else [], - }, + "master_info": MDF4Reader.master_to_dict(m, ctx), } + entry.update(unsorted_fields_from_ctx(m.dg_block_addr, m.record_id, ctx)) + return entry def _spec(masters, r0=None, r1=None): s = {"file_path": file_path, @@ -278,10 +270,12 @@ def plan_stripes_for_file( if file_bytes is None: with open(file_path, "rb") as fh: file_bytes = fh.read() - organized = MDF4Reader(file_bytes=file_bytes).scan_channels_organized() + reader = MDF4Reader(file_bytes=file_bytes) + organized = reader.scan_channels_organized() master_channels = organized["master_channels"] signal_channels = organized["signal_channels"] channel_id_map = organized["channel_id_map"] + unsorted_dg_ctx = organized.get("unsorted_dg_ctx") or {} target_rows = max(1, int(target_partition_mb * 1024 * 1024 / 16)) stripe_bytes_cap = int(stripe_target_mb * 1024 * 1024) @@ -291,49 +285,50 @@ def _minfo(group_idx): m = master_channels.get(group_idx) if not m: return None - return { - "byte_offset": m.byte_offset, "bit_offset": m.bit_offset, - "bit_count": m.bit_count, "data_type": m.data_type, - "channel_type": m.channel_type, "cc_type": m.cc_type, - "cc_params": list(m.cc_params) if m.cc_params else [], - } + return MDF4Reader.master_to_dict(m, unsorted_dg_ctx) def _chd(ch): - return { - "channel_id": channel_id_map.get((ch.group_idx, ch.channel_idx), -1), - "group_idx": ch.group_idx, "channel_idx": ch.channel_idx, - "sample_count": ch.sample_count, "data_type": ch.data_type, - "bit_offset": ch.bit_offset, "byte_offset": ch.byte_offset, - "bit_count": ch.bit_count, "channel_type": ch.channel_type, - "data_block_addr": ch.data_block_addr, "record_size": ch.record_size, - "cn_flags": ch.cn_flags, "invalidation_bit_pos": ch.invalidation_bit_pos, - "invalidation_bytes": ch.invalidation_bytes, "data_bytes": ch.data_bytes, - "cc_type": ch.cc_type, - "cc_params": list(ch.cc_params) if ch.cc_params else [], - } + d = MDF4Reader.channel_to_dict(ch, unsorted_dg_ctx) + d["channel_id"] = channel_id_map.get((ch.group_idx, ch.channel_idx), -1) + return d bio = io.BytesIO(file_bytes) - by_block = {} + by_group: Dict[int, list] = {} for ch in signal_channels: - by_block.setdefault(ch.data_block_addr, []).append(ch) + by_group.setdefault(ch.group_idx, []).append(ch) groups_meta = {} subblocks = [] - for addr, chans in by_block.items(): - rs = chans[0].record_size - sc = chans[0].sample_count - gi = chans[0].group_idx + for group_idx, chans in by_group.items(): + ch0 = chans[0] + rs = ch0.record_size + sc = ch0.sample_count if rs == 0 or sc == 0: continue - groups_meta[addr] = { - "record_size": rs, "master_info": _minfo(gi), - "channels": [_chd(c) for c in chans], "n_channels": len(chans), + from .mdf_decode import unsorted_fields_from_ctx + + meta = { + "group_idx": group_idx, + "data_block_addr": ch0.data_block_addr, + "record_size": rs, + "master_info": _minfo(group_idx), + "channels": [_chd(c) for c in chans], + "n_channels": len(chans), + "sample_count": sc, } - for (soff, slen, rstart, rcount) in parse_subblocks(bio, addr, rs, sc): - if rcount <= 0: + meta.update(unsorted_fields_from_ctx(ch0.dg_block_addr, ch0.record_id, unsorted_dg_ctx)) + groups_meta[group_idx] = meta + for (soff, slen, rstart, rcount) in parse_subblocks(bio, ch0.data_block_addr, rs, sc): + if rcount <= 0 and slen <= 0: continue - subblocks.append({"grp": addr, "abs_off": soff, "on_disk_len": slen, - "rec_start": rstart, "rec_count": rcount}) + subblocks.append({ + "group_idx": group_idx, + "grp": ch0.data_block_addr, + "abs_off": soff, + "on_disk_len": slen, + "rec_start": rstart, + "rec_count": rcount, + }) subblocks.sort(key=lambda s: s["abs_off"]) @@ -357,7 +352,8 @@ def _flush(): cur = []; cur_rows = cur_bytes = 0; cur_lo = cur_hi = None; cur_grps = set() for sb in subblocks: - rows = sb["rec_count"] * groups_meta[sb["grp"]]["n_channels"] + gidx = sb["group_idx"] + rows = sb["rec_count"] * groups_meta[gidx]["n_channels"] gap = (sb["abs_off"] - cur_hi) if cur_hi is not None else 0 if cur and (cur_rows + rows > target_rows or cur_bytes + sb["on_disk_len"] > stripe_bytes_cap @@ -367,7 +363,7 @@ def _flush(): cur.append(sb) cur_rows += rows cur_bytes += sb["on_disk_len"] - cur_grps.add(sb["grp"]) + cur_grps.add(gidx) end = sb["abs_off"] + sb["on_disk_len"] cur_lo = sb["abs_off"] if cur_lo is None else min(cur_lo, sb["abs_off"]) cur_hi = end if cur_hi is None else max(cur_hi, end) diff --git a/src/impulse_ds/mdf/converter.py b/src/impulse_ds/mdf/converter.py index 6574ae3b..943e2fe7 100644 --- a/src/impulse_ds/mdf/converter.py +++ b/src/impulse_ds/mdf/converter.py @@ -161,7 +161,9 @@ def convert( # Step 4: Plan record-range / channel-subset partitions partition_specs = self._plan( - file_path, master_channels, signal_channels, channel_id_map) + file_path, master_channels, signal_channels, channel_id_map, + unsorted_dg_ctx=reader._unsorted_dg_ctx, + ) # Step 5: Run distributed conversion total_samples = sum(ch.sample_count for ch in signal_channels) @@ -223,7 +225,14 @@ def _metadata_rows(self, signal_channels, channel_id_map, file_uri, header_datet for ch in signal_channels ] - def _plan(self, file_path, master_channels, signal_channels, channel_id_map): + def _plan( + self, + file_path, + master_channels, + signal_channels, + channel_id_map, + unsorted_dg_ctx=None, + ): """Plan partition specs for one file using this converter's settings. Shared by convert() and convert_batch_parallel().""" return plan_partitions( @@ -232,6 +241,7 @@ def _plan(self, file_path, master_channels, signal_channels, channel_id_map): time_dtype=self.time_dtype, value_dtype=self.value_dtype, run_length_encoding=self.run_length_encoding, max_groups_per_partition=self.max_groups_per_partition, + unsorted_dg_ctx=unsorted_dg_ctx, ) def _write_metadata( @@ -340,7 +350,11 @@ def convert_batch_parallel( def _scan(idx_path): idx, fp = idx_path reader = MDF4Reader(fp) - return idx, fp, reader.scan_metadata(), reader.read_header_datetime() + channels = reader.scan_metadata() + return ( + idx, fp, channels, reader.read_header_datetime(), + reader._unsorted_dg_ctx, + ) max_workers = min(16, max(1, len(file_paths))) with ThreadPoolExecutor(max_workers=max_workers) as ex: @@ -349,7 +363,7 @@ def _scan(idx_path): key=lambda r: r[0], ) - for i, file_path, all_channels_in_file, header_datetime in scanned: + for i, file_path, all_channels_in_file, header_datetime, unsorted_ctx in scanned: if not all_channels_in_file: continue @@ -360,7 +374,9 @@ def _scan(idx_path): all_metadata_rows.extend(self._metadata_rows( signal_channels, channel_id_map, file_path, header_datetime)) all_partition_specs.extend(self._plan( - file_path, master_channels, signal_channels, channel_id_map)) + file_path, master_channels, signal_channels, channel_id_map, + unsorted_dg_ctx=unsorted_ctx, + )) total_channels += len(signal_channels) total_samples += sum(ch.sample_count for ch in signal_channels) diff --git a/src/impulse_ds/mdf/datasources.py b/src/impulse_ds/mdf/datasources.py index 0e551d76..a43d54ee 100644 --- a/src/impulse_ds/mdf/datasources.py +++ b/src/impulse_ds/mdf/datasources.py @@ -257,6 +257,7 @@ def partitions(self): run_length_encoding=run_length_encoding, max_groups_per_partition=max_groups_per_partition, time_offset=time_offset, + unsorted_dg_ctx=organized.get("unsorted_dg_ctx"), ) all_partition_specs.extend(json.dumps(s) for s in specs) @@ -458,6 +459,7 @@ def partitions(self): time_dtype=time_dtype, max_groups_per_partition=max_groups_per_partition, time_offset=time_offset, + unsorted_dg_ctx=organized.get("unsorted_dg_ctx"), ) all_specs.extend(json.dumps(s) for s in specs) diff --git a/src/impulse_ds/mdf/mdf4_reader.py b/src/impulse_ds/mdf/mdf4_reader.py index 249dcb8f..9f600407 100644 --- a/src/impulse_ds/mdf/mdf4_reader.py +++ b/src/impulse_ds/mdf/mdf4_reader.py @@ -127,6 +127,7 @@ def __init__(self, file_path: str = None, file_bytes: "bytes" = None): self.file_path = file_path self._file_bytes = file_bytes self._data_groups: Optional[List[DataGroupInfo]] = None + self._unsorted_dg_ctx: Dict[int, dict] = {} self._text_cache: Dict[int, str] = {} # address -> TX/MD text (immutable per file) def _open(self): @@ -293,6 +294,7 @@ def scan_metadata(self) -> List[ChannelInfo]: reading actual signal data. Returns list of ChannelInfo objects. """ channels = [] + self._unsorted_dg_ctx = {} with self._open() as f: # Verify MDF4 signature f.seek(0) @@ -339,6 +341,7 @@ def scan_metadata(self) -> List[ChannelInfo]: dg_rec_id_size = struct.unpack(" List[ChannelInfo]: cg_invalidation_bytes = struct.unpack(" 0: + from .mdf_decode import storage_record_id + dg_cg_sizes[storage_record_id(cg_record_id, dg_rec_id_size)] = record_size # Traverse CN linked list channel_idx = 0 @@ -465,6 +471,12 @@ def scan_metadata(self) -> List[ChannelInfo]: cg_addr = next_cg_addr group_idx += 1 + if dg_rec_id_size > 0: + self._unsorted_dg_ctx[dg_addr] = { + "rec_id_size": dg_rec_id_size, + "cg_sizes": dg_cg_sizes, + } + dg_addr = next_dg_addr return channels @@ -486,6 +498,9 @@ def read_channel_data( data_bytes: int = 0, cc_type: int = -1, cc_params: tuple = (), + rec_id_size: int = 0, + record_id: int = 0, + cg_record_sizes: Optional[dict] = None, f: Optional[BinaryIO] = None, ) -> np.ndarray: """ @@ -499,7 +514,7 @@ def read_channel_data( This delegates to the executor-side decode functions in udf_helpers so that this reference API exercises the exact code path used in Spark. """ - from .udf_helpers import read_raw_data, extract_signal + from .udf_helpers import read_raw_data, extract_signal, prepare_cg_records ch_spec = { "channel_type": channel_type, @@ -517,6 +532,13 @@ def read_channel_data( } def _extract(raw_data): + raw_data, _ = prepare_cg_records( + raw_data, + record_size=record_size, + rec_id_size=rec_id_size, + record_id=record_id, + cg_record_sizes=cg_record_sizes, + ) if not raw_data or record_size <= 0: return np.array([], dtype=np.float64) values = extract_signal(raw_data, record_size, ch_spec) @@ -550,21 +572,35 @@ def read_channel_pair( opening the file again. """ from .udf_helpers import ( - read_raw_data, extract_signal, extract_timestamps, + read_raw_data, extract_signal, extract_timestamps, prepare_cg_records, ) def _do_read(fh: BinaryIO) -> Tuple[np.ndarray, np.ndarray]: data_block_addr = signal_info["data_block_addr"] record_size = signal_info["record_size"] + rec_id_size = signal_info.get("rec_id_size", 0) + record_id = signal_info.get("record_id", 0) + cg_record_sizes = signal_info.get("cg_record_sizes") # Read the raw data block once (shared between master and signal) raw_data = read_raw_data(fh, data_block_addr, record_size, sample_count) + raw_data, index_offset = prepare_cg_records( + raw_data, + record_size=record_size, + rec_id_size=rec_id_size, + record_id=record_id, + cg_record_sizes=cg_record_sizes, + ) actual_samples = len(raw_data) // record_size if record_size else 0 if master_info: - timestamps = extract_timestamps(raw_data, record_size, master_info) + timestamps = extract_timestamps( + raw_data, record_size, master_info, index_offset=index_offset, + ) else: - timestamps = np.arange(actual_samples, dtype=np.float64) + timestamps = np.arange( + index_offset, index_offset + actual_samples, dtype=np.float64, + ) values = extract_signal(raw_data, record_size, signal_info) if values is None: @@ -606,12 +642,15 @@ def scan_channels_organized(self) -> dict: "master_channels": master_channels, "signal_channels": signal_channels, "channel_id_map": channel_id_map, + "unsorted_dg_ctx": dict(self._unsorted_dg_ctx), } @staticmethod - def channel_to_dict(ch: "ChannelInfo") -> dict: + def channel_to_dict(ch: "ChannelInfo", unsorted_dg_ctx: Optional[dict] = None) -> dict: """Convert a ChannelInfo to a serializable dict suitable for bin packing.""" - return { + from .mdf_decode import unsorted_fields_from_ctx + + d = { "group_idx": ch.group_idx, "channel_idx": ch.channel_idx, "sample_count": ch.sample_count, @@ -630,12 +669,17 @@ def channel_to_dict(ch: "ChannelInfo") -> dict: "data_bytes": ch.data_bytes, "cc_type": ch.cc_type, "cc_params": list(ch.cc_params) if ch.cc_params else [], + "dg_block_addr": ch.dg_block_addr, } + d.update(unsorted_fields_from_ctx(ch.dg_block_addr, ch.record_id, unsorted_dg_ctx or {})) + return d @staticmethod - def master_to_dict(ch: "ChannelInfo") -> dict: + def master_to_dict(ch: "ChannelInfo", unsorted_dg_ctx: Optional[dict] = None) -> dict: """Convert a master ChannelInfo to a serializable dict for timestamp extraction.""" - return { + from .mdf_decode import unsorted_fields_from_ctx + + d = { "byte_offset": ch.byte_offset, "bit_offset": ch.bit_offset, "bit_count": ch.bit_count, @@ -644,3 +688,5 @@ def master_to_dict(ch: "ChannelInfo") -> dict: "cc_type": ch.cc_type, "cc_params": list(ch.cc_params) if ch.cc_params else [], } + d.update(unsorted_fields_from_ctx(ch.dg_block_addr, ch.record_id, unsorted_dg_ctx or {})) + return d diff --git a/src/impulse_ds/mdf/mdf_blocks.py b/src/impulse_ds/mdf/mdf_blocks.py index 1d611cba..80caa169 100644 --- a/src/impulse_ds/mdf/mdf_blocks.py +++ b/src/impulse_ds/mdf/mdf_blocks.py @@ -289,7 +289,8 @@ def dt_data_extent(f, data_block_addr): def _read_block_chunks(f, data_block_addr, record_size, sample_count, - row_start, row_end, prof, log): + row_start, row_end, prof, log, + rec_id_size=0, record_id=0, cg_record_sizes=None): """Yield (raw_bytes, start_record) for records [row_start, row_end) of one data block, using the SAME read strategy as the signals core: stream an uncompressed ##DT in record-aligned chunks, read only the overlapping @@ -297,9 +298,28 @@ def _read_block_chunks(f, data_block_addr, record_size, sample_count, slice. row_start/row_end None => the whole block. Shared by the master decoder so it inherits the streaming/coalescing behaviour without duplicating it.""" import time + from .mdf_decode import prepare_cg_records + _now = time.perf_counter_ns _CHUNK_BYTES = 256 * 1024 * 1024 + if rec_id_size > 0: + t0 = _now() + raw = read_raw_data(f, data_block_addr, record_size, sample_count) + prof["read"] += _now() - t0 + raw, start = prepare_cg_records( + raw, + record_size=record_size, + rec_id_size=rec_id_size, + record_id=record_id, + cg_record_sizes=cg_record_sizes, + row_start=row_start, + row_end=row_end, + ) + if record_size and len(raw) // record_size: + yield raw, start + return + try: extent = dt_data_extent(f, data_block_addr) except Exception as e: diff --git a/src/impulse_ds/mdf/mdf_decode.py b/src/impulse_ds/mdf/mdf_decode.py index a34dd7ce..62380ebf 100644 --- a/src/impulse_ds/mdf/mdf_decode.py +++ b/src/impulse_ds/mdf/mdf_decode.py @@ -3,6 +3,9 @@ interpretation, CC (channel conversion) scaling, and invalidation-bit handling. Vectorised with numpy; no file I/O. """ +import struct +from typing import Dict, Optional, Tuple, Union + import numpy as np @@ -217,6 +220,111 @@ def apply_cc_conversion(values, cc_type, cc_params): return values +_RECORD_ID_FMT = {1: " int: + """Return the record ID as stored in the leading bytes of each unsorted record.""" + if rec_id_size <= 0: + return 0 + if rec_id_size >= 8: + return record_id + mask = (1 << (8 * rec_id_size)) - 1 + return record_id & mask + + +def read_record_id(buf: Union[bytes, memoryview], offset: int, rec_id_size: int) -> int: + """Read a little-endian unsigned record ID from ``buf`` at ``offset``.""" + if rec_id_size <= 0: + return 0 + fmt = _RECORD_ID_FMT.get(rec_id_size) + if fmt is None: + raise ValueError(f"Unsupported rec_id_size: {rec_id_size}") + return struct.unpack_from(fmt, buf, offset)[0] + + +def filter_unsorted_records( + raw_data: bytes, + rec_id_size: int, + target_record_id: int, + cg_record_sizes: Dict[int, int], +) -> bytes: + """Extract records belonging to ``target_record_id`` from an interleaved block.""" + if rec_id_size <= 0: + return raw_data + target_record_id = storage_record_id(target_record_id, rec_id_size) + out = bytearray() + pos = 0 + n = len(raw_data) + while pos < n: + if pos + rec_id_size > n: + break + rid = read_record_id(raw_data, pos, rec_id_size) + rec_size = cg_record_sizes.get(rid) + if rec_size is None: + break + if pos + rec_size > n: + break + if rid == target_record_id: + out.extend(raw_data[pos:pos + rec_size]) + pos += rec_size + return bytes(out) + + +def prepare_cg_records( + raw_data: bytes, + *, + record_size: int, + rec_id_size: int = 0, + record_id: int = 0, + cg_record_sizes: Optional[Dict[int, int]] = None, + row_start: Optional[int] = None, + row_end: Optional[int] = None, +) -> Tuple[bytes, int]: + """Filter unsorted interleaved records and optionally slice by logical row range. + + Returns ``(prepared_bytes, index_offset)`` where ``index_offset`` is the + logical sample index of the first record (for virtual masters). + """ + if rec_id_size > 0: + if not cg_record_sizes: + return b"", 0 + # JSON partition specs stringify dict keys; normalize back to int. + cg_sizes = {int(k): v for k, v in cg_record_sizes.items()} + raw_data = filter_unsorted_records( + raw_data, rec_id_size, record_id, cg_sizes, + ) + + if record_size <= 0: + return b"", 0 + + actual = len(raw_data) // record_size + if actual == 0: + return b"", 0 + + lo = 0 if row_start is None else max(0, min(row_start, actual)) + hi = actual if row_end is None else max(lo, min(row_end, actual)) + if hi <= lo: + return b"", lo + + start = lo * record_size + end = hi * record_size + return raw_data[start:end], lo + + +def unsorted_fields_from_ctx(dg_block_addr: int, record_id: int, unsorted_dg_ctx: dict) -> dict: + """Build unsorted read kwargs from scan-time DG context and channel record_id.""" + ctx = unsorted_dg_ctx.get(dg_block_addr) if unsorted_dg_ctx else None + if not ctx or ctx.get("rec_id_size", 0) == 0: + return {"rec_id_size": 0, "record_id": 0, "cg_record_sizes": None} + rec_id_size = ctx["rec_id_size"] + return { + "rec_id_size": rec_id_size, + "record_id": storage_record_id(record_id, rec_id_size), + "cg_record_sizes": ctx["cg_sizes"], + } + + def extract_signal(raw_data, record_size, ch_spec): """Extract and convert a signal channel from raw data.""" actual = len(raw_data) // record_size diff --git a/src/impulse_ds/mdf/udf_helpers.py b/src/impulse_ds/mdf/udf_helpers.py index 0df05d58..d9243839 100644 --- a/src/impulse_ds/mdf/udf_helpers.py +++ b/src/impulse_ds/mdf/udf_helpers.py @@ -30,6 +30,11 @@ apply_cc_conversion, extract_signal, extract_timestamps, + read_record_id, + storage_record_id, + filter_unsorted_records, + prepare_cg_records, + unsorted_fields_from_ctx, FLOAT_LE, FLOAT_BE, UINT_LE, UINT_BE, SINT_LE, SINT_BE, CC_IDENTITY, CC_LINEAR, CC_RATIONAL, CC_ALGEBRAIC, CC_TAB_INTERP, CC_TAB_NOINTERP, CC_RANGE_TO_VALUE, diff --git a/tests/impulse_ds/mdf/_block_fixtures.py b/tests/impulse_ds/mdf/_block_fixtures.py new file mode 100644 index 00000000..43e37af1 --- /dev/null +++ b/tests/impulse_ds/mdf/_block_fixtures.py @@ -0,0 +1,171 @@ +"""Hand-built MDF4 data-block bytes for unit tests (DT/DZ/DL/HL).""" + +from __future__ import annotations + +import io +import struct +import zlib +from typing import List, Tuple + +import numpy as np + + +def make_dt_block(payload: bytes) -> bytes: + """Build a ##DT block containing ``payload``.""" + length = 24 + len(payload) + return b"##DT" + b"\x00" * 4 + struct.pack(" bytes: + """Build a ##DZ block; ``zip_type=1`` stores payload column-major before zlib.""" + to_compress = payload + if zip_type == 1: + cols = zip_parameter + arr = np.frombuffer(payload, dtype=np.uint8) + rows = len(arr) // cols + remainder = len(arr) % cols + if remainder == 0: + to_compress = arr.reshape(rows, cols).T.tobytes() + else: + col_major = bytearray() + for col in range(cols): + col_size = rows + (1 if col < remainder else 0) + for row in range(col_size): + col_major.append(arr[row * cols + col]) + to_compress = bytes(col_major) + compressed = zlib.compress(to_compress) + org_size = len(payload) + data_length = len(compressed) + length = 48 + data_length + header = ( + b"##DZ" + + b"\x00" * 4 + + struct.pack(" bytes: + """Build a ##DL block pointing at ``data_addrs`` (link 0 = next_dl).""" + dl_count = len(data_addrs) + link_count = 1 + dl_count + links = struct.pack(f"<{link_count}Q", next_dl, *data_addrs) + body = links + b"\x00" + b"\x00" * 3 + struct.pack(" bytes: + """Build a ##HL block whose first link points at ``dl_addr``.""" + link_count = 1 + length = 24 + 8 * link_count + return ( + b"##HL" + + b"\x00" * 4 + + struct.pack(" Tuple[bytes, int]: + """Lay out DT sub-blocks + DL (optionally HL) in one buffer. + + Returns ``(file_bytes, data_block_addr)`` where ``data_block_addr`` is the + address passed to ``read_raw_data`` / ``parse_subblocks`` (DL or HL). + """ + # Avoid placing DT blocks at file offset 0 — the DL reader treats link 0 as null. + blob = bytearray(b"\x00" * 8) + dt_addrs: List[int] = [] + for payload in dt_payloads: + dt_addrs.append(len(blob)) + if payload[:4] in (b"##DT", b"##DZ"): + blob.extend(payload) + else: + blob.extend(make_dt_block(payload)) + dl_addr = len(blob) + blob.extend(make_dl_block(0, dt_addrs)) + if wrap_hl: + hl_addr = len(blob) + blob.extend(make_hl_block(dl_addr)) + return bytes(blob), hl_addr + return bytes(blob), dl_addr + + +def cyclic_dl_file() -> Tuple[bytes, int]: + """DL whose next link points back to itself (cycle guard test).""" + blob = bytearray(b"\x00" * 8) + payload = make_dt_block(b"\x01\x02\x03\x04") + dt_addr = len(blob) + blob.extend(payload) + dl_addr = len(blob) + dl = make_dl_block(dl_addr, [dt_addr]) # next -> self + blob.extend(dl) + return bytes(blob), dl_addr + + +def bytes_io_at(data: bytes, offset: int = 0) -> io.BytesIO: + """Return a seekable buffer positioned at ``offset``.""" + bio = io.BytesIO(data) + bio.seek(offset) + return bio + + +def make_unknown_block(payload: bytes = b"\x00") -> bytes: + """Build a non-DT/DZ/DL block for parse_subblocks fallback tests.""" + length = 24 + len(payload) + return ( + b"##XX" + + b"\x00" * 4 + + struct.pack(" bytes: + """Build a minimal ##CC block at offset 0 when laid at start of buffer.""" + header = ( + struct.pack(" 0: + header += struct.pack(f"<{cc_val_count}d", *params[:cc_val_count]) + length = 24 + len(header) + return ( + b"##CC" + + b"\x00" * 4 + + struct.pack(" None: mdf.close() +def _build_cc_file(path: str) -> None: + """One group with linear CC: stored raw 0..9 -> physical 10, 12, ..., 28.""" + mdf = MDF(version="4.10") + t = np.arange(10, dtype=np.float64) * 0.1 + raw = np.arange(10, dtype=np.float64) + sig = Signal( + samples=raw, + timestamps=t, + name="Scaled", + unit="V", + conversion={"a": 2.0, "b": 10.0}, + ) + mdf.append([sig], comment="cc") + mdf.header.start_time = START_TIME + mdf.save(path, overwrite=True, compression=0) + mdf.close() + + +def _build_int_file(path: str) -> None: + """Integer dtypes: uint16 ramp and int32 signed counter.""" + mdf = MDF(version="4.10") + t = np.arange(20, dtype=np.float64) * 0.05 + u16 = Signal( + samples=np.arange(20, dtype=np.uint16), + timestamps=t, + name="UInt16Ramp", + unit="cnt", + ) + i32 = Signal( + samples=np.arange(-10, 10, dtype=np.int32), + timestamps=t, + name="Int32Signed", + unit="cnt", + ) + mdf.append([u16, i32], comment="ints") + mdf.header.start_time = START_TIME + mdf.save(path, overwrite=True, compression=0) + mdf.close() + + def sample_mdf_dir(): """Return (directory, sorted_filenames) of the generated sample MDF files. @@ -82,6 +124,8 @@ def sample_mdf_dir(): atexit.register(shutil.rmtree, d, ignore_errors=True) _build_file(os.path.join(d, "sample_a.mf4"), compression=0) # ##DT _build_file(os.path.join(d, "sample_b.mf4"), compression=2) # ##DZ + _build_cc_file(os.path.join(d, "sample_c.mf4")) + _build_int_file(os.path.join(d, "sample_d.mf4")) files = sorted(f for f in os.listdir(d) if f.lower().endswith(".mf4")) _CACHE = (d, files) return _CACHE diff --git a/tests/impulse_ds/mdf/test_arrow_emit.py b/tests/impulse_ds/mdf/test_arrow_emit.py new file mode 100644 index 00000000..9a5a6b99 --- /dev/null +++ b/tests/impulse_ds/mdf/test_arrow_emit.py @@ -0,0 +1,150 @@ +"""Integration tests for impulse_ds.mdf.arrow_emit decode paths.""" + +import os +import struct +from collections import defaultdict + +import numpy as np +import pytest + +from impulse_ds.mdf.arrow_emit import _rle_compress_chunk, _rle_flush +from impulse_ds.mdf.bin_packer import plan_stripes_for_file +from impulse_ds.mdf.datasources import MdfSignalsReader +from impulse_ds.mdf.udf_helpers import ( + convert_spec_to_arrow_batches, + convert_stripe_spec_to_arrow_batches, +) +from ._block_fixtures import build_dl_file +from ._mdf_samples import sample_mdf_dir + + +def _read_signals(opts): + reader = MdfSignalsReader(opts) + cols = defaultdict(list) + for p in reader.partitions(): + for b in reader.read(p): + for name in b.schema.names: + cols[name].append(b.column(name).to_numpy(zero_copy_only=False)) + return {n: (np.concatenate(v) if v else np.array([])) for n, v in cols.items()} + + +def _by_channel(cols): + out = defaultdict(lambda: {"time": [], "value": []}) + for i, cid in enumerate(cols["channel_id"]): + k = int(cid) + out[k]["time"].append(float(cols["time"][i])) + out[k]["value"].append(float(cols["value"][i])) + return out + + +class TestStripeParity: + @pytest.mark.parametrize("fname", ["sample_a.mf4", "sample_b.mf4"]) + def test_stripe_matches_group_mode(self, fname): + d, files = sample_mdf_dir() + if fname not in files: + pytest.skip("no sample") + base = {"path": d, "files": fname, "target_partition_mb": "16", "stripe_target_mb": "2"} + group = _by_channel(_read_signals({**base, "partitioning": "group"})) + stripe = _by_channel(_read_signals({**base, "partitioning": "stripe"})) + assert set(group) == set(stripe) + for cid in group: + gt = np.array(group[cid]["time"]) + st = np.array(stripe[cid]["time"]) + np.testing.assert_allclose(np.sort(gt), np.sort(st), rtol=1e-5) + g_order = np.argsort(group[cid]["time"]) + s_order = np.argsort(stripe[cid]["time"]) + gv = np.array(group[cid]["value"])[g_order] + sv = np.array(stripe[cid]["value"])[s_order] + assert ((gv == sv) | (np.isnan(gv) & np.isnan(sv))).all() + + +class TestDlRowRangeEmit: + def test_convert_spec_honors_row_range_on_dl(self): + records = [struct.pack(" 0 diff --git a/tests/impulse_ds/mdf/test_bin_packer.py b/tests/impulse_ds/mdf/test_bin_packer.py new file mode 100644 index 00000000..00c322b2 --- /dev/null +++ b/tests/impulse_ds/mdf/test_bin_packer.py @@ -0,0 +1,129 @@ +"""Tests for impulse_ds.mdf.bin_packer partition planners.""" + +import pytest + +from impulse_ds.mdf.bin_packer import ( + plan_master_partitions, + plan_partitions, + plan_stripes_for_file, +) +from impulse_ds.mdf.mdf4_reader import ChannelInfo, CN_TYPE_MASTER +from ._mdf_samples import sample_mdf_dir + + +def _ch(gi, ci, samples, addr, ctype=0, dg=0, rec_id=0, rec_id_size=0): + return ChannelInfo( + group_idx=gi, channel_idx=ci, channel_name=f"s{gi}_{ci}", unit="", + sample_count=samples, data_type=4, bit_offset=0, byte_offset=8, + bit_count=64, channel_type=ctype, cn_block_addr=0, cg_block_addr=0, + dg_block_addr=dg, data_block_addr=addr, record_size=16, + cn_flags=0, invalidation_bit_pos=0, invalidation_bytes=0, data_bytes=8, + cc_type=-1, cc_params=(), rec_id_size=rec_id_size, record_id=rec_id, + ) + + +class TestPlanMasterPartitions: + def test_skips_zero_sample_groups(self): + m = _ch(0, 0, 0, 1000, ctype=CN_TYPE_MASTER) + specs = plan_master_partitions("f.mf4", {0: m}) + assert specs == [] + + def test_splits_big_master_by_record_range(self): + m = _ch(0, 0, 100_000, 1000, ctype=CN_TYPE_MASTER) + specs = plan_master_partitions("f.mf4", {0: m}, target_partition_mb=0.001) + assert len(specs) > 1 + assert all("row_start" in s for s in specs) + + def test_coalesces_small_masters(self): + masters = {i: _ch(i, 0, 50, 1000 + i, ctype=CN_TYPE_MASTER) for i in range(10)} + specs = plan_master_partitions( + "f.mf4", masters, target_partition_mb=256, max_groups_per_partition=64, + ) + assert len(specs) < 10 + + def test_coalesce_flush_when_target_exceeded(self): + masters = { + 0: _ch(0, 0, 50, 1000, ctype=CN_TYPE_MASTER), + 1: _ch(1, 0, 50, 2000, ctype=CN_TYPE_MASTER), + 2: _ch(2, 0, 50, 3000, ctype=CN_TYPE_MASTER), + } + specs = plan_master_partitions("f.mf4", masters, target_partition_mb=0.001) + assert len(specs) >= 2 + total_masters = sum(len(s["masters"]) for s in specs) + assert total_masters == 3 + + +class TestPlanStripesForFile: + def test_stripes_on_sample_files(self): + d, files = sample_mdf_dir() + if not files: + pytest.skip("no samples") + for fn in files: + path = f"{d}/{fn}" + with open(path, "rb") as fh: + fb = fh.read() + specs = plan_stripes_for_file(path, file_bytes=fb, stripe_target_mb=0.001) + assert specs + for s in specs: + assert s["byte_start"] < s["byte_end"] + assert s["subblocks"] + total_recs = sum( + sb["rec_count"] * s["groups"][str(sb["group_idx"])]["n_channels"] + for sb in s["subblocks"] + ) + assert total_recs > 0 + + +class TestPlanPartitionsExtended: + def test_skips_zero_sample_signal_group(self): + ch = _ch(0, 1, 0, 1000) + master = _ch(0, 0, 0, 1000, ctype=CN_TYPE_MASTER) + specs = plan_partitions("f.mf4", {0: master}, [ch], {(0, 1): 0}) + assert specs == [] + + def test_wide_group_splits_by_channel_subset(self): + addr = 5000 + signals = [_ch(0, i, 1000, addr) for i in range(1, 300)] + master = _ch(0, 0, 1000, addr, ctype=CN_TYPE_MASTER) + cidmap = {(0, i): i - 1 for i in range(1, 300)} + specs = plan_partitions( + "f.mf4", {0: master}, signals, cidmap, + target_partition_mb=0.01, channel_threshold=16, + ) + multi = [s for s in specs if len(s["channels"]) < len(signals)] + assert multi + seen = set() + for s in specs: + for c in s["channels"]: + key = (c["group_idx"], c["channel_idx"]) + assert key not in seen + seen.add(key) + assert len(seen) == len(signals) + + def test_signal_without_matching_master(self): + signals = [_ch(1, 1, 100, 1000)] + specs = plan_partitions("f.mf4", {}, signals, {(1, 1): 0}) + assert len(specs) == 1 + assert specs[0]["channels"][0]["master_info"] is None + + def test_stripes_skip_zero_sample_group(self, monkeypatch): + d, files = sample_mdf_dir() + if not files: + pytest.skip("no samples") + path = f"{d}/{files[0]}" + with open(path, "rb") as fh: + fb = fh.read() + from impulse_ds.mdf.mdf4_reader import MDF4Reader + + organized = MDF4Reader(file_bytes=fb).scan_channels_organized() + organized = dict(organized) + organized["signal_channels"] = list(organized["signal_channels"]) + [ + _ch(99, 1, 0, 0), + ] + monkeypatch.setattr( + MDF4Reader, "scan_channels_organized", lambda self: organized, + ) + specs = plan_stripes_for_file(path, file_bytes=fb, stripe_target_mb=0.001) + assert specs + for spec in specs: + assert "99" not in spec["groups"] diff --git a/tests/impulse_ds/mdf/test_datasources.py b/tests/impulse_ds/mdf/test_datasources.py index 26e0946c..37c8738e 100644 --- a/tests/impulse_ds/mdf/test_datasources.py +++ b/tests/impulse_ds/mdf/test_datasources.py @@ -441,3 +441,109 @@ def test_all_option_combos_consistent(self): assert emitted == declared, ( f"schema/emit mismatch abs={abst} val={vdt} time={tdt} " f"rle={rle} part={part}: {declared} vs {emitted}") + + +class TestDatasourcesEdgeCases: + def test_metadata_read_empty_file_path(self): + from impulse_ds.mdf.datasources import MdfMetadataReader + from pyspark.sql.datasource import InputPartition + + reader = MdfMetadataReader({"path": "/unused"}) + rows = list(reader.read(InputPartition({"file_path": ""}))) + assert rows == [] + + def test_masters_schema_float32(self): + if not EXAMPLE_FILES: + pytest.skip("No example files") + from impulse_ds.mdf.datasources import MdfMastersDataSource, MdfMastersReader + + opts = {"path": EXAMPLE_DIR, "files": EXAMPLE_FILES[0], "time_dtype": "float32"} + sch = MdfMastersDataSource(dict(opts)).schema() + assert sch["timestamp"].dataType.simpleString() == "float" + reader = MdfMastersReader(opts) + for p in reader.partitions(): + for b in reader.read(p): + assert str(b.schema.field("timestamp").type) == "float" + return + + def test_absolute_time_raises_without_hd_start(self, tmp_path, monkeypatch): + from asammdf import MDF, Signal + import numpy as np + + path = tmp_path / "no_start.mf4" + mdf = MDF(version="4.10") + t = np.arange(5, dtype=np.float64) * 0.1 + mdf.append([Signal(samples=t, timestamps=t, name="x")]) + mdf.save(str(path), overwrite=True) + mdf.close() + + monkeypatch.setattr( + "impulse_ds.mdf.mdf4_reader.MDF4Reader.read_header_start_epoch_seconds", + lambda self: None, + ) + reader = MdfSignalsReader({"path": str(tmp_path), "files": "no_start.mf4", + "absolute_time": "true"}) + with pytest.raises(ValueError, match="no measurement start time"): + reader.partitions() + + def test_masters_absolute_time_raises_without_hd_start(self, tmp_path, monkeypatch): + from asammdf import MDF, Signal + import numpy as np + from impulse_ds.mdf.datasources import MdfMastersReader + + path = tmp_path / "no_start.mf4" + mdf = MDF(version="4.10") + t = np.arange(5, dtype=np.float64) * 0.1 + mdf.append([Signal(samples=t, timestamps=t, name="x")]) + mdf.save(str(path), overwrite=True) + mdf.close() + + monkeypatch.setattr( + "impulse_ds.mdf.mdf4_reader.MDF4Reader.read_header_start_epoch_seconds", + lambda self: None, + ) + reader = MdfMastersReader({ + "path": str(tmp_path), "files": "no_start.mf4", "absolute_time": "true", + }) + with pytest.raises(ValueError, match="no measurement start time"): + reader.partitions() + + def test_signals_empty_partitions_when_no_signals(self, monkeypatch): + from impulse_ds.mdf.datasources import MdfSignalsReader + + def _empty_scan(self): + return {"master_channels": {}, "signal_channels": [], "channel_id_map": {}, + "unsorted_dg_ctx": {}} + + monkeypatch.setattr( + "impulse_ds.mdf.datasources._resolve_file_list", + lambda opts: ["/fake/a.mf4"], + ) + monkeypatch.setattr( + "impulse_ds.mdf.mdf4_reader.MDF4Reader.scan_channels_organized", + _empty_scan, + ) + reader = MdfSignalsReader({"path": "/x", "files": "a.mf4"}) + parts = reader.partitions() + assert len(parts) == 1 + assert parts[0].value == "[]" + assert list(reader.read(parts[0])) == [] + + def test_masters_empty_when_no_masters(self, monkeypatch): + from impulse_ds.mdf.datasources import MdfMastersReader + + def _no_masters(self): + return {"master_channels": {}, "signal_channels": [], "channel_id_map": {}, + "unsorted_dg_ctx": {}} + + monkeypatch.setattr( + "impulse_ds.mdf.datasources._resolve_file_list", + lambda opts: ["/fake/a.mf4"], + ) + monkeypatch.setattr( + "impulse_ds.mdf.mdf4_reader.MDF4Reader.scan_channels_organized", + _no_masters, + ) + reader = MdfMastersReader({"path": "/x", "files": "a.mf4"}) + parts = reader.partitions() + assert parts[0].value == "[]" diff --git a/tests/impulse_ds/mdf/test_mdf4_reader.py b/tests/impulse_ds/mdf/test_mdf4_reader.py index f0863ebb..1e13b1c3 100644 --- a/tests/impulse_ds/mdf/test_mdf4_reader.py +++ b/tests/impulse_ds/mdf/test_mdf4_reader.py @@ -6,6 +6,7 @@ This also cross-validates our reader against asammdf's own output. """ +import io import os import pytest import numpy as np @@ -13,7 +14,7 @@ from impulse_ds.mdf.mdf4_reader import ( MDF4Reader, CN_TYPE_MASTER, CN_TYPE_VIRTUAL_MASTER ) -from ._mdf_samples import sample_mdf_dir +from ._mdf_samples import sample_mdf_dir, START_TIME _DIR, _FILES = sample_mdf_dir() @@ -392,3 +393,95 @@ def test_full_channel_coverage_exactly_once(self): assert a[1] == b[0] # contiguous, no gaps/overlap all_keys = whole_seen | set(ranges) assert len(all_keys) == len(signal) + + +class TestMDF4ReaderExtended: + def test_file_bytes_matches_path(self, mdf_file): + with open(mdf_file, "rb") as fh: + data = fh.read() + by_path = MDF4Reader(mdf_file).scan_metadata() + by_bytes = MDF4Reader(file_bytes=data).scan_metadata() + assert len(by_path) == len(by_bytes) + assert [c.channel_name for c in by_path] == [c.channel_name for c in by_bytes] + + def test_invalid_signature_raises(self): + with pytest.raises(ValueError, match="Not a valid MDF"): + MDF4Reader(file_bytes=b"NOTMDF!!" + b"\x00" * 56).scan_metadata() + + def test_header_datetime_from_samples(self): + d, files = sample_mdf_dir() + if not files: + pytest.skip("no samples") + path = f"{d}/{files[0]}" + reader = MDF4Reader(path) + dt = reader.read_header_datetime() + assert dt is not None + assert dt.year == START_TIME.year + epoch = reader.read_header_start_epoch_seconds() + assert epoch is not None + + def test_linear_cc_on_sample_c(self): + d, files = sample_mdf_dir() + if "sample_c.mf4" not in files: + pytest.skip("no cc sample") + path = f"{d}/sample_c.mf4" + reader = MDF4Reader(path) + channels = reader.scan_metadata() + scaled = [c for c in channels if c.channel_name == "Scaled"][0] + assert scaled.cc_type == 1 + values = MDF4Reader.read_channel_data( + path, scaled.data_block_addr, scaled.record_size, + scaled.byte_offset, scaled.bit_offset, scaled.bit_count, + scaled.data_type, scaled.channel_type, scaled.sample_count, + cc_type=scaled.cc_type, cc_params=scaled.cc_params, + ) + np.testing.assert_allclose(values, np.arange(10) * 2.0 + 10.0) + + def test_channel_to_dict_unsorted_fields(self): + from impulse_ds.mdf.mdf4_reader import ChannelInfo + ch = ChannelInfo( + group_idx=0, channel_idx=0, channel_name="x", unit="", + sample_count=1, data_type=4, bit_offset=0, byte_offset=4, + bit_count=64, channel_type=0, cn_block_addr=0, cg_block_addr=0, + dg_block_addr=100, data_block_addr=1000, record_size=20, + rec_id_size=4, record_id=1, + ) + ctx = {100: {"rec_id_size": 4, "cg_sizes": {1: 20}}} + d = MDF4Reader.channel_to_dict(ch, ctx) + assert d["rec_id_size"] == 4 + assert d["cg_record_sizes"] == {1: 20} + + +class TestParseCcBlock: + @staticmethod + def _cc_at_offset(blob: bytes, offset: int = 8): + return b"\x00" * offset + blob + + def test_zero_addr_returns_identity(self): + with io.BytesIO(b"") as f: + assert MDF4Reader._parse_cc_block(f, 0) == (-1, ()) + + def test_wrong_block_id(self): + blob = self._cc_at_offset(b"##DT" + b"\x00" * 20) + with io.BytesIO(blob) as f: + assert MDF4Reader._parse_cc_block(f, 8) == (-1, ()) + + def test_empty_params_and_unsupported_type(self): + from ._block_fixtures import make_cc_block + + no_params = self._cc_at_offset(make_cc_block(cc_type=0, cc_val_count=0, params=())) + with io.BytesIO(no_params) as f: + assert MDF4Reader._parse_cc_block(f, 8) == (0, ()) + + unsupported = self._cc_at_offset(make_cc_block(cc_type=9, cc_val_count=0, params=())) + with io.BytesIO(unsupported) as f: + assert MDF4Reader._parse_cc_block(f, 8) == (-1, ()) + + def test_linear_params(self): + from ._block_fixtures import make_cc_block + + blob = self._cc_at_offset(make_cc_block(cc_type=1, cc_val_count=2, params=(10.0, 2.0))) + with io.BytesIO(blob) as f: + cc_type, params = MDF4Reader._parse_cc_block(f, 8) + assert cc_type == 1 + assert params == (10.0, 2.0) diff --git a/tests/impulse_ds/mdf/test_mdf_blocks.py b/tests/impulse_ds/mdf/test_mdf_blocks.py new file mode 100644 index 00000000..1da15159 --- /dev/null +++ b/tests/impulse_ds/mdf/test_mdf_blocks.py @@ -0,0 +1,200 @@ +"""Unit tests for impulse_ds.mdf.mdf_blocks binary I/O.""" + +import io +import logging +import struct + +import numpy as np +import pytest + +from impulse_ds.mdf.mdf_blocks import ( + _collect_dl_block_addrs, + _read_block_chunks, + _read_dl_blob, + decompress_dz, + dt_data_extent, + parse_subblocks, + read_data_list_range, + read_raw_data, + resolve_dl_addr, +) +from ._block_fixtures import ( + build_dl_file, + cyclic_dl_file, + make_dt_block, + make_dz_block, + make_unknown_block, +) +from ._mdf_samples import sample_mdf_dir + + +class TestDtDzBlocks: + def test_read_raw_data_dt(self): + payload = struct.pack("<4d", 1.0, 2.0, 3.0, 4.0) + blob = make_dt_block(payload) + with io.BytesIO(blob) as f: + raw = read_raw_data(f, 0, record_size=8, sample_count=4) + assert raw == payload + assert len(raw) == 32 + + def test_dt_data_extent(self): + payload = b"\xab" * 16 + blob = make_dt_block(payload) + with io.BytesIO(blob) as f: + extent = dt_data_extent(f, 0) + assert extent == (24, 16) + + def test_read_raw_data_dz_plain(self): + payload = struct.pack("<2d", 3.14, 2.71) + blob = make_dz_block(payload, zip_type=0) + with io.BytesIO(blob) as f: + raw = read_raw_data(f, 0, record_size=8, sample_count=2) + assert raw == payload + + def test_decompress_dz_transpose_even(self): + # 2x3 row-major payload -> zip_type=1 with cols=3 + payload = bytes(range(6)) + blob = make_dz_block(payload, zip_type=1, zip_parameter=3) + with io.BytesIO(blob) as f: + out = decompress_dz(f, 0) + assert out == payload + + def test_decompress_dz_transpose_remainder(self): + # 10 bytes, cols=3 -> uneven column layout branch + payload = bytes(range(10)) + blob = make_dz_block(payload, zip_type=1, zip_parameter=3) + with io.BytesIO(blob) as f: + out = decompress_dz(f, 0) + assert out == payload + + def test_read_raw_data_dz_from_sample_b(self): + d, files = sample_mdf_dir() + if not files: + pytest.skip("no samples") + path = f"{d}/{files[1]}" # sample_b compressed + from impulse_ds.mdf.mdf4_reader import MDF4Reader + + ch = MDF4Reader(path).scan_metadata()[0] + with open(path, "rb") as f: + raw = read_raw_data(f, ch.data_block_addr, ch.record_size, ch.sample_count) + assert len(raw) == ch.record_size * ch.sample_count + + +class TestDlHlBlocks: + def test_resolve_dl_addr_variants(self): + p1 = struct.pack("2H", 100, 200) + col16 = np.frombuffer(raw16, dtype=np.uint8).reshape(2, 2) + np.testing.assert_allclose( + convert_values(col16, UINT_BE, 16, 0, 2), [100.0, 200.0], + ) + # 24-bit little-endian in 3-byte columns + col24 = np.array([[0x12, 0x34, 0x56], [0x78, 0x9A, 0xBC]], dtype=np.uint8) + out = convert_values(col24, UINT_LE, 24, 0, 2) + assert out[0] == pytest.approx(0x563412) + assert out[1] == pytest.approx(0xBC9A78) + + def test_sint_be_and_padded(self): + raw = struct.pack(">2h", -3, 7) + col = np.frombuffer(raw, dtype=np.uint8).reshape(2, 2) + np.testing.assert_allclose( + convert_values(col, SINT_BE, 16, 0, 2), [-3.0, 7.0], + ) + raw32 = struct.pack(" 0 + + def test_rle_helpers_edge_cases(self): + assert _eq_nan(float("nan"), float("nan")) + assert not _eq_nan(1.0, 2.0) + assert len(_rle_run_starts(np.array([1.0]))) == 1 + closed, carry = _rle_compress_chunk(np.array([]), np.array([]), None) + assert closed is None and carry is None + ts = np.array([0.0, 1.0]) + vs = np.array([3.0, 7.0]) + closed, carry = _rle_compress_chunk(ts, vs, [3.0, 0.0, 1.0]) + assert closed is not None + assert _rle_flush(None) is None + + def test_rle_integration_small_partition(self): + d, files = sample_mdf_dir() + if not files: + pytest.skip("no samples") + reader = MdfSignalsReader({ + "path": d, "files": files[0], "target_partition_mb": "0.0001", + "run_length_encoding": "true", + }) + rows = sum(b.num_rows for p in reader.partitions() for b in reader.read(p)) + assert rows > 0 + + def test_signals_float32_and_masters_schema(self): + d, files = sample_mdf_dir() + if not files: + pytest.skip("no samples") + from impulse_ds.mdf.datasources import MdfMastersDataSource, MdfSignalsDataSource + opts = {"path": d, "files": files[0], "time_dtype": "float32", "value_dtype": "float32"} + assert MdfSignalsDataSource(opts).schema()["value"].dataType.simpleString() == "float" + assert MdfMastersDataSource(opts).schema()["timestamp"].dataType.simpleString() == "float" + + +class TestMdf4ReaderCoverage: + def _make_cc_block(self, cc_type, params): + val_count = len(params) + body = ( + struct.pack("> 4 + vals = extract_signal(raw, rs, ch) + assert vals[0] == pytest.approx(raw_val * 2.0 + 1.0) + + def test_extract_timestamps_with_cc(self): + raw = struct.pack("d", 2.5), dtype=np.uint8).reshape(1, 8) + np.testing.assert_allclose(convert_values(col, FLOAT_BE, 64, 0, 1), [2.5]) + col5 = np.zeros((1, 5), dtype=np.uint8) + col5[0, :5] = [1, 2, 3, 4, 5] + assert convert_values(col5, UINT_LE, 40, 0, 1)[0] > 0 + cols = np.array([[0xFF]], dtype=np.uint8) + assert convert_values(cols, SINT_LE, 8, 0, 1)[0] == -1.0 + + def test_read_record_id_zero_size(self): + assert read_record_id(b"\x05", 0, 0) == 0 + + def test_filter_truncated_tail(self): + raw, rec_id_size, cg_sizes, record_size = _interleaved_raw() + bad = raw + struct.pack(" 0 + colf = np.frombuffer(struct.pack(">f", 2.0), dtype=np.uint8).reshape(1, 4) + np.testing.assert_allclose(convert_values(colf, FLOAT_BE, 32, 0, 1), [2.0]) + col = np.array([[0x12, 0x34, 0x56, 0x00]], dtype=np.uint8) + out = convert_values(col, UINT_BE, 24, 0, 1) + assert out[0] == pytest.approx(3429888.0) + + +class TestMdfBlocksMoreCoverage: + def test_dz_transpose_remainder_in_dl(self): + payload = bytes(range(10)) + dz = make_dz_block(payload, zip_type=1, zip_parameter=3) + blob, dl_addr = build_dl_file([dz]) + with io.BytesIO(blob) as f: + raw = read_raw_data(f, dl_addr, record_size=1, sample_count=10) + assert raw == payload + + def test_hl_zero_link_returns_empty(self): + hl = b"##HL" + b"\x00" * 4 + struct.pack(" 0 + + def test_convert_master_virtual_and_float32(self): + spec = { + "file_path": "/dev/null", + "time_dtype": "float32", + "time_offset": 1.5, + "row_start": 2, + "row_end": 5, + "masters": [{ + "group_idx": 0, + "record_size": 8, + "sample_count": 10, + "data_block_addr": 0, + "master_info": {"channel_type": 3, "cc_type": -1, "cc_params": []}, + }], + } + batches = list(convert_master_spec_to_arrow_batches(spec)) + assert len(batches) == 1 + ts = batches[0].column("timestamp").to_pylist() + assert ts == pytest.approx([3.5, 4.5, 5.5]) + + def test_convert_master_from_sample(self): + d, files = sample_mdf_dir() + if not files: + pytest.skip("no samples") + path = f"{d}/{files[0]}" + from impulse_ds.mdf.bin_packer import plan_master_partitions + from impulse_ds.mdf.mdf4_reader import MDF4Reader + from impulse_ds.mdf.udf_helpers import convert_master_spec_to_arrow_batches + org = MDF4Reader(path).scan_channels_organized() + specs = plan_master_partitions( + path, org["master_channels"], target_partition_mb=16, + unsorted_dg_ctx=org["unsorted_dg_ctx"], + ) + batches = list(convert_master_spec_to_arrow_batches(specs[0])) + assert batches[0].num_rows > 0 + + def test_stripe_unsorted_interleaved(self): + raw, rec_id_size, cg_sizes, record_size = _interleaved_raw() + blob = make_dt_block(raw) + fd, path = tempfile.mkstemp(suffix=".mf4") + __import__("os").write(fd, blob) + __import__("os").close(fd) + try: + ch = _unsorted_ch_spec(rec_id_size, cg_sizes, record_size, 0) + master = ch["master_info"] + spec = { + "file_path": path, + "byte_start": 0, + "byte_end": len(blob), + "groups": { + "0": { + "record_size": record_size, + "master_info": master, + "channels": [ch], + "rec_id_size": rec_id_size, + "record_id": 1, + "cg_record_sizes": cg_sizes, + }, + }, + "subblocks": [{ + "group_idx": 0, + "abs_off": 0, + "on_disk_len": len(blob), + "rec_start": 0, + "rec_count": 3, + }], + } + batches = list(convert_stripe_spec_to_arrow_batches(spec)) + assert batches[0].num_rows == 2 + finally: + Path(path).unlink(missing_ok=True) + + def test_stripe_without_master_info(self): + payload = b"".join(struct.pack(" 0 + + def test_stripe_decompress_failure_skipped(self, monkeypatch): + d, files = sample_mdf_dir() + if not files: + pytest.skip("no samples") + path = f"{d}/{files[0]}" + from impulse_ds.mdf.bin_packer import plan_stripes_for_file + specs = plan_stripes_for_file(path, stripe_target_mb=0.001) + + def _bad_decompress(*a, **k): + raise ValueError("bad") + + monkeypatch.setattr("impulse_ds.mdf.arrow_emit._decompress_subblock_blob", _bad_decompress) + assert list(convert_stripe_spec_to_arrow_batches(specs[0])) == [] + + def test_convert_spec_extent_error_and_empty_slice(self, monkeypatch): + d, files = sample_mdf_dir() + if not files: + pytest.skip("no samples") + path = f"{d}/{files[0]}" + from impulse_ds.mdf.bin_packer import plan_partitions + from impulse_ds.mdf.mdf4_reader import MDF4Reader + org = MDF4Reader(path).scan_channels_organized() + specs = plan_partitions( + path, org["master_channels"], org["signal_channels"], + org["channel_id_map"], target_partition_mb=16, + ) + spec = dict(specs[0]) + spec["row_start"] = 0 + spec["row_end"] = 0 + + def _raise(*a, **k): + raise OSError("extent") + + monkeypatch.setattr("impulse_ds.mdf.arrow_emit.dt_data_extent", _raise) + assert list(convert_spec_to_arrow_batches(spec)) == [] + + def test_master_spec_zero_record_size(self): + spec = { + "file_path": "/dev/null", + "masters": [{ + "group_idx": 0, "record_size": 0, "sample_count": 1, + "data_block_addr": 0, + "master_info": {"channel_type": 3, "cc_type": -1, "cc_params": []}, + }], + } + assert list(convert_master_spec_to_arrow_batches(spec)) == [] + + def test_convert_spec_without_master_info(self): + d, files = sample_mdf_dir() + if not files: + pytest.skip("no samples") + path = f"{d}/{files[0]}" + from impulse_ds.mdf.bin_packer import plan_partitions + from impulse_ds.mdf.mdf4_reader import MDF4Reader + org = MDF4Reader(path).scan_channels_organized() + specs = plan_partitions( + path, org["master_channels"], org["signal_channels"], + org["channel_id_map"], target_partition_mb=16, + ) + spec = dict(specs[0]) + ch = dict(spec["channels"][0]) + ch["master_info"] = None + spec["channels"] = [ch] + batches = list(convert_spec_to_arrow_batches(spec)) + assert batches[0].num_rows > 0 + + def test_convert_spec_rle_flush_and_float32(self): + d, files = sample_mdf_dir() + if not files: + pytest.skip("no samples") + path = f"{d}/{files[0]}" + from impulse_ds.mdf.bin_packer import plan_partitions + from impulse_ds.mdf.mdf4_reader import MDF4Reader + org = MDF4Reader(path).scan_channels_organized() + specs = plan_partitions( + path, org["master_channels"], org["signal_channels"], + org["channel_id_map"], target_partition_mb=16, + ) + batches = list(convert_spec_to_arrow_batches( + specs[0], run_length_encoding=True, time_dtype="float32", value_dtype="float32", + )) + assert batches + + def test_stripe_unsorted_decompress_failure(self, monkeypatch): + raw, rec_id_size, cg_sizes, record_size = _interleaved_raw() + blob = make_dt_block(raw) + fd, path = tempfile.mkstemp(suffix=".mf4") + __import__("os").write(fd, blob) + __import__("os").close(fd) + try: + ch = _unsorted_ch_spec(rec_id_size, cg_sizes, record_size, 0) + spec = { + "file_path": path, + "byte_start": 0, + "byte_end": len(blob), + "groups": { + "0": { + "record_size": record_size, + "master_info": ch["master_info"], + "channels": [ch], + "rec_id_size": rec_id_size, + "record_id": 1, + "cg_record_sizes": cg_sizes, + }, + }, + "subblocks": [{ + "group_idx": 0, "abs_off": 0, "on_disk_len": len(blob), + "rec_start": 0, "rec_count": 3, + }], + } + + def _bad(*a, **k): + raise ValueError("bad") + + monkeypatch.setattr("impulse_ds.mdf.arrow_emit._decompress_subblock_blob", _bad) + assert list(convert_stripe_spec_to_arrow_batches(spec)) == [] + finally: + Path(path).unlink(missing_ok=True) + + def test_emit_prepared_skips_vlsd_channel(self): + import logging + import time + prof = {"decode": 0} + log = logging.getLogger("t") + now = time.perf_counter_ns + vlsd = { + "channel_id": 2, "channel_type": 1, "data_type": FLOAT_LE, + "bit_count": 64, "byte_offset": 0, "bit_offset": 0, + "cn_flags": 0, "invalidation_bytes": 0, "data_bytes": 8, + "cc_type": -1, "cc_params": [], + } + good = { + "channel_id": 1, "channel_type": 0, "data_type": FLOAT_LE, + "bit_count": 64, "byte_offset": 0, "bit_offset": 0, + "cn_flags": 0, "invalidation_bytes": 0, "data_bytes": 8, + "cc_type": -1, "cc_params": [], + } + raw = struct.pack(" 0 + + def test_convert_spec_dl_row_range_integration(self): + records = [struct.pack("2d", 1.0, 2.0), [1.0, 2.0]), + (UINT_LE, 16, 0, struct.pack("<2H", 100, 200), [100.0, 200.0]), + (UINT_BE, 16, 0, struct.pack(">2H", 300, 400), [300.0, 400.0]), + (UINT_LE, 32, 0, struct.pack("<2I", 1, 42), [1.0, 42.0]), + (UINT_BE, 32, 0, struct.pack(">2I", 5, 6), [5.0, 6.0]), + (SINT_LE, 32, 0, struct.pack("<2i", -1, 42), [-1.0, 42.0]), + (SINT_BE, 32, 0, struct.pack(">2i", -5, 7), [-5.0, 7.0]), + (UINT_LE, 8, 0, bytes([1, 255]), [1.0, 255.0]), + ], + ) + def test_known_types(self, data_type, bit_count, bit_offset, raw, expected): + n = len(expected) + vb = (bit_count + 7) // 8 + col = np.frombuffer(raw, dtype=np.uint8).reshape(n, len(raw) // n) + if col.shape[1] != vb: + col = col[:, :vb] + out = convert_values(col, data_type, bit_count, bit_offset, n) + np.testing.assert_allclose(out, expected, rtol=1e-5) + + @pytest.mark.parametrize( + "data_type,bit_count,col,expected", + [ + (UINT_BE, 24, [[0, 0, 1], [0, 1, 0]], [256.0, 65536.0]), + (UINT_BE, 48, [[0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 1, 0]], [65536.0, 16777216.0]), + (SINT_BE, 24, [[0xFF, 0xFF, 0xFF], [0, 1, 0]], [-256.0, 65536.0]), + ], + ) + def test_padded_big_endian_widths(self, data_type, bit_count, col, expected): + arr = np.array(col, dtype=np.uint8) + out = convert_values(arr, data_type, bit_count, 0, len(expected)) + np.testing.assert_allclose(out, expected, rtol=1e-5) + + def test_unsupported_type_returns_zeros(self): + col = np.zeros((3, 8), dtype=np.uint8) + out = convert_values(col, 99, 64, 0, 3) + np.testing.assert_array_equal(out, [0.0, 0.0, 0.0]) + + def test_uint_with_bit_offset(self): + # 12-bit values 15 and 255 stored in uint16 with 4-bit offset + col = np.array([[0xF0, 0x00], [0xFF, 0x0F]], dtype=np.uint8) + out = convert_values(col, UINT_LE, 12, 4, 2) + np.testing.assert_allclose(out, [15.0, 255.0]) + + +class TestApplyInvalidation: + def test_invalidation_bit_sets_nan(self): + record_size = 9 + n = 2 + buf = bytearray(n * record_size) + # data byte 0, invalidation at data_bytes=8 byte 0 bit 0 + buf[0] = 10 + buf[record_size] = 20 + buf[8] = 0x01 # first record invalid + values = np.array([10.0, 20.0]) + info = { + "cn_flags": CN_FLAG_INVALIDATION_PRESENT, + "invalidation_bit_pos": 0, + "invalidation_bytes": 1, + "data_bytes": 8, + } + out = apply_invalidation(buf, record_size, n, values.copy(), info) + assert np.isnan(out[0]) + assert out[1] == 20.0 + + def test_all_invalid_flag(self): + values = np.array([1.0, 2.0]) + info = {"cn_flags": CN_FLAG_ALL_INVALID, "invalidation_bytes": 1, "data_bytes": 8} + out = apply_invalidation(b"\x00" * 18, 9, 2, values.copy(), info) + assert np.all(np.isnan(out)) + + +class TestApplyCcConversionExtended: + def test_tab_nointerp(self): + raw = np.array([10.0, 120.0, 250.0]) + params = (0.0, 0.0, 100.0, 50.0, 200.0, 100.0) + out = apply_cc_conversion(raw.copy(), CC_TAB_NOINTERP, params) + np.testing.assert_allclose(out, [0.0, 50.0, 100.0]) + + def test_range_to_value(self): + raw = np.array([5.0, 15.0, 25.0]) + params = (0.0, 10.0, 1.0, 10.0, 20.0, 2.0, 99.0) + out = apply_cc_conversion(raw.copy(), CC_RANGE_TO_VALUE, params) + np.testing.assert_allclose(out, [1.0, 2.0, 99.0]) + + def test_range_empty_returns_default(self): + raw = np.array([1.0]) + out = apply_cc_conversion(raw.copy(), CC_RANGE_TO_VALUE, (99.0,)) + assert out[0] == 99.0 + + +class TestFilterUnsortedRecords: + def test_unknown_record_id_stops(self): + raw, rec_id_size, cg_sizes, record_size = _build_interleaved_block() + # Append garbage record id not in cg_sizes + bad = struct.pack(" slow path + "bit_offset": 0, + "bit_count": 64, + "data_type": FLOAT_LE, + "cc_type": 1, + "cc_params": (0.0, 10.0), + } + ts = extract_timestamps(raw, record_size, master) + assert len(ts) == n diff --git a/tests/impulse_ds/mdf/test_mdf_package.py b/tests/impulse_ds/mdf/test_mdf_package.py new file mode 100644 index 00000000..bbedfd9e --- /dev/null +++ b/tests/impulse_ds/mdf/test_mdf_package.py @@ -0,0 +1,12 @@ +"""Smoke tests for impulse_ds.mdf lazy public API.""" + + +def test_lazy_imports(): + import impulse_ds.mdf as mdf + + assert mdf.MDF4Reader is not None + assert mdf.MdfSignalsDataSource is not None + assert mdf.MdfMetadataDataSource is not None + assert mdf.MdfMastersDataSource is not None + assert mdf.register_mdf_datasources is not None + assert mdf.MDFToDeltaConverter is not None diff --git a/tests/impulse_ds/mdf/test_unsorted_dg.py b/tests/impulse_ds/mdf/test_unsorted_dg.py new file mode 100644 index 00000000..38e86590 --- /dev/null +++ b/tests/impulse_ds/mdf/test_unsorted_dg.py @@ -0,0 +1,205 @@ +"""Tests for unsorted MDF4 data group record filtering.""" + +import struct +import tempfile +from pathlib import Path + +import numpy as np +import pytest + +from impulse_ds.mdf.mdf_decode import ( + filter_unsorted_records, + prepare_cg_records, + read_record_id, + storage_record_id, + extract_signal, + extract_timestamps, +) +from impulse_ds.mdf.mdf4_reader import MDF4Reader +from impulse_ds.mdf.bin_packer import plan_partitions +from impulse_ds.mdf.udf_helpers import convert_spec_to_arrow_batches + + +def _build_interleaved_block(): + """Two CGs interleaved: rec_id_size=4, both CGs record_size=20.""" + rec_id_size = 4 + record_size = 20 + cg_sizes = {1: record_size, 2: record_size} + records = [] + # CG1: time=1.0, value=10.0 + r1 = struct.pack(" str: + dt = b"##DT" + b"\x00" * 4 + dt += struct.pack(" Date: Wed, 22 Jul 2026 14:32:35 +0200 Subject: [PATCH 3/8] moved known limitations to its own md --- src/impulse_ds/mdf/KNOWN_LIMITATIONS.md | 125 ++++++++++++++++++++++++ src/impulse_ds/mdf/README.md | 42 +++----- 2 files changed, 139 insertions(+), 28 deletions(-) create mode 100644 src/impulse_ds/mdf/KNOWN_LIMITATIONS.md diff --git a/src/impulse_ds/mdf/KNOWN_LIMITATIONS.md b/src/impulse_ds/mdf/KNOWN_LIMITATIONS.md new file mode 100644 index 00000000..f8b5df69 --- /dev/null +++ b/src/impulse_ds/mdf/KNOWN_LIMITATIONS.md @@ -0,0 +1,125 @@ +# Known limitations + +`impulse_ds.mdf` is **experimental** and under active development. It does **not** +yet fully implement the [ASAM MDF4](https://www.asam.net/standards/detail/mdf/) +specification. Some block types, encodings, compression modes, and edge cases may +be missing or behave differently than reference tools. Validate outputs against +your files before relying on this in production workflows. + +**MDF4 only.** Files must have an `MDF` identification block and an `##HD` header +at offset 64. **MDF3** (and other legacy layouts) are not supported. + +**Numeric-first output.** Signal values are decoded to a single `double` / `float` +column. String, byte-array, MIME, and complex channels are not represented in the +output schema. + +--- + +## Backlog (feature gaps) + +| area | severity | status | +| ---- | -------- | ------ | +| **VLSD channels** (`cn_type = 1`) — variable-length signals store an offset in the fixed record; the `##SD` payload linked from CN is not followed. Channels currently emit NaN. String/byte output would need schema changes. | MEDIUM | not implemented | +| **MLSD channels** (`cn_type = 5`) — maximum-length data lists are not decoded; bytes in the record are interpreted as fixed-width numeric data. | MEDIUM | not implemented | +| **CC type 3 (algebraic / formula)** — formula text in `cc_ref[0]` (`##TX`) is not read or evaluated; `apply_cc_conversion` has no handler for type 3. | LOW–MEDIUM | not implemented | +| **CC types 7–10 (text conversions)** — require `##TX` / `cc_ref` resolution. Unsupported by design for the numeric-only `value` column; `_parse_cc_block` returns `(-1, ())` for `cc_type > 6`. | LOW | not implemented (by design) | +| **CN composition** — the CN composition link (link 1) is not resolved; composite / array channels are not expanded. | MEDIUM | not implemented | +| **CN virtual data** (`cn_type = 6`) — not synthesized from other channels; record bytes are decoded as if the channel were fixed-length. | MEDIUM | not implemented | +| **CN sync channels** (`cn_type = 4`) — included in `mdf_signals` like ordinary signals rather than used as a time/sync axis. | LOW | not implemented | +| **Source information (`##SI`)** — `si_source` CN links are ignored; bus/protocol metadata is not surfaced. | LOW | not implemented | +| **Attachments** — `cn_attachment_count` is read for layout only; `##AT` blocks are not loaded. | LOW | not implemented | +| **Events / global metadata** — `##EV`, `##FH`, `##CH`, and other non-DG block types outside the HD→DG→CG→CN walk are not parsed. | LOW | not implemented | + +**Unsorted DGs:** reads filter interleaved records by `record_id` before decode +(`filter_unsorted_records` in `mdf_decode.py`). Stripe mode concatenates +sub-blocks, then filters once per channel group. + +--- + +## CC (`##CC`) block fields not used + +When parsing channel conversions (`_parse_cc_block` in `mdf4_reader.py`), only +`cc_type` and the inline `cc_val_count` double parameters are returned. The +following CC header fields are read to advance the file pointer but **not applied** +to decoded values: + +| field | notes | +| ----- | ----- | +| `cc_precision` | physical-value decimal places — ignored | +| `cc_flags` | status / validity flags — ignored | +| `cc_ref_count` | number of `cc_ref` links — ignored | +| `cc_phy_range_min` / `cc_phy_range_max` | expected physical range — not used for clamping or validation | + +Additionally: + +- **CC reference links** (name, unit, comment, inverse CC, `cc_ref` TX blocks for + formulas and text tables) are skipped entirely; only inline numeric parameters + are used for types 0–6. +- **Inverse CC** — the inverse-conversion link is not followed. + +--- + +## CN (`##CN`) block fields not used + +CN layout fields are read in spec order during `scan_metadata`, but only +`cn_type`, `cn_data_type`, offsets, `cn_bit_count`, `cn_flags`, and +`cn_invalid_bit_pos` drive decoding. These fields are **not used** downstream: + +| field | notes | +| ----- | ----- | +| `cn_sync_type` | sync relationship to master — ignored | +| `cn_precision` | display precision — ignored | +| `cn_attachment_count` | attachment list size — ignored | +| `cn_val_range_min` / `cn_val_range_max` | value range — not used for validation | +| `cn_limit_min` / `cn_limit_max` | soft limits — ignored | +| `cn_limit_ext_min` / `cn_limit_ext_max` | extended limits — ignored | + +**CG-level fields** `cg_flags` and `cg_path_separator` are likewise read for layout +only and not interpreted. + +--- + +## Data types + +`convert_values` (`mdf_decode.py`) fully decodes little- and big-endian integer +and float types (types 0–5) for common bit widths. All other `cn_data_type` values +fall through to **zeros** (or NaN for VLSD): + +| `cn_data_type` | name | behaviour | +| -------------- | ---- | --------- | +| 6–9 | string (Latin / UTF-8 / UTF-16) | zeros emitted | +| 10 | byte array | zeros emitted | +| 11–12 | MIME sample / stream | zeros emitted | +| 13–14 | CANopen date / time | zeros emitted | +| 15–16 | complex LE / BE | zeros emitted | + +Unsupported **float bit widths** (e.g. float16) within types 4–5 also produce zeros. + +**Endianness / alignment:** fast strided decode paths in `extract_signal` and +`extract_timestamps` are implemented for **little-endian, byte-aligned** fields. +Big-endian and unaligned (`bit_offset > 0`) types use the slower generic path in +`convert_values`. + +--- + +## Data blocks and I/O + +Supported payload containers: `##DT`, `##DZ` (zlib deflate; `zip_type` 0 = plain, +1 = transposed deflate), `##DL` / `##HL` chains. + +| gap | notes | +| --- | ----- | +| **Unknown / future block types** at the DG data link | `read_raw_data` falls back to reading `record_size * sample_count` bytes from offset 24 with no structure validation. | +| **Non-zlib `##DZ` compression** | only zlib (`zip_type` 0/1) is handled; other MDF compression identifiers are not implemented. | +| **Malformed DL chains** | cyclic DL links stop traversal; truncated chains may yield partial data without error. | + +--- + +## Semantic / API limitations + +| gap | notes | +| --- | ----- | +| **One master per group** | `scan_channels_organized` keeps the last `CN_TYPE_MASTER` / `CN_TYPE_VIRTUAL_MASTER` per `group_idx`; files with multiple masters per group are not modeled. | +| **Fixed CN link indices** | name, CC, unit, and comment addresses assume the standard MDF4 link order; variant link counts / orderings may mis-resolve metadata. | +| **Absolute time precision** | `read_header_start_epoch_seconds` documents float64 epoch seconds (~0.3 µs resolution at current epoch); HD nanosecond start time is not preserved bit-for-bit in outputs. | +| **Invalidation** | per-sample invalidation bits are applied when `CN_FLAG_INVALIDATION_PRESENT` is set; other CN/CG invalidation modes may differ from reference tools. | diff --git a/src/impulse_ds/mdf/README.md b/src/impulse_ds/mdf/README.md index 3d74e500..33655b25 100644 --- a/src/impulse_ds/mdf/README.md +++ b/src/impulse_ds/mdf/README.md @@ -1,5 +1,8 @@ # impulse_ds.mdf +> ⚠️ **Experimental** — see [KNOWN_LIMITATIONS.md](KNOWN_LIMITATIONS.md) for spec +> coverage gaps and backlog items. + Convert ASAM **MDF4** measurement files to **Delta Lake** tables with PySpark / Databricks. The reader parses MDF4 binary blocks directly (no `asammdf` at runtime), so conversion parallelises across Spark workers, each reading only the @@ -8,12 +11,22 @@ bytes for its partition. Every output row is identified by `file_uri` — the source file path. **New to the data sources?** See [QUICKSTART.md](QUICKSTART.md) for minimal -examples of `mdf_signals`, `mdf_metadata`, and `mdf_masters`. +examples of `mdf_signals`, `mdf_metadata`, and `mdf_masters`. For experimental +status and known gaps, see [KNOWN_LIMITATIONS.md](KNOWN_LIMITATIONS.md). ## Solution Accelerator An end-to-end solution accelerator to convert mf4 files into the impulse schema will be available soon. + +## Acknowledgments + +The MDF data sources and low-level reader were implemented with reference to +[asammdf](https://github.com/danielhrisca/asammdf) by [Daniel Hrisca](https://github.com/danielhrisca). +`asammdf` is not a runtime dependency of this package; it is listed under test +dependencies only (see below) for synthesising small MDF4 fixtures. + + ## Two ways to use it ### 1. Custom Spark data sources (read MDF4 as DataFrames) @@ -199,33 +212,6 @@ Package path: `src/impulse_ds/mdf/` | `schemas.py` | shared Spark schemas (`SIGNALS_SCHEMA`, `METADATA_SCHEMA`) | - - -## Limitations (backlog) - -Known gaps in the numeric-first reader/converter. **Sorted** data groups (`rec_id_size = 0`) -and CC types 0–2, 4–6 work as expected. **Unsorted** data groups (`rec_id_size > 0`) -with interleaved channel groups are supported via per-CG record filtering on read. - - -| area | severity | status | -| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------- | --------------------------- | -| **VLSD channels** — variable-length signals store an offset in the fixed record; payload in SDBLOCK is not followed. Channels currently emit NaN. String/byte output would need schema changes. | MEDIUM | not implemented | -| **CC type 3 (algebraic / formula)** — formula text in `cc_ref[0]` (TXBLOCK) is not read or evaluated; `apply_cc_conversion` has no handler for type 3. | LOW–MEDIUM | not implemented | -| **CC types 7–10 (text conversions)** — require TXBLOCK / `cc_ref` resolution. Unsupported by design for the numeric-only `value` column; `_parse_cc_block` returns `(-1, ())` for `cc_type > 6`. | LOW | not implemented (by design) | - - -**CC types 7–10:** types 7, 8, 10 produce text (need a string extraction path / separate table); type 9 (text→value) could stay numeric but needs reference-text matching. - -**Unsorted DGs:** reads filter interleaved records by `record_id` before decode (`filter_unsorted_records` in `mdf_decode.py`). Stripe mode concatenates sub-blocks, then filters once per channel group. - -## Acknowledgments - -The MDF data sources and low-level reader were implemented with reference to -[asammdf](https://github.com/danielhrisca/asammdf) by [Daniel Hrisca](https://github.com/danielhrisca). -`asammdf` is not a runtime dependency of this package; it is listed under test -dependencies only (see below) for synthesising small MDF4 fixtures. - ## Dependencies - Runtime: `numpy`, `pyarrow` (`pyspark` is provided by the Databricks runtime). From 5cc9587f721aee18994466d9a316ae98a790a287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Br=C3=A4uer?= Date: Thu, 30 Jul 2026 08:24:24 +0200 Subject: [PATCH 4/8] renamed impulse_ds => impulse_data_sources --- src/{impulse_ds => impulse_data_sources}/__init__.py | 0 src/{impulse_ds => impulse_data_sources}/mdf/KNOWN_LIMITATIONS.md | 0 src/{impulse_ds => impulse_data_sources}/mdf/QUICKSTART.md | 0 src/{impulse_ds => impulse_data_sources}/mdf/README.md | 0 src/{impulse_ds => impulse_data_sources}/mdf/__init__.py | 0 src/{impulse_ds => impulse_data_sources}/mdf/arrow_emit.py | 0 src/{impulse_ds => impulse_data_sources}/mdf/bin_packer.py | 0 src/{impulse_ds => impulse_data_sources}/mdf/converter.py | 0 src/{impulse_ds => impulse_data_sources}/mdf/datasources.py | 0 src/{impulse_ds => impulse_data_sources}/mdf/mdf4_reader.py | 0 src/{impulse_ds => impulse_data_sources}/mdf/mdf_blocks.py | 0 src/{impulse_ds => impulse_data_sources}/mdf/mdf_decode.py | 0 src/{impulse_ds => impulse_data_sources}/mdf/schemas.py | 0 src/{impulse_ds => impulse_data_sources}/mdf/udf_helpers.py | 0 14 files changed, 0 insertions(+), 0 deletions(-) rename src/{impulse_ds => impulse_data_sources}/__init__.py (100%) rename src/{impulse_ds => impulse_data_sources}/mdf/KNOWN_LIMITATIONS.md (100%) rename src/{impulse_ds => impulse_data_sources}/mdf/QUICKSTART.md (100%) rename src/{impulse_ds => impulse_data_sources}/mdf/README.md (100%) rename src/{impulse_ds => impulse_data_sources}/mdf/__init__.py (100%) rename src/{impulse_ds => impulse_data_sources}/mdf/arrow_emit.py (100%) rename src/{impulse_ds => impulse_data_sources}/mdf/bin_packer.py (100%) rename src/{impulse_ds => impulse_data_sources}/mdf/converter.py (100%) rename src/{impulse_ds => impulse_data_sources}/mdf/datasources.py (100%) rename src/{impulse_ds => impulse_data_sources}/mdf/mdf4_reader.py (100%) rename src/{impulse_ds => impulse_data_sources}/mdf/mdf_blocks.py (100%) rename src/{impulse_ds => impulse_data_sources}/mdf/mdf_decode.py (100%) rename src/{impulse_ds => impulse_data_sources}/mdf/schemas.py (100%) rename src/{impulse_ds => impulse_data_sources}/mdf/udf_helpers.py (100%) diff --git a/src/impulse_ds/__init__.py b/src/impulse_data_sources/__init__.py similarity index 100% rename from src/impulse_ds/__init__.py rename to src/impulse_data_sources/__init__.py diff --git a/src/impulse_ds/mdf/KNOWN_LIMITATIONS.md b/src/impulse_data_sources/mdf/KNOWN_LIMITATIONS.md similarity index 100% rename from src/impulse_ds/mdf/KNOWN_LIMITATIONS.md rename to src/impulse_data_sources/mdf/KNOWN_LIMITATIONS.md diff --git a/src/impulse_ds/mdf/QUICKSTART.md b/src/impulse_data_sources/mdf/QUICKSTART.md similarity index 100% rename from src/impulse_ds/mdf/QUICKSTART.md rename to src/impulse_data_sources/mdf/QUICKSTART.md diff --git a/src/impulse_ds/mdf/README.md b/src/impulse_data_sources/mdf/README.md similarity index 100% rename from src/impulse_ds/mdf/README.md rename to src/impulse_data_sources/mdf/README.md diff --git a/src/impulse_ds/mdf/__init__.py b/src/impulse_data_sources/mdf/__init__.py similarity index 100% rename from src/impulse_ds/mdf/__init__.py rename to src/impulse_data_sources/mdf/__init__.py diff --git a/src/impulse_ds/mdf/arrow_emit.py b/src/impulse_data_sources/mdf/arrow_emit.py similarity index 100% rename from src/impulse_ds/mdf/arrow_emit.py rename to src/impulse_data_sources/mdf/arrow_emit.py diff --git a/src/impulse_ds/mdf/bin_packer.py b/src/impulse_data_sources/mdf/bin_packer.py similarity index 100% rename from src/impulse_ds/mdf/bin_packer.py rename to src/impulse_data_sources/mdf/bin_packer.py diff --git a/src/impulse_ds/mdf/converter.py b/src/impulse_data_sources/mdf/converter.py similarity index 100% rename from src/impulse_ds/mdf/converter.py rename to src/impulse_data_sources/mdf/converter.py diff --git a/src/impulse_ds/mdf/datasources.py b/src/impulse_data_sources/mdf/datasources.py similarity index 100% rename from src/impulse_ds/mdf/datasources.py rename to src/impulse_data_sources/mdf/datasources.py diff --git a/src/impulse_ds/mdf/mdf4_reader.py b/src/impulse_data_sources/mdf/mdf4_reader.py similarity index 100% rename from src/impulse_ds/mdf/mdf4_reader.py rename to src/impulse_data_sources/mdf/mdf4_reader.py diff --git a/src/impulse_ds/mdf/mdf_blocks.py b/src/impulse_data_sources/mdf/mdf_blocks.py similarity index 100% rename from src/impulse_ds/mdf/mdf_blocks.py rename to src/impulse_data_sources/mdf/mdf_blocks.py diff --git a/src/impulse_ds/mdf/mdf_decode.py b/src/impulse_data_sources/mdf/mdf_decode.py similarity index 100% rename from src/impulse_ds/mdf/mdf_decode.py rename to src/impulse_data_sources/mdf/mdf_decode.py diff --git a/src/impulse_ds/mdf/schemas.py b/src/impulse_data_sources/mdf/schemas.py similarity index 100% rename from src/impulse_ds/mdf/schemas.py rename to src/impulse_data_sources/mdf/schemas.py diff --git a/src/impulse_ds/mdf/udf_helpers.py b/src/impulse_data_sources/mdf/udf_helpers.py similarity index 100% rename from src/impulse_ds/mdf/udf_helpers.py rename to src/impulse_data_sources/mdf/udf_helpers.py From 04ab77c92a6c20fe82756b7467863513be562f95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Br=C3=A4uer?= Date: Thu, 30 Jul 2026 16:31:23 +0200 Subject: [PATCH 5/8] code cleanup for pylint --- pyproject.toml | 2 +- src/impulse_data_sources/mdf/arrow_emit.py | 268 +++-- src/impulse_data_sources/mdf/bin_packer.py | 97 +- src/impulse_data_sources/mdf/converter.py | 170 +-- src/impulse_data_sources/mdf/datasources.py | 149 ++- src/impulse_data_sources/mdf/mdf4_reader.py | 133 +-- src/impulse_data_sources/mdf/mdf_blocks.py | 55 +- src/impulse_data_sources/mdf/mdf_decode.py | 156 ++- src/impulse_data_sources/mdf/schemas.py | 37 +- src/impulse_data_sources/mdf/udf_helpers.py | 19 +- tests/impulse_ds/mdf/_block_fixtures.py | 33 +- tests/impulse_ds/mdf/_mdf_samples.py | 7 +- tests/impulse_ds/mdf/conftest.py | 36 + tests/impulse_ds/mdf/test_arrow_emit.py | 1 + tests/impulse_ds/mdf/test_bin_packer.py | 46 +- tests/impulse_ds/mdf/test_datasources.py | 160 ++- tests/impulse_ds/mdf/test_mdf4_reader.py | 157 ++- tests/impulse_ds/mdf/test_mdf_blocks.py | 21 +- .../impulse_ds/mdf/test_mdf_coverage_gaps.py | 977 +++++++++++++----- tests/impulse_ds/mdf/test_unsorted_dg.py | 71 +- 20 files changed, 1830 insertions(+), 765 deletions(-) create mode 100644 tests/impulse_ds/mdf/conftest.py diff --git a/pyproject.toml b/pyproject.toml index 38000104..91208c6d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -138,7 +138,7 @@ ignore = [ convention = "numpy" [tool.ruff.lint.isort] -known-first-party = ["impulse_query_engine", "impulse_reporting", "impulse_ds"] +known-first-party = ["impulse_query_engine", "impulse_reporting", "impulse_ds", "impulse_data_sources"] [tool.black] line-length = 99 diff --git a/src/impulse_data_sources/mdf/arrow_emit.py b/src/impulse_data_sources/mdf/arrow_emit.py index 0c11a7c4..a11a24a5 100644 --- a/src/impulse_data_sources/mdf/arrow_emit.py +++ b/src/impulse_data_sources/mdf/arrow_emit.py @@ -9,17 +9,23 @@ plus run-length encoding (collapse constant runs into [tstart, tend) intervals). """ + import numpy as np from .mdf_blocks import ( - dt_data_extent, resolve_dl_addr, read_data_list_range, read_raw_data, - _decompress_subblock_blob, _read_block_chunks, + dt_data_extent, + resolve_dl_addr, + read_data_list_range, + read_raw_data, + _decompress_subblock_blob, + _read_block_chunks, ) from .mdf_decode import extract_signal, extract_timestamps, prepare_cg_records def _pa_float(dtype): import pyarrow as pa + return pa.float32() if str(dtype) == "float32" else pa.float64() @@ -55,7 +61,10 @@ def _emit_prepared_signal_group( t0 = _now() if master_info is not None: timestamps = extract_timestamps( - raw_data, record_size, master_info, index_offset=index_offset, + raw_data, + record_size, + master_info, + index_offset=index_offset, ) else: timestamps = np.arange(index_offset, index_offset + actual, dtype=np.float64) @@ -73,7 +82,9 @@ def _emit_prepared_signal_group( except Exception as e: log.warning( "extract failed ch=%s block=%d: %s", - ch_spec.get("channel_id"), data_block_addr, e, + ch_spec.get("channel_id"), + data_block_addr, + e, ) @@ -129,23 +140,23 @@ def _rle_compress_chunk(ts, vs, carry): else: # Value changed at this chunk's first sample: close the carried run # there (zero-order hold to the change point). - seg_t0.append(np.array([c_t0])); seg_t1.append(np.array([ts[0]])) + seg_t0.append(np.array([c_t0])) + seg_t1.append(np.array([ts[0]])) seg_v.append(np.array([c_val])) if m >= 2: - t0 = run_t0[:m - 1].copy() + t0 = run_t0[: m - 1].copy() t0[0] = first_t0 seg_t0.append(t0) - seg_t1.append(run_t0[1:m]) # tend = start of the next run - seg_v.append(run_vals[:m - 1]) + seg_t1.append(run_t0[1:m]) # tend = start of the next run + seg_v.append(run_vals[: m - 1]) new_carry = [run_vals[m - 1], run_t0[m - 1], last_ts] else: # Whole chunk is a single run; it remains open. new_carry = [run_vals[0], first_t0, last_ts] if seg_v: - return (np.concatenate(seg_t0), np.concatenate(seg_t1), - np.concatenate(seg_v)), new_carry + return (np.concatenate(seg_t0), np.concatenate(seg_t1), np.concatenate(seg_v)), new_carry return None, new_carry @@ -165,13 +176,11 @@ def _rle_flush(carry): return None c_val, c_t0, c_last = carry if c_t0 < c_last: - return (np.array([c_t0, c_last]), np.array([c_last, c_last]), - np.array([c_val, c_val])) + return (np.array([c_t0, c_last]), np.array([c_last, c_last]), np.array([c_val, c_val])) return np.array([c_last]), np.array([c_last]), np.array([c_val]) -def signals_arrow_schema(time_dtype="float64", value_dtype="float64", - run_length_encoding=False): +def signals_arrow_schema(time_dtype="float64", value_dtype="float64", run_length_encoding=False): """Arrow schema for emitted signal batches. time/value default to float64 but can be float32 (halves their on-disk bytes) per the data-source options. value is nullable to accept NaN/None invalid samples. @@ -182,36 +191,52 @@ def signals_arrow_schema(time_dtype="float64", value_dtype="float64", (tstart == tend == last timestamp) so the final sample is recoverable. """ import pyarrow as pa + if run_length_encoding: - return pa.schema([ + return pa.schema( + [ + pa.field("file_uri", pa.string(), nullable=False), + pa.field("channel_id", pa.int32(), nullable=False), + pa.field("tstart", _pa_float(time_dtype), nullable=False), + pa.field("tend", _pa_float(time_dtype), nullable=False), + pa.field("value", _pa_float(value_dtype), nullable=True), + ] + ) + return pa.schema( + [ pa.field("file_uri", pa.string(), nullable=False), pa.field("channel_id", pa.int32(), nullable=False), - pa.field("tstart", _pa_float(time_dtype), nullable=False), - pa.field("tend", _pa_float(time_dtype), nullable=False), + pa.field("time", _pa_float(time_dtype), nullable=False), pa.field("value", _pa_float(value_dtype), nullable=True), - ]) - return pa.schema([ - pa.field("file_uri", pa.string(), nullable=False), - pa.field("channel_id", pa.int32(), nullable=False), - pa.field("time", _pa_float(time_dtype), nullable=False), - pa.field("value", _pa_float(value_dtype), nullable=True), - ]) + ] + ) def master_arrow_schema(time_dtype="float64"): """Arrow schema for the master time-base output: one row per ORIGINAL sample of each group's master channel (file_uri, group_idx, timestamp).""" import pyarrow as pa - return pa.schema([ - pa.field("file_uri", pa.string(), nullable=False), - pa.field("group_idx", pa.int32(), nullable=False), - pa.field("timestamp", _pa_float(time_dtype), nullable=False), - ]) - -def _make_signal_emitters(file_uri, output_schema, pa_time, pa_value, - np_time, np_value, run_length_encoding, prof, - max_batch_rows=2_000_000): + return pa.schema( + [ + pa.field("file_uri", pa.string(), nullable=False), + pa.field("group_idx", pa.int32(), nullable=False), + pa.field("timestamp", _pa_float(time_dtype), nullable=False), + ] + ) + + +def _make_signal_emitters( + file_uri, + output_schema, + pa_time, + pa_value, + np_time, + np_value, + run_length_encoding, + prof, + max_batch_rows=2_000_000, +): """Build the ``(emit_fn, flush_fn)`` pair shared by the per-group and stripe signal converters, so both inherit identical batching/RLE behaviour. @@ -231,6 +256,7 @@ def _make_signal_emitters(file_uri, output_schema, pa_time, pa_value, zero-width point row per channel).""" import time import pyarrow as pa + _now = time.perf_counter_ns uri_cache = [] @@ -238,7 +264,8 @@ def _make_signal_emitters(file_uri, output_schema, pa_time, pa_value, def _uri_const(): if not uri_cache: uri_cache.append( - pa.array(np.full(max_batch_rows, file_uri, dtype=object), type=pa.string())) + pa.array(np.full(max_batch_rows, file_uri, dtype=object), type=pa.string()) + ) return uri_cache[0] def _emit_points(timestamps, values, channel_id): @@ -247,8 +274,9 @@ def _emit_points(timestamps, values, channel_id): return cont_full = _uri_const() t0 = _now() - chan_full = pa.array(np.full(min(n, max_batch_rows), channel_id, dtype=np.int32), - type=pa.int32()) + chan_full = pa.array( + np.full(min(n, max_batch_rows), channel_id, dtype=np.int32), type=pa.int32() + ) prof["arrow"] += _now() - t0 for offset in range(0, n, max_batch_rows): end = min(offset + max_batch_rows, n) @@ -261,9 +289,14 @@ def _emit_points(timestamps, values, channel_id): if np_value is np.float32: vs = vs.astype(np.float32) rb = pa.RecordBatch.from_arrays( - [cont_full.slice(0, clen), chan_full.slice(0, clen), - pa.array(ts, type=pa_time), pa.array(vs, type=pa_value)], - schema=output_schema) + [ + cont_full.slice(0, clen), + chan_full.slice(0, clen), + pa.array(ts, type=pa_time), + pa.array(vs, type=pa_value), + ], + schema=output_schema, + ) prof["arrow"] += _now() - t1 prof["rows"] += clen yield rb @@ -282,17 +315,25 @@ def _emit_rle_batch(t0arr, t1arr, varr, channel_id): end = min(offset + max_batch_rows, n) clen = end - offset _ta = _now() - t0 = t0arr[offset:end]; te = t1arr[offset:end]; vv = varr[offset:end] + t0 = t0arr[offset:end] + te = t1arr[offset:end] + vv = varr[offset:end] if np_time is np.float32: - t0 = t0.astype(np.float32); te = te.astype(np.float32) + t0 = t0.astype(np.float32) + te = te.astype(np.float32) if np_value is np.float32: vv = vv.astype(np.float32) chan_full = pa.array(np.full(clen, channel_id, dtype=np.int32), type=pa.int32()) rb = pa.RecordBatch.from_arrays( - [cont_full.slice(0, clen), chan_full, - pa.array(t0, type=pa_time), pa.array(te, type=pa_time), - pa.array(vv, type=pa_value)], - schema=output_schema) + [ + cont_full.slice(0, clen), + chan_full, + pa.array(t0, type=pa_time), + pa.array(te, type=pa_time), + pa.array(vv, type=pa_value), + ], + schema=output_schema, + ) prof["arrow"] += _now() - _ta prof["rows"] += clen yield rb @@ -313,8 +354,9 @@ def flush_fn(): return emit_fn, flush_fn -def convert_spec_to_arrow_batches(spec, prof=None, time_dtype="float64", value_dtype="float64", - run_length_encoding=False): +def convert_spec_to_arrow_batches( + spec, prof=None, time_dtype="float64", value_dtype="float64", run_length_encoding=False +): """ Convert ONE partition spec into an iterator of pyarrow.RecordBatch with the signals schema (file_uri, channel_id, time, value). @@ -372,8 +414,8 @@ def convert_spec_to_arrow_batches(spec, prof=None, time_dtype="float64", value_d # or run-length-encoded interval rows. flush_fn() drains any state held back # between read chunks (only RLE carries a trailing open run). emit_fn, flush_fn = _make_signal_emitters( - file_uri, output_schema, pa_time, pa_value, np_time, np_value, - run_length_encoding, prof) + file_uri, output_schema, pa_time, pa_value, np_time, np_value, run_length_encoding, prof + ) block_groups = {} for ch_spec in channels_spec: @@ -397,8 +439,9 @@ def convert_spec_to_arrow_batches(spec, prof=None, time_dtype="float64", value_d raw_data = read_raw_data(f, data_block_addr, record_size, sample_count) prof["read"] += _now() - t0 except Exception as e: - log.warning("read_raw_data failed at %d in %s: %s", - data_block_addr, file_path, e) + log.warning( + "read_raw_data failed at %d in %s: %s", data_block_addr, file_path, e + ) continue raw_data, index_offset = prepare_cg_records( raw_data, @@ -408,8 +451,16 @@ def convert_spec_to_arrow_batches(spec, prof=None, time_dtype="float64", value_d **us, ) yield from _emit_prepared_signal_group( - raw_data, group_channels, record_size, master_info, - time_offset, emit_fn, prof, log, data_block_addr, _now, + raw_data, + group_channels, + record_size, + master_info, + time_offset, + emit_fn, + prof, + log, + data_block_addr, + _now, index_offset=index_offset, ) continue @@ -417,8 +468,9 @@ def convert_spec_to_arrow_batches(spec, prof=None, time_dtype="float64", value_d try: extent = dt_data_extent(f, data_block_addr) except Exception as e: - log.warning("DT extent probe failed at %d in %s: %s", - data_block_addr, file_path, e) + log.warning( + "DT extent probe failed at %d in %s: %s", data_block_addr, file_path, e + ) extent = None if extent is not None: @@ -429,7 +481,11 @@ def convert_spec_to_arrow_batches(spec, prof=None, time_dtype="float64", value_d continue # Honor the planner's record-range slice (defaults to whole block). lo = 0 if spec_row_start is None else max(0, min(spec_row_start, total_records)) - hi = total_records if spec_row_end is None else max(lo, min(spec_row_end, total_records)) + hi = ( + total_records + if spec_row_end is None + else max(lo, min(spec_row_end, total_records)) + ) if hi <= lo: continue chunk_records = max(1, _CHUNK_BYTES // record_size) @@ -446,7 +502,10 @@ def convert_spec_to_arrow_batches(spec, prof=None, time_dtype="float64", value_d t0 = _now() if master_info is not None: timestamps = extract_timestamps( - raw_chunk, record_size, master_info, index_offset=rec0, + raw_chunk, + record_size, + master_info, + index_offset=rec0, ) else: timestamps = np.arange(rec0, rec0 + actual, dtype=np.float64) @@ -461,11 +520,17 @@ def convert_spec_to_arrow_batches(spec, prof=None, time_dtype="float64", value_d if values is None: continue yield from emit_fn( - timestamps, values, ch_spec["channel_id"], + timestamps, + values, + ch_spec["channel_id"], ) except Exception as e: - log.warning("extract failed ch=%s block=%d: %s", - ch_spec.get("channel_id"), data_block_addr, e) + log.warning( + "extract failed ch=%s block=%d: %s", + ch_spec.get("channel_id"), + data_block_addr, + e, + ) continue continue @@ -478,7 +543,11 @@ def convert_spec_to_arrow_batches(spec, prof=None, time_dtype="float64", value_d re_hi = spec_row_end if spec_row_end is not None else (1 << 62) t0 = _now() raw_data, start_rec = read_data_list_range( - f, dl_addr, record_size, spec_row_start, re_hi, + f, + dl_addr, + record_size, + spec_row_start, + re_hi, ) prof["read"] += _now() - t0 actual = len(raw_data) // record_size if record_size else 0 @@ -487,7 +556,10 @@ def convert_spec_to_arrow_batches(spec, prof=None, time_dtype="float64", value_d t0 = _now() if master_info is not None: timestamps = extract_timestamps( - raw_data, record_size, master_info, index_offset=start_rec, + raw_data, + record_size, + master_info, + index_offset=start_rec, ) else: timestamps = np.arange(start_rec, start_rec + actual, dtype=np.float64) @@ -502,11 +574,17 @@ def convert_spec_to_arrow_batches(spec, prof=None, time_dtype="float64", value_d if values is None: continue yield from emit_fn( - timestamps, values, ch_spec["channel_id"], + timestamps, + values, + ch_spec["channel_id"], ) except Exception as e: - log.warning("extract failed ch=%s block=%d: %s", - ch_spec.get("channel_id"), data_block_addr, e) + log.warning( + "extract failed ch=%s block=%d: %s", + ch_spec.get("channel_id"), + data_block_addr, + e, + ) continue continue @@ -519,8 +597,7 @@ def convert_spec_to_arrow_batches(spec, prof=None, time_dtype="float64", value_d raw_data = read_raw_data(f, data_block_addr, record_size, sample_count) prof["read"] += _now() - t0 except Exception as e: - log.warning("read_raw_data failed at %d in %s: %s", - data_block_addr, file_path, e) + log.warning("read_raw_data failed at %d in %s: %s", data_block_addr, file_path, e) continue total = len(raw_data) // record_size if record_size else 0 if total == 0: @@ -536,11 +613,20 @@ def convert_spec_to_arrow_batches(spec, prof=None, time_dtype="float64", value_d ) else: raw_data, start_rec = prepare_cg_records( - raw_data, record_size=record_size, + raw_data, + record_size=record_size, ) yield from _emit_prepared_signal_group( - raw_data, group_channels, record_size, master_info, - time_offset, emit_fn, prof, log, data_block_addr, _now, + raw_data, + group_channels, + record_size, + master_info, + time_offset, + emit_fn, + prof, + log, + data_block_addr, + _now, index_offset=start_rec, ) @@ -590,7 +676,8 @@ def convert_master_spec_to_arrow_batches(spec, prof=None, time_dtype="float64"): def _uri_const(): if not _uri_full_cache: _uri_full_cache.append( - pa.array(np.full(_MAX_BATCH_ROWS, file_uri, dtype=object), type=pa.string())) + pa.array(np.full(_MAX_BATCH_ROWS, file_uri, dtype=object), type=pa.string()) + ) return _uri_full_cache[0] def _emit(ts, group_idx): @@ -637,7 +724,14 @@ def _emit(ts, group_idx): continue for raw, start in _read_block_chunks( - f, mspec["data_block_addr"], rs, sc, r0, r1, prof, log, + f, + mspec["data_block_addr"], + rs, + sc, + r0, + r1, + prof, + log, rec_id_size=mspec.get("rec_id_size", 0), record_id=mspec.get("record_id", 0), cg_record_sizes=mspec.get("cg_record_sizes"), @@ -650,8 +744,9 @@ def _emit(ts, group_idx): yield from _emit(ts, gid) -def convert_stripe_spec_to_arrow_batches(spec, prof=None, time_dtype="float64", - value_dtype="float64", run_length_encoding=False): +def convert_stripe_spec_to_arrow_batches( + spec, prof=None, time_dtype="float64", value_dtype="float64", run_length_encoding=False +): """Decode ONE byte-offset stripe (Design B): a contiguous file region holding a set of data sub-blocks from possibly several groups. The whole region is read in ONE sequential IO, then each sub-block is decompressed + extracted from RAM. @@ -686,8 +781,8 @@ def convert_stripe_spec_to_arrow_batches(spec, prof=None, time_dtype="float64", # Same emission dispatch as convert_spec_to_arrow_batches (per-sample or RLE). emit_fn, flush_fn = _make_signal_emitters( - file_uri, output_schema, pa_time, pa_value, np_time, np_value, - run_length_encoding, prof) + file_uri, output_schema, pa_time, pa_value, np_time, np_value, run_length_encoding, prof + ) # One sequential read of the whole stripe. t0 = _now() @@ -721,15 +816,24 @@ def convert_stripe_spec_to_arrow_batches(spec, prof=None, time_dtype="float64", parts.append(_decompress_subblock_blob(blob, rel)) prof["decode"] += _now() - t0 except Exception as e: - log.warning("stripe decompress failed gidx=%s off=%d: %s", - gidx, sb["abs_off"], e) + log.warning( + "stripe decompress failed gidx=%s off=%d: %s", gidx, sb["abs_off"], e + ) if not parts: continue raw = b"".join(parts) raw, index_offset = prepare_cg_records(raw, record_size=record_size, **us) yield from _emit_prepared_signal_group( - raw, channels, record_size, master_info, time_offset, - emit_fn, prof, log, meta.get("data_block_addr", 0), _now, + raw, + channels, + record_size, + master_info, + time_offset, + emit_fn, + prof, + log, + meta.get("data_block_addr", 0), + _now, index_offset=index_offset, ) continue @@ -748,7 +852,9 @@ def convert_stripe_spec_to_arrow_batches(spec, prof=None, time_dtype="float64", continue t0 = _now() if master_info is not None: - ts = extract_timestamps(raw, record_size, master_info, index_offset=sb["rec_start"]) + ts = extract_timestamps( + raw, record_size, master_info, index_offset=sb["rec_start"] + ) else: ts = np.arange(sb["rec_start"], sb["rec_start"] + actual, dtype=np.float64) if time_offset: diff --git a/src/impulse_data_sources/mdf/bin_packer.py b/src/impulse_data_sources/mdf/bin_packer.py index 46b00edd..96f9aec3 100644 --- a/src/impulse_data_sources/mdf/bin_packer.py +++ b/src/impulse_data_sources/mdf/bin_packer.py @@ -8,8 +8,6 @@ planner, and `plan_master_partitions` plans the per-group master time base. """ -from typing import Dict, List - from .mdf4_reader import MDF4Reader @@ -26,7 +24,7 @@ def plan_partitions( max_groups_per_partition: int = 64, time_offset: float = 0.0, unsorted_dg_ctx: dict = None, -) -> List[dict]: +) -> list[dict]: """ Plan Spark partitions for one MDF file, decoupling parallelism from channel count so executors stay saturated and a single dominant channel group no @@ -69,7 +67,7 @@ def plan_partitions( target_rows = max(1, int(target_partition_mb * 1024 * 1024 / 16)) ctx = unsorted_dg_ctx or {} - groups: Dict[int, list] = {} + groups: dict[int, list] = {} for ch in signal_channels: groups.setdefault(ch.group_idx, []).append(ch) @@ -86,9 +84,14 @@ def _ch_dict(ch): return d def _spec(ch_dicts, r0=None, r1=None): - s = {"file_path": file_path, "channels": ch_dicts, - "time_dtype": time_dtype, "value_dtype": value_dtype, - "run_length_encoding": run_length_encoding, "time_offset": time_offset} + s = { + "file_path": file_path, + "channels": ch_dicts, + "time_dtype": time_dtype, + "value_dtype": value_dtype, + "run_length_encoding": run_length_encoding, + "time_offset": time_offset, + } if r0 is not None: s["row_start"] = r0 s["row_end"] = r1 @@ -100,10 +103,10 @@ def _spec(ch_dicts, r0=None, r1=None): # FUSE-mounted volume those are scattered cold reads ~10-25 ms each, i.e. # minutes for 30k+ groups — a planning blocker.) Block type is resolved at # READ time on executors instead (DT seek / DL sub-block range / DZ slice). - specs: List[dict] = [] + specs: list[dict] = [] # Open bin for coalescing small (single-partition) groups. Flushed when it # reaches ~target_rows of output or max_groups_per_partition groups. - pending_ch: List[dict] = [] + pending_ch: list[dict] = [] pending_rows = 0 pending_groups = 0 @@ -126,7 +129,7 @@ def _flush_small(): # Wide group: split by channel subset (no channel-list duplication). ch_per_part = max(1, target_rows // group_records) for i in range(0, c, ch_per_part): - specs.append(_spec(ch_dicts[i:i + ch_per_part])) + specs.append(_spec(ch_dicts[i : i + ch_per_part])) else: rows_per_part = max(1, target_rows // c) if rows_per_part >= group_records: @@ -159,7 +162,7 @@ def plan_master_partitions( max_groups_per_partition: int = 64, time_offset: float = 0.0, unsorted_dg_ctx: dict = None, -) -> List[dict]: +) -> list[dict]: """ Plan Spark partitions for the MASTER channels of one MDF file — the time base of each acquisition group, one master per group, emitted as one row per @@ -194,15 +197,19 @@ def _master_entry(group_idx, m): return entry def _spec(masters, r0=None, r1=None): - s = {"file_path": file_path, - "time_dtype": time_dtype, "masters": masters, "time_offset": time_offset} + s = { + "file_path": file_path, + "time_dtype": time_dtype, + "masters": masters, + "time_offset": time_offset, + } if r0 is not None: s["row_start"] = r0 s["row_end"] = r1 return s - specs: List[dict] = [] - pending: List[dict] = [] + specs: list[dict] = [] + pending: list[dict] = [] pending_rows = 0 def _flush(): @@ -250,7 +257,7 @@ def plan_stripes_for_file( gap_threshold_mb: float = 8.0, max_subblocks_per_stripe: int = 4096, file_bytes: bytes = None, -) -> List[dict]: +) -> list[dict]: """Design B planner: read the file ONCE (in RAM), build a sub-block map, and pack sub-blocks — sorted by file offset — into contiguous byte-offset STRIPES. @@ -293,7 +300,7 @@ def _chd(ch): return d bio = io.BytesIO(file_bytes) - by_group: Dict[int, list] = {} + by_group: dict[int, list] = {} for ch in signal_channels: by_group.setdefault(ch.group_idx, []).append(ch) @@ -318,17 +325,19 @@ def _chd(ch): } meta.update(unsorted_fields_from_ctx(ch0.dg_block_addr, ch0.record_id, unsorted_dg_ctx)) groups_meta[group_idx] = meta - for (soff, slen, rstart, rcount) in parse_subblocks(bio, ch0.data_block_addr, rs, sc): + for soff, slen, rstart, rcount in parse_subblocks(bio, ch0.data_block_addr, rs, sc): if rcount <= 0 and slen <= 0: continue - subblocks.append({ - "group_idx": group_idx, - "grp": ch0.data_block_addr, - "abs_off": soff, - "on_disk_len": slen, - "rec_start": rstart, - "rec_count": rcount, - }) + subblocks.append( + { + "group_idx": group_idx, + "grp": ch0.data_block_addr, + "abs_off": soff, + "on_disk_len": slen, + "rec_start": rstart, + "rec_count": rcount, + } + ) subblocks.sort(key=lambda s: s["abs_off"]) @@ -341,24 +350,34 @@ def _chd(ch): def _flush(): nonlocal cur, cur_rows, cur_bytes, cur_lo, cur_hi, cur_grps if cur: - specs.append({ - "file_path": file_path, - "byte_start": cur_lo, "byte_end": cur_hi, - "time_dtype": time_dtype, "value_dtype": value_dtype, - "run_length_encoding": run_length_encoding, "time_offset": time_offset, - "groups": {str(g): groups_meta[g] for g in cur_grps}, - "subblocks": cur, - }) - cur = []; cur_rows = cur_bytes = 0; cur_lo = cur_hi = None; cur_grps = set() + specs.append( + { + "file_path": file_path, + "byte_start": cur_lo, + "byte_end": cur_hi, + "time_dtype": time_dtype, + "value_dtype": value_dtype, + "run_length_encoding": run_length_encoding, + "time_offset": time_offset, + "groups": {str(g): groups_meta[g] for g in cur_grps}, + "subblocks": cur, + } + ) + cur = [] + cur_rows = cur_bytes = 0 + cur_lo = cur_hi = None + cur_grps = set() for sb in subblocks: gidx = sb["group_idx"] rows = sb["rec_count"] * groups_meta[gidx]["n_channels"] gap = (sb["abs_off"] - cur_hi) if cur_hi is not None else 0 - if cur and (cur_rows + rows > target_rows - or cur_bytes + sb["on_disk_len"] > stripe_bytes_cap - or gap > gap_threshold - or len(cur) >= max_subblocks_per_stripe): + if cur and ( + cur_rows + rows > target_rows + or cur_bytes + sb["on_disk_len"] > stripe_bytes_cap + or gap > gap_threshold + or len(cur) >= max_subblocks_per_stripe + ): _flush() cur.append(sb) cur_rows += rows diff --git a/src/impulse_data_sources/mdf/converter.py b/src/impulse_data_sources/mdf/converter.py index 943e2fe7..23473512 100644 --- a/src/impulse_data_sources/mdf/converter.py +++ b/src/impulse_data_sources/mdf/converter.py @@ -12,21 +12,20 @@ import time from datetime import datetime -from typing import List, Dict, Optional, Tuple from dataclasses import dataclass from pyspark.sql import SparkSession -from pyspark.sql.types import ( - StructType, StructField, IntegerType, StringType -) +from pyspark.sql.types import StructType, StructField, IntegerType, StringType from .mdf4_reader import ( - MDF4Reader, ChannelInfo, CN_TYPE_MASTER, CN_TYPE_VIRTUAL_MASTER, + MDF4Reader, + ChannelInfo, + CN_TYPE_MASTER, + CN_TYPE_VIRTUAL_MASTER, ) from .bin_packer import plan_partitions from .schemas import METADATA_SCHEMA - _artifacts_shipped = False @@ -49,6 +48,7 @@ def _ensure_artifacts_shipped(spark: SparkSession): import pathlib import zipfile import tempfile + package_dir = pathlib.Path(__file__).parent impulse_ds_dir = package_dir.parent # Ship as a zip to preserve package structure (import impulse_ds.mdf.*) @@ -64,6 +64,7 @@ def _ensure_artifacts_shipped(spark: SparkSession): @dataclass class ConversionResult: """Result of an MDF to Delta conversion.""" + file_uri: str file_path: str num_channels: int @@ -152,16 +153,17 @@ def convert( raise ValueError(f"No channels found in {file_path}") # Step 2: Identify master channels per group and build channel map - master_channels, signal_channels, channel_id_map = self._organize_channels( - all_channels - ) + master_channels, signal_channels, channel_id_map = self._organize_channels(all_channels) # Step 3: Write metadata table self._write_metadata(signal_channels, channel_id_map, file_path, header_datetime) # Step 4: Plan record-range / channel-subset partitions partition_specs = self._plan( - file_path, master_channels, signal_channels, channel_id_map, + file_path, + master_channels, + signal_channels, + channel_id_map, unsorted_dg_ctx=reader._unsorted_dg_ctx, ) @@ -183,8 +185,8 @@ def convert( ) def _organize_channels( - self, channels: List[ChannelInfo] - ) -> Tuple[Dict[int, ChannelInfo], List[ChannelInfo], Dict[Tuple[int, int], int]]: + self, channels: list[ChannelInfo] + ) -> tuple[dict[int, ChannelInfo], list[ChannelInfo], dict[tuple[int, int], int]]: """ Separate master and signal channels, assign channel IDs. @@ -193,9 +195,9 @@ def _organize_channels( - signal_channels: list of non-master channels - channel_id_map: {(group_idx, channel_idx): channel_id} """ - master_channels: Dict[int, ChannelInfo] = {} - signal_channels: List[ChannelInfo] = [] - channel_id_map: Dict[Tuple[int, int], int] = {} + master_channels: dict[int, ChannelInfo] = {} + signal_channels: list[ChannelInfo] = [] + channel_id_map: dict[tuple[int, int], int] = {} channel_id = 0 for ch in channels: @@ -236,9 +238,13 @@ def _plan( """Plan partition specs for one file using this converter's settings. Shared by convert() and convert_batch_parallel().""" return plan_partitions( - file_path, master_channels, signal_channels, channel_id_map, + file_path, + master_channels, + signal_channels, + channel_id_map, target_partition_mb=self.target_partition_mb, - time_dtype=self.time_dtype, value_dtype=self.value_dtype, + time_dtype=self.time_dtype, + value_dtype=self.value_dtype, run_length_encoding=self.run_length_encoding, max_groups_per_partition=self.max_groups_per_partition, unsorted_dg_ctx=unsorted_dg_ctx, @@ -246,19 +252,20 @@ def _plan( def _write_metadata( self, - signal_channels: List[ChannelInfo], - channel_id_map: Dict[Tuple[int, int], int], + signal_channels: list[ChannelInfo], + channel_id_map: dict[tuple[int, int], int], file_uri: str, - header_datetime: Optional[datetime], + header_datetime: datetime | None, ): """Write channel metadata to the metadata Delta table.""" metadata_rows = self._metadata_rows( - signal_channels, channel_id_map, file_uri, header_datetime) + signal_channels, channel_id_map, file_uri, header_datetime + ) if metadata_rows: meta_df = self.spark.createDataFrame(metadata_rows, schema=METADATA_SCHEMA) _write_metadata_df(meta_df, self.metadata_table, "append") - def _run_spark_conversion(self, partition_specs: List[dict], mode: str): + def _run_spark_conversion(self, partition_specs: list[dict], mode: str): """ Execute the distributed conversion using mapInArrow for vectorized processing. @@ -273,10 +280,12 @@ def _run_spark_conversion(self, partition_specs: List[dict], mode: str): # Create a seed DataFrame with one row per partition seed_df = self.spark.createDataFrame( [(i, spec_strings[i]) for i in range(len(spec_strings))], - schema=StructType([ - StructField("partition_id", IntegerType(), False), - StructField("spec_json", StringType(), False), - ]) + schema=StructType( + [ + StructField("partition_id", IntegerType(), False), + StructField("spec_json", StringType(), False), + ] + ), ).repartition(len(spec_strings), "partition_id") # Use mapInArrow for zero-copy vectorized conversion. The output schema @@ -286,7 +295,11 @@ def _run_spark_conversion(self, partition_specs: List[dict], mode: str): udf_func = _make_arrow_udf() td = partition_specs[0].get("time_dtype", "float64") if partition_specs else "float64" vd = partition_specs[0].get("value_dtype", "float64") if partition_specs else "float64" - rle = bool(partition_specs[0].get("run_length_encoding", False)) if partition_specs else False + rle = ( + bool(partition_specs[0].get("run_length_encoding", False)) + if partition_specs + else False + ) result_df = seed_df.mapInArrow(udf_func, schema=_signals_spark_schema(td, vd, rle)) # Write to Delta (plain write; see _write_signals_df for storage findings) @@ -294,9 +307,9 @@ def _run_spark_conversion(self, partition_specs: List[dict], mode: str): def convert_batch( self, - file_paths: List[str], + file_paths: list[str], mode: str = "append", - ) -> List[ConversionResult]: + ) -> list[ConversionResult]: """ Convert multiple MDF4 files in sequence; each row is tagged with its source file path (file_uri). @@ -318,7 +331,7 @@ def convert_batch( def convert_batch_parallel( self, - file_paths: List[str], + file_paths: list[str], mode: str = "overwrite", ) -> ConversionResult: """ @@ -352,7 +365,10 @@ def _scan(idx_path): reader = MDF4Reader(fp) channels = reader.scan_metadata() return ( - idx, fp, channels, reader.read_header_datetime(), + idx, + fp, + channels, + reader.read_header_datetime(), reader._unsorted_dg_ctx, ) @@ -363,7 +379,7 @@ def _scan(idx_path): key=lambda r: r[0], ) - for i, file_path, all_channels_in_file, header_datetime, unsorted_ctx in scanned: + for _i, file_path, all_channels_in_file, header_datetime, unsorted_ctx in scanned: if not all_channels_in_file: continue @@ -371,12 +387,18 @@ def _scan(idx_path): all_channels_in_file ) - all_metadata_rows.extend(self._metadata_rows( - signal_channels, channel_id_map, file_path, header_datetime)) - all_partition_specs.extend(self._plan( - file_path, master_channels, signal_channels, channel_id_map, - unsorted_dg_ctx=unsorted_ctx, - )) + all_metadata_rows.extend( + self._metadata_rows(signal_channels, channel_id_map, file_path, header_datetime) + ) + all_partition_specs.extend( + self._plan( + file_path, + master_channels, + signal_channels, + channel_id_map, + unsorted_dg_ctx=unsorted_ctx, + ) + ) total_channels += len(signal_channels) total_samples += sum(ch.sample_count for ch in signal_channels) @@ -433,8 +455,7 @@ def _ensure_clustered_table(spark, table: str, schema, cluster_cols: str): """ ddl = _schema_to_ddl(schema) spark.sql( - f"CREATE TABLE IF NOT EXISTS {table} ({ddl}) " - f"USING DELTA CLUSTER BY ({cluster_cols})" + f"CREATE TABLE IF NOT EXISTS {table} ({ddl}) " f"USING DELTA CLUSTER BY ({cluster_cols})" ) try: spark.sql(f"ALTER TABLE {table} CLUSTER BY ({cluster_cols})") @@ -482,47 +503,54 @@ def _write_signals_df(df, table: str, mode: str): The clustered table is created from df.schema (not the fixed SIGNALS_SCHEMA) so a float32 time/value DataFrame produces a matching float table. """ - _ensure_clustered_table( - df.sparkSession, table, df.schema, "file_uri, channel_id" - ) + _ensure_clustered_table(df.sparkSession, table, df.schema, "file_uri, channel_id") df.write.format("delta").mode(mode).saveAsTable(table) try: df.sparkSession.sql( - f"ALTER TABLE {table} SET TBLPROPERTIES " - f"('delta.targetFileSize' = '128mb')" + f"ALTER TABLE {table} SET TBLPROPERTIES " f"('delta.targetFileSize' = '128mb')" ) except Exception: # Property hint is best-effort; never fail the conversion over it. pass -def _signals_spark_schema(time_dtype: str = "float64", value_dtype: str = "float64", - run_length_encoding: bool = False): +def _signals_spark_schema( + time_dtype: str = "float64", value_dtype: str = "float64", run_length_encoding: bool = False +): """Spark StructType for the signals output; time/value follow the configured dtype (float32 halves their on-disk bytes). With run_length_encoding the per-sample `time` column is replaced by the [`tstart`, `tend`] interval.""" from pyspark.sql.types import ( - StructType, StructField, StringType, IntegerType, DoubleType, FloatType, + StructType, + StructField, + StringType, + IntegerType, + DoubleType, + FloatType, ) def _ft(dt): return FloatType() if str(dt) == "float32" else DoubleType() if run_length_encoding: - return StructType([ + return StructType( + [ + StructField("file_uri", StringType(), False), + StructField("channel_id", IntegerType(), False), + StructField("tstart", _ft(time_dtype), False), + StructField("tend", _ft(time_dtype), False), + StructField("value", _ft(value_dtype), True), + ] + ) + + return StructType( + [ StructField("file_uri", StringType(), False), StructField("channel_id", IntegerType(), False), - StructField("tstart", _ft(time_dtype), False), - StructField("tend", _ft(time_dtype), False), + StructField("time", _ft(time_dtype), False), StructField("value", _ft(value_dtype), True), - ]) - - return StructType([ - StructField("file_uri", StringType(), False), - StructField("channel_id", IntegerType(), False), - StructField("time", _ft(time_dtype), False), - StructField("value", _ft(value_dtype), True), - ]) + ] + ) def _convert_partition_arrow(batch_iter): @@ -534,7 +562,8 @@ def _convert_partition_arrow(batch_iter): import logging import pyarrow as pa from .udf_helpers import ( - convert_spec_to_arrow_batches, convert_stripe_spec_to_arrow_batches, + convert_spec_to_arrow_batches, + convert_stripe_spec_to_arrow_batches, signals_arrow_schema, ) @@ -557,10 +586,14 @@ def _convert_partition_arrow(batch_iter): spec = json.loads(spec_json) # A stripe spec (Design B, byte-offset) carries "subblocks"; a group # spec (default) carries "channels". Dispatch to the matching decoder. - decode = (convert_stripe_spec_to_arrow_batches if "subblocks" in spec - else convert_spec_to_arrow_batches) + decode = ( + convert_stripe_spec_to_arrow_batches + if "subblocks" in spec + else convert_spec_to_arrow_batches + ) for rb in decode( - spec, prof=prof, + spec, + prof=prof, time_dtype=spec.get("time_dtype", "float64"), value_dtype=spec.get("value_dtype", "float64"), run_length_encoding=bool(spec.get("run_length_encoding", False)), @@ -570,8 +603,10 @@ def _convert_partition_arrow(batch_iter): if not yielded: yield pa.RecordBatch.from_arrays( - [pa.array([], type=output_schema.field(i).type) - for i in range(len(output_schema))], + [ + pa.array([], type=output_schema.field(i).type) + for i in range(len(output_schema)) + ], schema=output_schema, ) @@ -579,5 +614,8 @@ def _convert_partition_arrow(batch_iter): # without raising the default level; it is a measurement line, not an error. log.warning( "MDF_PROFILE rows=%d read_ms=%.0f decode_ms=%.0f arrow_ms=%.0f", - prof["rows"], prof["read"] / 1e6, prof["decode"] / 1e6, prof["arrow"] / 1e6, + prof["rows"], + prof["read"] / 1e6, + prof["decode"] / 1e6, + prof["arrow"] / 1e6, ) diff --git a/src/impulse_data_sources/mdf/datasources.py b/src/impulse_data_sources/mdf/datasources.py index a43d54ee..4f7b43f5 100644 --- a/src/impulse_data_sources/mdf/datasources.py +++ b/src/impulse_data_sources/mdf/datasources.py @@ -157,8 +157,14 @@ def schema(self): # module-global function there forces a module import that can fail in # that context. Inline imports of pyspark types are always safe. from pyspark.sql.types import ( - StructType, StructField, StringType, IntegerType, DoubleType, FloatType, + StructType, + StructField, + StringType, + IntegerType, + DoubleType, + FloatType, ) + absolute = self._absolute_time() def _ftype(opt): @@ -168,23 +174,29 @@ def _ftype(opt): # disagree on `value` and the writer fails (getDouble on a float vector). if absolute and opt == "time_dtype": return DoubleType() - return FloatType() if str(self.options.get(opt, "float64")) == "float32" else DoubleType() + return ( + FloatType() if str(self.options.get(opt, "float64")) == "float32" else DoubleType() + ) if str(self.options.get("run_length_encoding", "false")).lower() == "true": - return StructType([ + return StructType( + [ + StructField("file_uri", StringType(), False), + StructField("channel_id", IntegerType(), False), + StructField("tstart", _ftype("time_dtype"), False), + StructField("tend", _ftype("time_dtype"), False), + StructField("value", _ftype("value_dtype"), True), + ] + ) + + return StructType( + [ StructField("file_uri", StringType(), False), StructField("channel_id", IntegerType(), False), - StructField("tstart", _ftype("time_dtype"), False), - StructField("tend", _ftype("time_dtype"), False), + StructField("time", _ftype("time_dtype"), False), StructField("value", _ftype("value_dtype"), True), - ]) - - return StructType([ - StructField("file_uri", StringType(), False), - StructField("channel_id", IntegerType(), False), - StructField("time", _ftype("time_dtype"), False), - StructField("value", _ftype("value_dtype"), True), - ]) + ] + ) def reader(self, schema): return MdfSignalsReader(self.options) @@ -210,7 +222,9 @@ def partitions(self): file_paths = _resolve_file_list(self.options) target_partition_mb = float(self.options.get("target_partition_mb", "64")) - run_length_encoding = str(self.options.get("run_length_encoding", "false")).lower() == "true" + run_length_encoding = ( + str(self.options.get("run_length_encoding", "false")).lower() == "true" + ) max_groups_per_partition = int(self.options.get("max_groups_per_partition", "64")) absolute_time = str(self.options.get("absolute_time", "false")).lower() == "true" # partitioning: "group" (default, per-group/record-range) or "stripe" @@ -229,16 +243,19 @@ def partitions(self): if start is None: raise ValueError( f"absolute_time=true but {file_path} has no measurement " - f"start time in its HD block") + f"start time in its HD block" + ) time_offset = start if partitioning == "stripe": specs = plan_stripes_for_file( file_path, target_partition_mb=target_partition_mb, - time_dtype=time_dtype, value_dtype=value_dtype, + time_dtype=time_dtype, + value_dtype=value_dtype, run_length_encoding=run_length_encoding, - time_offset=time_offset, stripe_target_mb=stripe_target_mb, + time_offset=time_offset, + stripe_target_mb=stripe_target_mb, ) all_partition_specs.extend(json.dumps(s) for s in specs) continue @@ -253,7 +270,8 @@ def partitions(self): organized["signal_channels"], organized["channel_id_map"], target_partition_mb=target_partition_mb, - time_dtype=time_dtype, value_dtype=value_dtype, + time_dtype=time_dtype, + value_dtype=value_dtype, run_length_encoding=run_length_encoding, max_groups_per_partition=max_groups_per_partition, time_offset=time_offset, @@ -280,7 +298,9 @@ def read(self, partition): import json import logging from .udf_helpers import ( - convert_spec_to_arrow_batches, convert_stripe_spec_to_arrow_batches) + convert_spec_to_arrow_batches, + convert_stripe_spec_to_arrow_batches, + ) spec_json = partition.value if spec_json == "[]": @@ -292,19 +312,32 @@ def read(self, partition): # options for older specs. time_dtype = str(spec.get("time_dtype", self.options.get("time_dtype", "float64"))) value_dtype = str(spec.get("value_dtype", self.options.get("value_dtype", "float64"))) - run_length_encoding = bool(spec.get( - "run_length_encoding", - str(self.options.get("run_length_encoding", "false")).lower() == "true")) + run_length_encoding = bool( + spec.get( + "run_length_encoding", + str(self.options.get("run_length_encoding", "false")).lower() == "true", + ) + ) prof = {"read": 0, "decode": 0, "arrow": 0, "rows": 0} # Stripe spec (Design B) carries "subblocks"; group spec carries "channels". - decode = (convert_stripe_spec_to_arrow_batches if "subblocks" in spec - else convert_spec_to_arrow_batches) + decode = ( + convert_stripe_spec_to_arrow_batches + if "subblocks" in spec + else convert_spec_to_arrow_batches + ) yield from decode( - spec, prof=prof, time_dtype=time_dtype, value_dtype=value_dtype, - run_length_encoding=run_length_encoding) + spec, + prof=prof, + time_dtype=time_dtype, + value_dtype=value_dtype, + run_length_encoding=run_length_encoding, + ) logging.getLogger("impulse_ds.mdf.convert").warning( "MDF_PROFILE rows=%d read_ms=%.0f decode_ms=%.0f arrow_ms=%.0f", - prof["rows"], prof["read"] / 1e6, prof["decode"] / 1e6, prof["arrow"] / 1e6, + prof["rows"], + prof["read"] / 1e6, + prof["decode"] / 1e6, + prof["arrow"] / 1e6, ) @@ -359,16 +392,18 @@ def read(self, partition): rows = [] for ch_id, ch in enumerate(organized["signal_channels"]): - rows.append(( - file_path, - ch_id, - ch.group_idx, - ch.channel_idx, - ch.channel_name, - ch.unit or "", - header_datetime, - ch.md_comment or None, - )) + rows.append( + ( + file_path, + ch_id, + ch.group_idx, + ch.channel_idx, + ch.channel_name, + ch.unit or "", + header_datetime, + ch.md_comment or None, + ) + ) return iter(rows) @@ -405,15 +440,27 @@ def schema(self): master sample. timestamp is float (double unless time_dtype=float32, or absolute_time which forces double).""" from pyspark.sql.types import ( - StructType, StructField, StringType, IntegerType, DoubleType, FloatType, + StructType, + StructField, + StringType, + IntegerType, + DoubleType, + FloatType, ) + absolute = str(self.options.get("absolute_time", "false")).lower() == "true" - ts_type = DoubleType() if absolute or str(self.options.get("time_dtype", "float64")) != "float32" else FloatType() - return StructType([ - StructField("file_uri", StringType(), False), - StructField("group_idx", IntegerType(), False), - StructField("timestamp", ts_type, False), - ]) + ts_type = ( + DoubleType() + if absolute or str(self.options.get("time_dtype", "float64")) != "float32" + else FloatType() + ) + return StructType( + [ + StructField("file_uri", StringType(), False), + StructField("group_idx", IntegerType(), False), + StructField("timestamp", ts_type, False), + ] + ) def reader(self, schema): return MdfMastersReader(self.options) @@ -451,10 +498,12 @@ def partitions(self): if start is None: raise ValueError( f"absolute_time=true but {file_path} has no measurement " - f"start time in its HD block") + f"start time in its HD block" + ) time_offset = start specs = plan_master_partitions( - file_path, organized["master_channels"], + file_path, + organized["master_channels"], target_partition_mb=target_partition_mb, time_dtype=time_dtype, max_groups_per_partition=max_groups_per_partition, @@ -482,9 +531,11 @@ def read(self, partition): # Use the dtype baked into the spec (reflects the absolute_time override). time_dtype = str(spec.get("time_dtype", self.options.get("time_dtype", "float64"))) prof = {"read": 0, "decode": 0, "arrow": 0, "rows": 0} - yield from convert_master_spec_to_arrow_batches( - spec, prof=prof, time_dtype=time_dtype) + yield from convert_master_spec_to_arrow_batches(spec, prof=prof, time_dtype=time_dtype) logging.getLogger("impulse_ds.mdf.convert").warning( "MDF_PROFILE(masters) rows=%d read_ms=%.0f decode_ms=%.0f arrow_ms=%.0f", - prof["rows"], prof["read"] / 1e6, prof["decode"] / 1e6, prof["arrow"] / 1e6, + prof["rows"], + prof["read"] / 1e6, + prof["decode"] / 1e6, + prof["arrow"] / 1e6, ) diff --git a/src/impulse_data_sources/mdf/mdf4_reader.py b/src/impulse_data_sources/mdf/mdf4_reader.py index 9f600407..092f1b7a 100644 --- a/src/impulse_data_sources/mdf/mdf4_reader.py +++ b/src/impulse_data_sources/mdf/mdf4_reader.py @@ -11,10 +11,9 @@ import struct from datetime import datetime, timezone import numpy as np -from typing import BinaryIO, List, Tuple, Dict, Optional +from typing import BinaryIO from dataclasses import dataclass - # MDF4 block IDs BLOCK_ID_HD = b"##HD" BLOCK_ID_DG = b"##DG" @@ -64,6 +63,7 @@ @dataclass class ChannelInfo: """Metadata for a single channel within an MDF4 file.""" + group_idx: int channel_idx: int channel_name: str @@ -98,20 +98,22 @@ class ChannelInfo: @dataclass class DataGroupInfo: """Metadata for a data group.""" + address: int data_block_addr: int - channel_groups: List["ChannelGroupInfo"] + channel_groups: list["ChannelGroupInfo"] @dataclass class ChannelGroupInfo: """Metadata for a channel group.""" + address: int record_id: int cycle_count: int data_bytes: int invalidation_bytes: int - channels: List[ChannelInfo] + channels: list[ChannelInfo] class MDF4Reader: @@ -126,23 +128,26 @@ def __init__(self, file_path: str = None, file_bytes: "bytes" = None): build the block map from RAM without re-reading the volume.""" self.file_path = file_path self._file_bytes = file_bytes - self._data_groups: Optional[List[DataGroupInfo]] = None - self._unsorted_dg_ctx: Dict[int, dict] = {} - self._text_cache: Dict[int, str] = {} # address -> TX/MD text (immutable per file) + self._data_groups: list[DataGroupInfo] | None = None + self._unsorted_dg_ctx: dict[int, dict] = {} + self._text_cache: dict[int, str] = {} # address -> TX/MD text (immutable per file) def _open(self): """Context manager yielding a seekable binary source (in-RAM buffer if file_bytes was provided, else the file on disk).""" import contextlib import io + if self._file_bytes is not None: + @contextlib.contextmanager def _buf(): yield io.BytesIO(self._file_bytes) + return _buf() return open(self.file_path, "rb") - def _read_hd_start_utc_ns(self) -> Optional[int]: + def _read_hd_start_utc_ns(self) -> int | None: """Read the measurement start time from the HD block as UTC nanoseconds since the Unix epoch (full precision), or None if not set. @@ -182,7 +187,7 @@ def _read_hd_start_utc_ns(self) -> Optional[int]: utc_ns -= total_offset_min * 60 * 1_000_000_000 return utc_ns - def read_header_datetime(self) -> Optional[datetime]: + def read_header_datetime(self) -> datetime | None: """ Read measurement start datetime from the MDF4 HD block. @@ -198,7 +203,7 @@ def read_header_datetime(self) -> Optional[datetime]: ) return dt.replace(tzinfo=None) - def read_header_start_epoch_seconds(self) -> Optional[float]: + def read_header_start_epoch_seconds(self) -> float | None: """Measurement start time as Unix epoch seconds (UTC), as a float with the HD block's sub-second precision (not rounded to whole seconds), or None if not set. Used to make signal timestamps absolute. @@ -245,7 +250,7 @@ def _read_text_block(self, f: BinaryIO, address: int) -> str: return text @staticmethod - def _parse_cc_block(f: BinaryIO, cc_addr: int) -> Tuple[int, tuple]: + def _parse_cc_block(f: BinaryIO, cc_addr: int) -> tuple[int, tuple]: """ Parse a CC (Channel Conversion) block and return (cc_type, cc_params). @@ -269,9 +274,9 @@ def _parse_cc_block(f: BinaryIO, cc_addr: int) -> Tuple[int, tuple]: # (precision, flags, ref_count, phy_range_*) are kept as named reads to # document the block layout and keep the offsets self-evident. cc_type = struct.unpack(" Tuple[int, tuple]: return cc_type, cc_params - def scan_metadata(self) -> List[ChannelInfo]: + def scan_metadata(self) -> list[ChannelInfo]: """ Scan the MDF4 file to extract all channel metadata without reading actual signal data. Returns list of ChannelInfo objects. @@ -341,7 +346,7 @@ def scan_metadata(self) -> List[ChannelInfo]: dg_rec_id_size = struct.unpack(" List[ChannelInfo]: record_size = dg_rec_id_size + cg_data_bytes + cg_invalidation_bytes if dg_rec_id_size > 0: from .mdf_decode import storage_record_id + dg_cg_sizes[storage_record_id(cg_record_id, dg_rec_id_size)] = record_size # Traverse CN linked list @@ -412,20 +418,22 @@ def scan_metadata(self) -> List[ChannelInfo]: # limit ranges) are read in spec order purely to advance the # file position; they are named to document the block layout. cn_type = struct.unpack(" List[ChannelInfo]: # Parse CC conversion block cc_type, cc_params = self._parse_cc_block(f, cc_addr) - channels.append(ChannelInfo( - group_idx=group_idx, - channel_idx=channel_idx, - channel_name=channel_name, - unit=unit, - sample_count=cg_cycle_count, - data_type=cn_data_type, - bit_offset=cn_bit_offset, - byte_offset=dg_rec_id_size + cn_byte_offset, - bit_count=cn_bit_count, - channel_type=cn_type, - cn_block_addr=cn_addr, - cg_block_addr=cg_addr, - dg_block_addr=dg_addr, - data_block_addr=data_block_addr, - record_size=record_size, - cn_flags=cn_flags, - invalidation_bit_pos=cn_invalid_bit_pos, - invalidation_bytes=cg_invalidation_bytes, - data_bytes=dg_rec_id_size + cg_data_bytes, - cc_type=cc_type, - cc_params=cc_params, - rec_id_size=dg_rec_id_size, - record_id=cg_record_id, - md_comment=md_comment, - )) + channels.append( + ChannelInfo( + group_idx=group_idx, + channel_idx=channel_idx, + channel_name=channel_name, + unit=unit, + sample_count=cg_cycle_count, + data_type=cn_data_type, + bit_offset=cn_bit_offset, + byte_offset=dg_rec_id_size + cn_byte_offset, + bit_count=cn_bit_count, + channel_type=cn_type, + cn_block_addr=cn_addr, + cg_block_addr=cg_addr, + dg_block_addr=dg_addr, + data_block_addr=data_block_addr, + record_size=record_size, + cn_flags=cn_flags, + invalidation_bit_pos=cn_invalid_bit_pos, + invalidation_bytes=cg_invalidation_bytes, + data_bytes=dg_rec_id_size + cg_data_bytes, + cc_type=cc_type, + cc_params=cc_params, + rec_id_size=dg_rec_id_size, + record_id=cg_record_id, + md_comment=md_comment, + ) + ) channel_idx += 1 cn_addr = next_cn_addr @@ -500,8 +510,8 @@ def read_channel_data( cc_params: tuple = (), rec_id_size: int = 0, record_id: int = 0, - cg_record_sizes: Optional[dict] = None, - f: Optional[BinaryIO] = None, + cg_record_sizes: dict | None = None, + f: BinaryIO | None = None, ) -> np.ndarray: """ Read raw signal data for a single channel directly from the binary file. @@ -561,8 +571,8 @@ def read_channel_pair( master_info: dict, signal_info: dict, sample_count: int, - f: Optional[BinaryIO] = None, - ) -> Tuple[np.ndarray, np.ndarray]: + f: BinaryIO | None = None, + ) -> tuple[np.ndarray, np.ndarray]: """ Read both master (time) and signal channel data for a channel group. Returns (timestamps, values) both as float64 arrays. @@ -572,10 +582,13 @@ def read_channel_pair( opening the file again. """ from .udf_helpers import ( - read_raw_data, extract_signal, extract_timestamps, prepare_cg_records, + read_raw_data, + extract_signal, + extract_timestamps, + prepare_cg_records, ) - def _do_read(fh: BinaryIO) -> Tuple[np.ndarray, np.ndarray]: + def _do_read(fh: BinaryIO) -> tuple[np.ndarray, np.ndarray]: data_block_addr = signal_info["data_block_addr"] record_size = signal_info["record_size"] rec_id_size = signal_info.get("rec_id_size", 0) @@ -595,11 +608,16 @@ def _do_read(fh: BinaryIO) -> Tuple[np.ndarray, np.ndarray]: actual_samples = len(raw_data) // record_size if record_size else 0 if master_info: timestamps = extract_timestamps( - raw_data, record_size, master_info, index_offset=index_offset, + raw_data, + record_size, + master_info, + index_offset=index_offset, ) else: timestamps = np.arange( - index_offset, index_offset + actual_samples, dtype=np.float64, + index_offset, + index_offset + actual_samples, + dtype=np.float64, ) values = extract_signal(raw_data, record_size, signal_info) @@ -614,7 +632,6 @@ def _do_read(fh: BinaryIO) -> Tuple[np.ndarray, np.ndarray]: with open(file_path, "rb") as fh: return _do_read(fh) - def scan_channels_organized(self) -> dict: """ Scan metadata and return channels organized into masters and signals. @@ -646,7 +663,7 @@ def scan_channels_organized(self) -> dict: } @staticmethod - def channel_to_dict(ch: "ChannelInfo", unsorted_dg_ctx: Optional[dict] = None) -> dict: + def channel_to_dict(ch: "ChannelInfo", unsorted_dg_ctx: dict | None = None) -> dict: """Convert a ChannelInfo to a serializable dict suitable for bin packing.""" from .mdf_decode import unsorted_fields_from_ctx @@ -675,7 +692,7 @@ def channel_to_dict(ch: "ChannelInfo", unsorted_dg_ctx: Optional[dict] = None) - return d @staticmethod - def master_to_dict(ch: "ChannelInfo", unsorted_dg_ctx: Optional[dict] = None) -> dict: + def master_to_dict(ch: "ChannelInfo", unsorted_dg_ctx: dict | None = None) -> dict: """Convert a master ChannelInfo to a serializable dict for timestamp extraction.""" from .mdf_decode import unsorted_fields_from_ctx diff --git a/src/impulse_data_sources/mdf/mdf_blocks.py b/src/impulse_data_sources/mdf/mdf_blocks.py index 80caa169..9a731174 100644 --- a/src/impulse_data_sources/mdf/mdf_blocks.py +++ b/src/impulse_data_sources/mdf/mdf_blocks.py @@ -5,6 +5,7 @@ Arrow emitters; they operate on an open binary file object (real file or an in-memory ``BytesIO``). """ + import struct import zlib import numpy as np @@ -44,7 +45,7 @@ def decompress_dz(f, dz_addr): pos = 0 for col in range(cols): col_size = rows + (1 if col < remainder else 0) - dest_idx[pos:pos + col_size] = np.arange(col_size) * cols + col + dest_idx[pos : pos + col_size] = np.arange(col_size) * cols + col pos += col_size out = np.empty(len(src), dtype=np.uint8) out[dest_idx] = src @@ -93,9 +94,9 @@ def resolve_dl_addr(f, data_block_addr): if bid == b"##DL": return data_block_addr if bid == b"##HL": - f.read(4) # reserved - f.read(8) # length - f.read(8) # link_count + f.read(4) # reserved + f.read(8) # length + f.read(8) # link_count hl_dl_first = struct.unpack(" un-transpose cols = zip_param rows = len(dec) // cols @@ -154,14 +155,14 @@ def _decompress_subblock_blob(blob, off): pos = 0 for col in range(cols): cs = rows + (1 if col < remainder else 0) - dest_idx[pos:pos + cs] = np.arange(cs) * cols + col + dest_idx[pos : pos + cs] = np.arange(cs) * cols + col pos += cs out = np.empty(len(src), dtype=np.uint8) out[dest_idx] = src dec = out.tobytes() return dec length = struct.unpack_from("> bit_offset vals = vals & ((1 << bit_count) - 1) sign_bit = np.uint64(1 << (bit_count - 1)) - vals = np.where(vals & sign_bit, vals.astype(np.int64) - (1 << bit_count), vals.astype(np.int64)) + vals = np.where( + vals & sign_bit, vals.astype(np.int64) - (1 << bit_count), vals.astype(np.int64) + ) return vals.astype(np.float64) else: return np.zeros(sample_count, dtype=np.float64) @@ -209,7 +212,7 @@ def apply_cc_conversion(values, cc_type, cc_params): uppers = np.array([cc_params[i * 3 + 1] for i in range(n)]) phys_vals = np.array([cc_params[i * 3 + 2] for i in range(n)]) # Find which range each value falls into - indices = np.searchsorted(lowers, values, side='right') - 1 + indices = np.searchsorted(lowers, values, side="right") - 1 indices = np.clip(indices, 0, n - 1) result = np.where( (values >= lowers[indices]) & (values < uppers[indices]), @@ -233,7 +236,7 @@ def storage_record_id(record_id: int, rec_id_size: int) -> int: return record_id & mask -def read_record_id(buf: Union[bytes, memoryview], offset: int, rec_id_size: int) -> int: +def read_record_id(buf: bytes | memoryview, offset: int, rec_id_size: int) -> int: """Read a little-endian unsigned record ID from ``buf`` at ``offset``.""" if rec_id_size <= 0: return 0 @@ -247,7 +250,7 @@ def filter_unsorted_records( raw_data: bytes, rec_id_size: int, target_record_id: int, - cg_record_sizes: Dict[int, int], + cg_record_sizes: dict[int, int], ) -> bytes: """Extract records belonging to ``target_record_id`` from an interleaved block.""" if rec_id_size <= 0: @@ -266,7 +269,7 @@ def filter_unsorted_records( if pos + rec_size > n: break if rid == target_record_id: - out.extend(raw_data[pos:pos + rec_size]) + out.extend(raw_data[pos : pos + rec_size]) pos += rec_size return bytes(out) @@ -277,10 +280,10 @@ def prepare_cg_records( record_size: int, rec_id_size: int = 0, record_id: int = 0, - cg_record_sizes: Optional[Dict[int, int]] = None, - row_start: Optional[int] = None, - row_end: Optional[int] = None, -) -> Tuple[bytes, int]: + cg_record_sizes: dict[int, int] | None = None, + row_start: int | None = None, + row_end: int | None = None, +) -> tuple[bytes, int]: """Filter unsorted interleaved records and optionally slice by logical row range. Returns ``(prepared_bytes, index_offset)`` where ``index_offset`` is the @@ -292,7 +295,10 @@ def prepare_cg_records( # JSON partition specs stringify dict keys; normalize back to int. cg_sizes = {int(k): v for k, v in cg_record_sizes.items()} raw_data = filter_unsorted_records( - raw_data, rec_id_size, record_id, cg_sizes, + raw_data, + rec_id_size, + record_id, + cg_sizes, ) if record_size <= 0: @@ -333,7 +339,7 @@ def extract_signal(raw_data, record_size, ch_spec): if ch_spec.get("channel_type") == 1: # VLSD return np.full(actual, np.nan, dtype=np.float64) - usable = raw_data[:actual * record_size] + usable = raw_data[: actual * record_size] s_data_type = ch_spec["data_type"] s_bit_count = ch_spec["bit_count"] s_byte_offset = ch_spec["byte_offset"] @@ -346,53 +352,83 @@ def extract_signal(raw_data, record_size, ch_spec): if s_bit_offset == 0: if s_data_type == FLOAT_LE and s_bit_count == 64 and s_byte_offset % 8 == 0: values = np.ndarray( - shape=(actual,), dtype=np.float64, buffer=buf, - offset=s_byte_offset, strides=(record_size,), + shape=(actual,), + dtype=np.float64, + buffer=buf, + offset=s_byte_offset, + strides=(record_size,), ).copy() elif s_data_type == FLOAT_LE and s_bit_count == 32 and s_byte_offset % 4 == 0: values = np.ndarray( - shape=(actual,), dtype=np.float32, buffer=buf, - offset=s_byte_offset, strides=(record_size,), + shape=(actual,), + dtype=np.float32, + buffer=buf, + offset=s_byte_offset, + strides=(record_size,), ).astype(np.float64) elif s_data_type == UINT_LE and s_bit_count == 16 and s_byte_offset % 2 == 0: values = np.ndarray( - shape=(actual,), dtype=np.uint16, buffer=buf, - offset=s_byte_offset, strides=(record_size,), + shape=(actual,), + dtype=np.uint16, + buffer=buf, + offset=s_byte_offset, + strides=(record_size,), ).astype(np.float64) elif s_data_type == UINT_LE and s_bit_count == 32 and s_byte_offset % 4 == 0: values = np.ndarray( - shape=(actual,), dtype=np.uint32, buffer=buf, - offset=s_byte_offset, strides=(record_size,), + shape=(actual,), + dtype=np.uint32, + buffer=buf, + offset=s_byte_offset, + strides=(record_size,), ).astype(np.float64) elif s_data_type == UINT_LE and s_bit_count == 8: values = np.ndarray( - shape=(actual,), dtype=np.uint8, buffer=buf, - offset=s_byte_offset, strides=(record_size,), + shape=(actual,), + dtype=np.uint8, + buffer=buf, + offset=s_byte_offset, + strides=(record_size,), ).astype(np.float64) elif s_data_type == SINT_LE and s_bit_count == 16 and s_byte_offset % 2 == 0: values = np.ndarray( - shape=(actual,), dtype=np.int16, buffer=buf, - offset=s_byte_offset, strides=(record_size,), + shape=(actual,), + dtype=np.int16, + buffer=buf, + offset=s_byte_offset, + strides=(record_size,), ).astype(np.float64) elif s_data_type == SINT_LE and s_bit_count == 32 and s_byte_offset % 4 == 0: values = np.ndarray( - shape=(actual,), dtype=np.int32, buffer=buf, - offset=s_byte_offset, strides=(record_size,), + shape=(actual,), + dtype=np.int32, + buffer=buf, + offset=s_byte_offset, + strides=(record_size,), ).astype(np.float64) elif s_data_type == SINT_LE and s_bit_count == 8: values = np.ndarray( - shape=(actual,), dtype=np.int8, buffer=buf, - offset=s_byte_offset, strides=(record_size,), + shape=(actual,), + dtype=np.int8, + buffer=buf, + offset=s_byte_offset, + strides=(record_size,), ).astype(np.float64) elif s_data_type == UINT_LE and s_bit_count == 64 and s_byte_offset % 8 == 0: values = np.ndarray( - shape=(actual,), dtype=np.uint64, buffer=buf, - offset=s_byte_offset, strides=(record_size,), + shape=(actual,), + dtype=np.uint64, + buffer=buf, + offset=s_byte_offset, + strides=(record_size,), ).astype(np.float64) elif s_data_type == SINT_LE and s_bit_count == 64 and s_byte_offset % 8 == 0: values = np.ndarray( - shape=(actual,), dtype=np.int64, buffer=buf, - offset=s_byte_offset, strides=(record_size,), + shape=(actual,), + dtype=np.int64, + buffer=buf, + offset=s_byte_offset, + strides=(record_size,), ).astype(np.float64) else: sig_raw = extract_column_strided(usable, record_size, s_byte_offset, s_bytes, actual) @@ -404,7 +440,9 @@ def extract_signal(raw_data, record_size, ch_spec): # Apply invalidation — pass buf to avoid redundant np.frombuffer cn_flags = ch_spec.get("cn_flags", 0) invalidation_bytes_nr = ch_spec.get("invalidation_bytes", 0) - if invalidation_bytes_nr > 0 and (cn_flags & (CN_FLAG_ALL_INVALID | CN_FLAG_INVALIDATION_PRESENT)): + if invalidation_bytes_nr > 0 and ( + cn_flags & (CN_FLAG_ALL_INVALID | CN_FLAG_INVALIDATION_PRESENT) + ): signal_info = { "cn_flags": cn_flags, "invalidation_bit_pos": ch_spec.get("invalidation_bit_pos", 0), @@ -435,7 +473,7 @@ def extract_timestamps(raw_data, record_size, master_info, index_offset=0): if master_info["channel_type"] == 3: # virtual master timestamps = np.arange(index_offset, index_offset + actual, dtype=np.float64) else: - usable = raw_data[:actual * record_size] + usable = raw_data[: actual * record_size] m_bit_count = master_info["bit_count"] m_byte_offset = master_info["byte_offset"] m_bit_offset = master_info["bit_offset"] @@ -444,23 +482,49 @@ def extract_timestamps(raw_data, record_size, master_info, index_offset=0): buf = np.frombuffer(usable, dtype=np.uint8) - if m_bit_offset == 0 and m_data_type == FLOAT_LE and m_bit_count == 64 and m_byte_offset % 8 == 0: + if ( + m_bit_offset == 0 + and m_data_type == FLOAT_LE + and m_bit_count == 64 + and m_byte_offset % 8 == 0 + ): timestamps = np.ndarray( - shape=(actual,), dtype=np.float64, buffer=buf, - offset=m_byte_offset, strides=(record_size,), + shape=(actual,), + dtype=np.float64, + buffer=buf, + offset=m_byte_offset, + strides=(record_size,), ).copy() - elif m_bit_offset == 0 and m_data_type == FLOAT_LE and m_bit_count == 32 and m_byte_offset % 4 == 0: + elif ( + m_bit_offset == 0 + and m_data_type == FLOAT_LE + and m_bit_count == 32 + and m_byte_offset % 4 == 0 + ): timestamps = np.ndarray( - shape=(actual,), dtype=np.float32, buffer=buf, - offset=m_byte_offset, strides=(record_size,), + shape=(actual,), + dtype=np.float32, + buffer=buf, + offset=m_byte_offset, + strides=(record_size,), ).astype(np.float64) - elif m_bit_offset == 0 and m_data_type == UINT_LE and m_bit_count == 64 and m_byte_offset % 8 == 0: + elif ( + m_bit_offset == 0 + and m_data_type == UINT_LE + and m_bit_count == 64 + and m_byte_offset % 8 == 0 + ): timestamps = np.ndarray( - shape=(actual,), dtype=np.uint64, buffer=buf, - offset=m_byte_offset, strides=(record_size,), + shape=(actual,), + dtype=np.uint64, + buffer=buf, + offset=m_byte_offset, + strides=(record_size,), ).astype(np.float64) else: - master_raw = extract_column_strided(usable, record_size, m_byte_offset, m_bytes, actual) + master_raw = extract_column_strided( + usable, record_size, m_byte_offset, m_bytes, actual + ) timestamps = convert_values(master_raw, m_data_type, m_bit_count, m_bit_offset, actual) # Apply CC conversion to master channel if present diff --git a/src/impulse_data_sources/mdf/schemas.py b/src/impulse_data_sources/mdf/schemas.py index dfa45ea4..3e7d04ea 100644 --- a/src/impulse_data_sources/mdf/schemas.py +++ b/src/impulse_data_sources/mdf/schemas.py @@ -9,21 +9,24 @@ TimestampType, ) +SIGNALS_SCHEMA = StructType( + [ + StructField("file_uri", StringType(), False), + StructField("channel_id", IntegerType(), False), + StructField("time", DoubleType(), False), + StructField("value", DoubleType(), True), + ] +) -SIGNALS_SCHEMA = StructType([ - StructField("file_uri", StringType(), False), - StructField("channel_id", IntegerType(), False), - StructField("time", DoubleType(), False), - StructField("value", DoubleType(), True), -]) - -METADATA_SCHEMA = StructType([ - StructField("file_uri", StringType(), False), - StructField("channel_id", IntegerType(), False), - StructField("group_idx", IntegerType(), False), - StructField("channel_idx", IntegerType(), False), - StructField("channel_name", StringType(), False), - StructField("unit", StringType(), True), - StructField("header_datetime", TimestampType(), True), - StructField("md_comment", StringType(), True), -]) +METADATA_SCHEMA = StructType( + [ + StructField("file_uri", StringType(), False), + StructField("channel_id", IntegerType(), False), + StructField("group_idx", IntegerType(), False), + StructField("channel_idx", IntegerType(), False), + StructField("channel_name", StringType(), False), + StructField("unit", StringType(), True), + StructField("header_datetime", TimestampType(), True), + StructField("md_comment", StringType(), True), + ] +) diff --git a/src/impulse_data_sources/mdf/udf_helpers.py b/src/impulse_data_sources/mdf/udf_helpers.py index d9243839..a6d805d5 100644 --- a/src/impulse_data_sources/mdf/udf_helpers.py +++ b/src/impulse_data_sources/mdf/udf_helpers.py @@ -35,10 +35,21 @@ filter_unsorted_records, prepare_cg_records, unsorted_fields_from_ctx, - FLOAT_LE, FLOAT_BE, UINT_LE, UINT_BE, SINT_LE, SINT_BE, - CC_IDENTITY, CC_LINEAR, CC_RATIONAL, CC_ALGEBRAIC, - CC_TAB_INTERP, CC_TAB_NOINTERP, CC_RANGE_TO_VALUE, - CN_FLAG_ALL_INVALID, CN_FLAG_INVALIDATION_PRESENT, + FLOAT_LE, + FLOAT_BE, + UINT_LE, + UINT_BE, + SINT_LE, + SINT_BE, + CC_IDENTITY, + CC_LINEAR, + CC_RATIONAL, + CC_ALGEBRAIC, + CC_TAB_INTERP, + CC_TAB_NOINTERP, + CC_RANGE_TO_VALUE, + CN_FLAG_ALL_INVALID, + CN_FLAG_INVALIDATION_PRESENT, ) from .arrow_emit import ( # noqa: F401 signals_arrow_schema, diff --git a/tests/impulse_ds/mdf/_block_fixtures.py b/tests/impulse_ds/mdf/_block_fixtures.py index 43e37af1..b09c1940 100644 --- a/tests/impulse_ds/mdf/_block_fixtures.py +++ b/tests/impulse_ds/mdf/_block_fixtures.py @@ -5,7 +5,6 @@ import io import struct import zlib -from typing import List, Tuple import numpy as np @@ -56,20 +55,14 @@ def make_dz_block( return header + compressed -def make_dl_block(next_dl: int, data_addrs: List[int]) -> bytes: +def make_dl_block(next_dl: int, data_addrs: list[int]) -> bytes: """Build a ##DL block pointing at ``data_addrs`` (link 0 = next_dl).""" dl_count = len(data_addrs) link_count = 1 + dl_count links = struct.pack(f"<{link_count}Q", next_dl, *data_addrs) body = links + b"\x00" + b"\x00" * 3 + struct.pack(" bytes: @@ -86,9 +79,9 @@ def make_hl_block(dl_addr: int) -> bytes: def build_dl_file( - dt_payloads: List[bytes], + dt_payloads: list[bytes], wrap_hl: bool = False, -) -> Tuple[bytes, int]: +) -> tuple[bytes, int]: """Lay out DT sub-blocks + DL (optionally HL) in one buffer. Returns ``(file_bytes, data_block_addr)`` where ``data_block_addr`` is the @@ -96,7 +89,7 @@ def build_dl_file( """ # Avoid placing DT blocks at file offset 0 — the DL reader treats link 0 as null. blob = bytearray(b"\x00" * 8) - dt_addrs: List[int] = [] + dt_addrs: list[int] = [] for payload in dt_payloads: dt_addrs.append(len(blob)) if payload[:4] in (b"##DT", b"##DZ"): @@ -112,7 +105,7 @@ def build_dl_file( return bytes(blob), dl_addr -def cyclic_dl_file() -> Tuple[bytes, int]: +def cyclic_dl_file() -> tuple[bytes, int]: """DL whose next link points back to itself (cycle guard test).""" blob = bytearray(b"\x00" * 8) payload = make_dt_block(b"\x01\x02\x03\x04") @@ -134,13 +127,7 @@ def bytes_io_at(data: bytes, offset: int = 0) -> io.BytesIO: def make_unknown_block(payload: bytes = b"\x00") -> bytes: """Build a non-DT/DZ/DL block for parse_subblocks fallback tests.""" length = 24 + len(payload) - return ( - b"##XX" - + b"\x00" * 4 - + struct.pack(" None: # Group 0: 100 samples at 10 Hz. t0 = (np.arange(100) * 0.1).astype(np.float64) speed = Signal( - samples=(t0 * 2.0), timestamps=t0, name="Speed", unit="km/h", + samples=(t0 * 2.0), + timestamps=t0, + name="Speed", + unit="km/h", comment="vehicle speed", ) gear = np.zeros(100, dtype=np.int32) diff --git a/tests/impulse_ds/mdf/conftest.py b/tests/impulse_ds/mdf/conftest.py new file mode 100644 index 00000000..84d6c6b3 --- /dev/null +++ b/tests/impulse_ds/mdf/conftest.py @@ -0,0 +1,36 @@ +"""Register impulse_ds.mdf as an alias for impulse_data_sources.mdf (package rename).""" + +import importlib +import pkgutil +import sys +import types + + +def _set_parent_attr(full_name: str, mod: types.ModuleType) -> None: + """Attach *mod* on its parent so monkeypatch can resolve dotted paths.""" + parent_name, _, child_name = full_name.rpartition(".") + parent = sys.modules.get(parent_name) + if parent is not None: + setattr(parent, child_name, mod) + + +def _install_impulse_ds_shim() -> None: + if "impulse_ds.mdf" in sys.modules: + return + + impulse_ds = types.ModuleType("impulse_ds") + impulse_ds.__path__ = [] + sys.modules["impulse_ds"] = impulse_ds + + mdf = importlib.import_module("impulse_data_sources.mdf") + sys.modules["impulse_ds.mdf"] = mdf + impulse_ds.mdf = mdf + + for modinfo in pkgutil.walk_packages(mdf.__path__, prefix="impulse_data_sources.mdf."): + alias = modinfo.name.replace("impulse_data_sources", "impulse_ds", 1) + mod = importlib.import_module(modinfo.name) + sys.modules[alias] = mod + _set_parent_attr(alias, mod) + + +_install_impulse_ds_shim() diff --git a/tests/impulse_ds/mdf/test_arrow_emit.py b/tests/impulse_ds/mdf/test_arrow_emit.py index 9a5a6b99..d6557938 100644 --- a/tests/impulse_ds/mdf/test_arrow_emit.py +++ b/tests/impulse_ds/mdf/test_arrow_emit.py @@ -63,6 +63,7 @@ def test_convert_spec_honors_row_range_on_dl(self): records = [struct.pack(" 0 from impulse_ds.mdf.schemas import METADATA_SCHEMA + assert len(rows[0]) == len(METADATA_SCHEMA.fields) # md_comment included - (file_uri, channel_id, group_idx, channel_idx, channel_name, unit, - header_datetime, md_comment) = rows[0] + ( + file_uri, + channel_id, + group_idx, + channel_idx, + channel_name, + unit, + header_datetime, + md_comment, + ) = rows[0] assert isinstance(file_uri, str) and file_uri.endswith(".mf4") assert channel_id == 0 assert isinstance(channel_name, str) @@ -144,6 +153,7 @@ def test_read_produces_arrow_batches(self): if not EXAMPLE_FILES: pytest.skip("No example files") import pyarrow as pa + reader = MdfSignalsReader({"path": EXAMPLE_DIR, "files": EXAMPLE_FILES[0]}) partitions = reader.partitions() batches = [] @@ -173,6 +183,7 @@ def test_timestamps_nonnegative(self): class TestRunLengthEncoding: def _read(self, opts): from collections import defaultdict + reader = MdfSignalsReader(opts) cols = defaultdict(list) names = None @@ -187,10 +198,16 @@ def test_rle_schema(self): if not EXAMPLE_FILES: pytest.skip("No example files") from impulse_ds.mdf.datasources import MdfSignalsDataSource + opts = {"path": EXAMPLE_DIR, "files": EXAMPLE_FILES[0], "run_length_encoding": "true"} sch = MdfSignalsDataSource(dict(opts)).schema() assert [f.name for f in sch.fields] == [ - "file_uri", "channel_id", "tstart", "tend", "value"] + "file_uri", + "channel_id", + "tstart", + "tend", + "value", + ] names, _ = self._read(opts) assert names == ["file_uri", "channel_id", "tstart", "tend", "value"] @@ -200,6 +217,7 @@ def test_rle_final_sample_is_point(self): if not EXAMPLE_FILES: pytest.skip("No example files") from collections import defaultdict + base = {"path": EXAMPLE_DIR, "files": EXAMPLE_FILES[0], "target_partition_mb": "16"} _, plain = self._read(base) _, rle = self._read({**base, "run_length_encoding": "true"}) @@ -244,15 +262,21 @@ def per_channel(d, cols): rch = per_channel(rle, ["tstart", "tend", "value"]) def whole_rle(t, v): - o = np.argsort(t, kind="stable"); t, v = t[o], v[o] - s = _rle_run_starts(v); m = len(s) + o = np.argsort(t, kind="stable") + t, v = t[o], v[o] + s = _rle_run_starts(v) + m = len(s) return [(t[s[k]], t[s[k + 1]] if k < m - 1 else t[-1], v[s[k]]) for k in range(m)] def merge_adjacent(rows): - rows = sorted(rows, key=lambda r: r[0]); out = [] + rows = sorted(rows, key=lambda r: r[0]) + out = [] for t0, t1, val in rows: - same = out and out[-1][1] == t0 and ( - out[-1][2] == val or (out[-1][2] != out[-1][2] and val != val)) + same = ( + out + and out[-1][1] == t0 + and (out[-1][2] == val or (out[-1][2] != out[-1][2] and val != val)) + ) if same: out[-1] = (out[-1][0], t1, out[-1][2]) else: @@ -262,10 +286,13 @@ def merge_adjacent(rows): total_plain = total_runs = 0 for k, p in pch.items(): ref = whole_rle(p["time"], p["value"]) - got = merge_adjacent(list(zip(rch[k]["tstart"], rch[k]["tend"], rch[k]["value"]))) - total_plain += len(p["time"]); total_runs += len(got) + got = merge_adjacent( + list(zip(rch[k]["tstart"], rch[k]["tend"], rch[k]["value"], strict=False)) + ) + total_plain += len(p["time"]) + total_runs += len(got) assert len(ref) == len(got), f"channel {k}: {len(ref)} runs vs {len(got)}" - for (a0, a1, av), (b0, b1, bv) in zip(ref, got): + for (a0, a1, av), (b0, b1, bv) in zip(ref, got, strict=False): assert abs(a0 - b0) < 1e-6 and abs(a1 - b1) < 1e-6 assert av == bv or (av != av and bv != bv) # NaN == NaN # This example compresses substantially; guard against a no-op RLE. @@ -275,6 +302,7 @@ def merge_adjacent(rows): class TestMastersDataSource: def _read(self, reader, cols): from collections import defaultdict + out = defaultdict(lambda: defaultdict(list)) names = None for p in reader.partitions(): @@ -292,7 +320,10 @@ def test_masters_schema_and_grid(self): if not EXAMPLE_FILES: pytest.skip("No example files") from impulse_ds.mdf.datasources import ( - MdfMastersDataSource, MdfMastersReader, MdfSignalsReader) + MdfMastersDataSource, + MdfMastersReader, + MdfSignalsReader, + ) from impulse_ds.mdf.mdf4_reader import MDF4Reader opts = {"path": EXAMPLE_DIR, "files": EXAMPLE_FILES[0], "target_partition_mb": "16"} @@ -320,8 +351,10 @@ def test_reverse_rle_recovers_originals(self): opts = {"path": EXAMPLE_DIR, "files": EXAMPLE_FILES[0], "target_partition_mb": "16"} _, orig = self._read(MdfSignalsReader(opts), ["channel_id", "time", "value"]) - _, rle = self._read(MdfSignalsReader({**opts, "run_length_encoding": "true"}), - ["channel_id", "tstart", "tend", "value"]) + _, rle = self._read( + MdfSignalsReader({**opts, "run_length_encoding": "true"}), + ["channel_id", "tstart", "tend", "value"], + ) _, masters = self._read(MdfMastersReader(opts), ["group_idx", "timestamp"]) masters = {g: np.sort(d["timestamp"]) for g, d in masters.items()} org = MDF4Reader(os.path.join(EXAMPLE_DIR, EXAMPLE_FILES[0])).scan_channels_organized() @@ -344,6 +377,7 @@ class TestAbsoluteTime: def _read(self, opts, cols): from collections import defaultdict from impulse_ds.mdf.datasources import MdfSignalsReader + rd = MdfSignalsReader(opts) out = defaultdict(lambda: defaultdict(list)) for p in rd.partitions(): @@ -366,18 +400,21 @@ def test_absolute_time_adds_start_and_forces_float64(self): pytest.skip("file has no HD start time") # Schema forces float64 time even when float32 requested. - sch = MdfSignalsDataSource({"path": EXAMPLE_DIR, "files": f, - "absolute_time": "true", "time_dtype": "float32"}).schema() + sch = MdfSignalsDataSource( + {"path": EXAMPLE_DIR, "files": f, "absolute_time": "true", "time_dtype": "float32"} + ).schema() assert sch["time"].dataType.simpleString() == "double" base = {"path": EXAMPLE_DIR, "files": f, "target_partition_mb": "16"} rel = self._read(base, ["time", "value"]) ab = self._read({**base, "absolute_time": "true"}, ["time", "value"]) for ch in rel: - rt = np.sort(rel[ch]["time"]); at = np.sort(ab[ch]["time"]) - assert np.allclose(at, rt + start, atol=1e-3) # offset applied - assert np.array_equal(np.sort(rel[ch]["value"]), # values unchanged - np.sort(ab[ch]["value"])) + rt = np.sort(rel[ch]["time"]) + at = np.sort(ab[ch]["time"]) + assert np.allclose(at, rt + start, atol=1e-3) # offset applied + assert np.array_equal( + np.sort(rel[ch]["value"]), np.sort(ab[ch]["value"]) # values unchanged + ) def test_absolute_time_rle_and_masters_align(self): if not EXAMPLE_FILES: @@ -395,7 +432,8 @@ def masters(opts): out = defaultdict(list) for p in rd.partitions(): for b in rd.read(p): - g = b.column("group_idx").to_numpy(); ts = b.column("timestamp").to_numpy() + g = b.column("group_idx").to_numpy() + ts = b.column("timestamp").to_numpy() for k in np.unique(g): out[int(k)].append(ts[g == k]) return {k: np.sort(np.concatenate(v)) for k, v in out.items()} @@ -418,15 +456,35 @@ def test_all_option_combos_consistent(self): pytest.skip("No example files") from itertools import product from impulse_ds.mdf.datasources import MdfSignalsDataSource - spark2arrow = {"double": "double", "float": "float", - "bigint": "int64", "int": "int32", "string": "string"} - base = {"path": EXAMPLE_DIR, "files": EXAMPLE_FILES[0], - "target_partition_mb": "8", "stripe_target_mb": "2"} + + spark2arrow = { + "double": "double", + "float": "float", + "bigint": "int64", + "int": "int32", + "string": "string", + } + base = { + "path": EXAMPLE_DIR, + "files": EXAMPLE_FILES[0], + "target_partition_mb": "8", + "stripe_target_mb": "2", + } for abst, vdt, tdt, rle, part in product( - ["false", "true"], ["float64", "float32"], ["float64", "float32"], - ["false", "true"], ["group", "stripe"]): - opts = {**base, "absolute_time": abst, "value_dtype": vdt, - "time_dtype": tdt, "run_length_encoding": rle, "partitioning": part} + ["false", "true"], + ["float64", "float32"], + ["float64", "float32"], + ["false", "true"], + ["group", "stripe"], + ): + opts = { + **base, + "absolute_time": abst, + "value_dtype": vdt, + "time_dtype": tdt, + "run_length_encoding": rle, + "partitioning": part, + } sch = MdfSignalsDataSource(dict(opts)).schema() declared = {f.name: spark2arrow[f.dataType.simpleString()] for f in sch.fields} reader = MdfSignalsReader(opts) @@ -440,7 +498,8 @@ def test_all_option_combos_consistent(self): if emitted is not None: assert emitted == declared, ( f"schema/emit mismatch abs={abst} val={vdt} time={tdt} " - f"rle={rle} part={part}: {declared} vs {emitted}") + f"rle={rle} part={part}: {declared} vs {emitted}" + ) class TestDatasourcesEdgeCases: @@ -479,10 +538,11 @@ def test_absolute_time_raises_without_hd_start(self, tmp_path, monkeypatch): monkeypatch.setattr( "impulse_ds.mdf.mdf4_reader.MDF4Reader.read_header_start_epoch_seconds", - lambda self: None, + lambda _self: None, + ) + reader = MdfSignalsReader( + {"path": str(tmp_path), "files": "no_start.mf4", "absolute_time": "true"} ) - reader = MdfSignalsReader({"path": str(tmp_path), "files": "no_start.mf4", - "absolute_time": "true"}) with pytest.raises(ValueError, match="no measurement start time"): reader.partitions() @@ -500,11 +560,15 @@ def test_masters_absolute_time_raises_without_hd_start(self, tmp_path, monkeypat monkeypatch.setattr( "impulse_ds.mdf.mdf4_reader.MDF4Reader.read_header_start_epoch_seconds", - lambda self: None, + lambda _self: None, + ) + reader = MdfMastersReader( + { + "path": str(tmp_path), + "files": "no_start.mf4", + "absolute_time": "true", + } ) - reader = MdfMastersReader({ - "path": str(tmp_path), "files": "no_start.mf4", "absolute_time": "true", - }) with pytest.raises(ValueError, match="no measurement start time"): reader.partitions() @@ -512,12 +576,16 @@ def test_signals_empty_partitions_when_no_signals(self, monkeypatch): from impulse_ds.mdf.datasources import MdfSignalsReader def _empty_scan(self): - return {"master_channels": {}, "signal_channels": [], "channel_id_map": {}, - "unsorted_dg_ctx": {}} + return { + "master_channels": {}, + "signal_channels": [], + "channel_id_map": {}, + "unsorted_dg_ctx": {}, + } monkeypatch.setattr( "impulse_ds.mdf.datasources._resolve_file_list", - lambda opts: ["/fake/a.mf4"], + lambda _opts: ["/fake/a.mf4"], ) monkeypatch.setattr( "impulse_ds.mdf.mdf4_reader.MDF4Reader.scan_channels_organized", @@ -533,12 +601,16 @@ def test_masters_empty_when_no_masters(self, monkeypatch): from impulse_ds.mdf.datasources import MdfMastersReader def _no_masters(self): - return {"master_channels": {}, "signal_channels": [], "channel_id_map": {}, - "unsorted_dg_ctx": {}} + return { + "master_channels": {}, + "signal_channels": [], + "channel_id_map": {}, + "unsorted_dg_ctx": {}, + } monkeypatch.setattr( "impulse_ds.mdf.datasources._resolve_file_list", - lambda opts: ["/fake/a.mf4"], + lambda _opts: ["/fake/a.mf4"], ) monkeypatch.setattr( "impulse_ds.mdf.mdf4_reader.MDF4Reader.scan_channels_organized", diff --git a/tests/impulse_ds/mdf/test_mdf4_reader.py b/tests/impulse_ds/mdf/test_mdf4_reader.py index 1e13b1c3..9c4c0211 100644 --- a/tests/impulse_ds/mdf/test_mdf4_reader.py +++ b/tests/impulse_ds/mdf/test_mdf4_reader.py @@ -11,12 +11,9 @@ import pytest import numpy as np -from impulse_ds.mdf.mdf4_reader import ( - MDF4Reader, CN_TYPE_MASTER, CN_TYPE_VIRTUAL_MASTER -) +from impulse_ds.mdf.mdf4_reader import MDF4Reader, CN_TYPE_MASTER, CN_TYPE_VIRTUAL_MASTER from ._mdf_samples import sample_mdf_dir, START_TIME - _DIR, _FILES = sample_mdf_dir() EXAMPLE_DIR = _DIR EXAMPLE_FILES = [os.path.join(_DIR, f) for f in _FILES] # full paths @@ -51,8 +48,7 @@ def test_has_master_channels(self, mdf_file): reader = MDF4Reader(mdf_file) channels = reader.scan_metadata() masters = [ - ch for ch in channels - if ch.channel_type in (CN_TYPE_MASTER, CN_TYPE_VIRTUAL_MASTER) + ch for ch in channels if ch.channel_type in (CN_TYPE_MASTER, CN_TYPE_VIRTUAL_MASTER) ] assert len(masters) > 0, "No master (time) channels found" @@ -63,10 +59,12 @@ def test_read_channel_data(self, mdf_file): # Find a signal channel with data signal_ch = None for ch in channels: - if ch.channel_type not in (CN_TYPE_MASTER, CN_TYPE_VIRTUAL_MASTER): - if ch.sample_count > 0: - signal_ch = ch - break + if ( + ch.channel_type not in (CN_TYPE_MASTER, CN_TYPE_VIRTUAL_MASTER) + and ch.sample_count > 0 + ): + signal_ch = ch + break if signal_ch is None: pytest.skip("No signal channels with data") @@ -99,10 +97,13 @@ def test_read_channel_pair(self, mdf_file): signal_ch = None for ch in channels: - if ch.channel_type not in (CN_TYPE_MASTER, CN_TYPE_VIRTUAL_MASTER): - if ch.sample_count > 0 and ch.group_idx in masters: - signal_ch = ch - break + if ( + ch.channel_type not in (CN_TYPE_MASTER, CN_TYPE_VIRTUAL_MASTER) + and ch.sample_count > 0 + and ch.group_idx in masters + ): + signal_ch = ch + break if signal_ch is None: pytest.skip("No suitable channel pair found") @@ -146,6 +147,7 @@ class TestCrossValidation: def _check_asammdf(self): try: import asammdf + self.asammdf = asammdf except ImportError: pytest.skip("asammdf not installed") @@ -210,9 +212,7 @@ def test_values_match_asammdf(self, mdf_file): # asammdf try: - sig = mdf.get( - ch.channel_name, group=ch.group_idx, index=ch.channel_idx - ) + sig = mdf.get(ch.channel_name, group=ch.group_idx, index=ch.channel_idx) except Exception: continue @@ -224,10 +224,12 @@ def test_values_match_asammdf(self, mdf_file): continue np.testing.assert_allclose( - our_values[:n], ref_values[:n], - rtol=1e-5, atol=1e-10, + our_values[:n], + ref_values[:n], + rtol=1e-5, + atol=1e-10, err_msg=f"Mismatch for channel {ch.channel_name} " - f"(group={ch.group_idx}, idx={ch.channel_idx})" + f"(group={ch.group_idx}, idx={ch.channel_idx})", ) compared += 1 @@ -248,6 +250,7 @@ def test_cc_fields_present_on_channel_info(self, mdf_file): def test_apply_cc_linear(self): from impulse_ds.mdf.udf_helpers import apply_cc_conversion + raw = np.array([0.0, 1.0, 2.0, 100.0]) # linear: phys = 2.0 * raw + 10.0, params = (b=10.0, a=2.0) result = apply_cc_conversion(raw, 1, (10.0, 2.0)) @@ -255,6 +258,7 @@ def test_apply_cc_linear(self): def test_apply_cc_rational(self): from impulse_ds.mdf.udf_helpers import apply_cc_conversion + raw = np.array([1.0, 2.0, 10.0]) # rational: (0*X^2 + 2*X + 1) / (0*X^2 + 0*X + 1) = 2*X + 1 result = apply_cc_conversion(raw, 2, (0.0, 2.0, 1.0, 0.0, 0.0, 1.0)) @@ -262,12 +266,14 @@ def test_apply_cc_rational(self): def test_apply_cc_identity(self): from impulse_ds.mdf.udf_helpers import apply_cc_conversion + raw = np.array([42.0, -1.5, 0.0]) result = apply_cc_conversion(raw, 0, ()) np.testing.assert_array_equal(result, raw) def test_apply_cc_tabular_interp(self): from impulse_ds.mdf.udf_helpers import apply_cc_conversion + # Interleaved per spec: (key_0, val_0, key_1, val_1, key_2, val_2) raw = np.array([0.0, 50.0, 100.0, 150.0, 200.0]) result = apply_cc_conversion(raw, 4, (0.0, 0.0, 100.0, 50.0, 200.0, 100.0)) @@ -275,6 +281,7 @@ def test_apply_cc_tabular_interp(self): def test_apply_cc_no_conversion(self): from impulse_ds.mdf.udf_helpers import apply_cc_conversion + raw = np.array([1.0, 2.0, 3.0]) result = apply_cc_conversion(raw, -1, ()) np.testing.assert_array_equal(result, raw) @@ -284,8 +291,9 @@ def test_apply_cc_no_conversion(self): def test_virtual_master_cc_applied(self): """Verify CC conversion is applied to virtual master timestamps.""" from impulse_ds.mdf.udf_helpers import extract_timestamps + # Simulate raw_data for 5 samples with 8-byte records (any content) - raw_data = b'\x00' * 40 + raw_data = b"\x00" * 40 record_size = 8 master_info = { "channel_type": 3, # virtual master @@ -302,7 +310,8 @@ def test_virtual_master_cc_applied(self): def test_virtual_master_no_cc(self): """Virtual master without CC returns raw indices.""" from impulse_ds.mdf.udf_helpers import extract_timestamps - raw_data = b'\x00' * 24 + + raw_data = b"\x00" * 24 record_size = 8 master_info = { "channel_type": 3, @@ -325,56 +334,84 @@ class TestPlanPartitionsCoalescing: @staticmethod def _ch(gi, ci, samples, addr, ctype=0): from impulse_ds.mdf.mdf4_reader import ChannelInfo + return ChannelInfo( - group_idx=gi, channel_idx=ci, channel_name=f"s{gi}_{ci}", unit="", - sample_count=samples, data_type=4, bit_offset=0, byte_offset=0, - bit_count=64, channel_type=ctype, cn_block_addr=0, cg_block_addr=0, - dg_block_addr=0, data_block_addr=addr, record_size=16, cn_flags=0, - invalidation_bit_pos=0, invalidation_bytes=0, data_bytes=8, - cc_type=-1, cc_params=[], rec_id_size=0, record_id=0) + group_idx=gi, + channel_idx=ci, + channel_name=f"s{gi}_{ci}", + unit="", + sample_count=samples, + data_type=4, + bit_offset=0, + byte_offset=0, + bit_count=64, + channel_type=ctype, + cn_block_addr=0, + cg_block_addr=0, + dg_block_addr=0, + data_block_addr=addr, + record_size=16, + cn_flags=0, + invalidation_bit_pos=0, + invalidation_bytes=0, + data_bytes=8, + cc_type=-1, + cc_params=[], + rec_id_size=0, + record_id=0, + ) def _layout(self): signal, masters, cidmap, gi = [], {}, {}, 0 - for _ in range(2000): # many tiny groups + for _ in range(2000): # many tiny groups addr = 1000 + gi signal.append(self._ch(gi, 1, 100, addr)) masters[gi] = self._ch(gi, 0, 100, addr, ctype=2) - cidmap[(gi, 1)] = gi; gi += 1 - for _ in range(2): # big groups -> record-range split + cidmap[(gi, 1)] = gi + gi += 1 + for _ in range(2): # big groups -> record-range split addr = 1000 + gi signal.append(self._ch(gi, 1, 50_000_000, addr)) masters[gi] = self._ch(gi, 0, 50_000_000, addr, ctype=2) - cidmap[(gi, 1)] = gi; gi += 1 + cidmap[(gi, 1)] = gi + gi += 1 return masters, signal, cidmap def test_coalesces_and_respects_bounds(self): from impulse_ds.mdf.bin_packer import plan_partitions + masters, signal, cidmap = self._layout() cap = 64 target_mb = 256 target_rows = target_mb * 1024 * 1024 // 16 specs = plan_partitions( - "f.mf4", masters, signal, cidmap, - target_partition_mb=target_mb, max_groups_per_partition=cap) + "f.mf4", + masters, + signal, + cidmap, + target_partition_mb=target_mb, + max_groups_per_partition=cap, + ) # Far fewer specs than groups (2000 tiny would-be tasks collapse). assert len(specs) < 2000 / 10 whole = [s for s in specs if "row_start" not in s] for s in whole: blocks = {c["data_block_addr"] for c in s["channels"]} - assert len(blocks) <= cap # group-count bound + assert len(blocks) <= cap # group-count bound rows = sum(c["sample_count"] for c in s["channels"]) - assert rows <= target_rows # output-row bound + assert rows <= target_rows # output-row bound # Big groups still split by record range. assert any("row_start" in s for s in specs) def test_full_channel_coverage_exactly_once(self): from impulse_ds.mdf.bin_packer import plan_partitions + masters, signal, cidmap = self._layout() specs = plan_partitions( - "f.mf4", masters, signal, cidmap, - target_partition_mb=256, max_groups_per_partition=64) + "f.mf4", masters, signal, cidmap, target_partition_mb=256, max_groups_per_partition=64 + ) # Every channel appears (whole-group once; ranged groups contiguously). whole_seen = set() ranges = {} @@ -386,11 +423,11 @@ def test_full_channel_coverage_exactly_once(self): else: assert key not in whole_seen, "channel double-counted" whole_seen.add(key) - for key, ivs in ranges.items(): + for _key, ivs in ranges.items(): ivs.sort() assert ivs[0][0] == 0 - for a, b in zip(ivs, ivs[1:]): - assert a[1] == b[0] # contiguous, no gaps/overlap + for a, b in zip(ivs, ivs[1:], strict=False): + assert a[1] == b[0] # contiguous, no gaps/overlap all_keys = whole_seen | set(ranges) assert len(all_keys) == len(signal) @@ -430,21 +467,41 @@ def test_linear_cc_on_sample_c(self): scaled = [c for c in channels if c.channel_name == "Scaled"][0] assert scaled.cc_type == 1 values = MDF4Reader.read_channel_data( - path, scaled.data_block_addr, scaled.record_size, - scaled.byte_offset, scaled.bit_offset, scaled.bit_count, - scaled.data_type, scaled.channel_type, scaled.sample_count, - cc_type=scaled.cc_type, cc_params=scaled.cc_params, + path, + scaled.data_block_addr, + scaled.record_size, + scaled.byte_offset, + scaled.bit_offset, + scaled.bit_count, + scaled.data_type, + scaled.channel_type, + scaled.sample_count, + cc_type=scaled.cc_type, + cc_params=scaled.cc_params, ) np.testing.assert_allclose(values, np.arange(10) * 2.0 + 10.0) def test_channel_to_dict_unsorted_fields(self): from impulse_ds.mdf.mdf4_reader import ChannelInfo + ch = ChannelInfo( - group_idx=0, channel_idx=0, channel_name="x", unit="", - sample_count=1, data_type=4, bit_offset=0, byte_offset=4, - bit_count=64, channel_type=0, cn_block_addr=0, cg_block_addr=0, - dg_block_addr=100, data_block_addr=1000, record_size=20, - rec_id_size=4, record_id=1, + group_idx=0, + channel_idx=0, + channel_name="x", + unit="", + sample_count=1, + data_type=4, + bit_offset=0, + byte_offset=4, + bit_count=64, + channel_type=0, + cn_block_addr=0, + cg_block_addr=0, + dg_block_addr=100, + data_block_addr=1000, + record_size=20, + rec_id_size=4, + record_id=1, ) ctx = {100: {"rec_id_size": 4, "cg_sizes": {1: 20}}} d = MDF4Reader.channel_to_dict(ch, ctx) diff --git a/tests/impulse_ds/mdf/test_mdf_blocks.py b/tests/impulse_ds/mdf/test_mdf_blocks.py index 1da15159..d0b670bb 100644 --- a/tests/impulse_ds/mdf/test_mdf_blocks.py +++ b/tests/impulse_ds/mdf/test_mdf_blocks.py @@ -155,7 +155,14 @@ def test_dt_streaming_with_row_range(self): with io.BytesIO(blob) as f: chunks = list( _read_block_chunks( - f, 0, 8, 10, row_start=2, row_end=5, prof=prof, log=log, + f, + 0, + 8, + 10, + row_start=2, + row_end=5, + prof=prof, + log=log, ) ) assert len(chunks) == 1 @@ -171,14 +178,22 @@ def test_dl_row_range_chunks(self): with io.BytesIO(blob) as f: chunks = list( _read_block_chunks( - f, dl_addr, 8, 4, row_start=1, row_end=3, prof=prof, log=log, + f, + dl_addr, + 8, + 4, + row_start=1, + row_end=3, + prof=prof, + log=log, ) ) assert len(chunks) == 1 raw, start = chunks[0] assert start == 1 np.testing.assert_allclose( - np.frombuffer(raw, dtype=np.float64), [1.0, 2.0], + np.frombuffer(raw, dtype=np.float64), + [1.0, 2.0], ) diff --git a/tests/impulse_ds/mdf/test_mdf_coverage_gaps.py b/tests/impulse_ds/mdf/test_mdf_coverage_gaps.py index e7a28f65..8f4b1649 100644 --- a/tests/impulse_ds/mdf/test_mdf_coverage_gaps.py +++ b/tests/impulse_ds/mdf/test_mdf_coverage_gaps.py @@ -120,7 +120,8 @@ def test_uint_be_and_padded_widths(self): raw16 = struct.pack(">2H", 100, 200) col16 = np.frombuffer(raw16, dtype=np.uint8).reshape(2, 2) np.testing.assert_allclose( - convert_values(col16, UINT_BE, 16, 0, 2), [100.0, 200.0], + convert_values(col16, UINT_BE, 16, 0, 2), + [100.0, 200.0], ) # 24-bit little-endian in 3-byte columns col24 = np.array([[0x12, 0x34, 0x56], [0x78, 0x9A, 0xBC]], dtype=np.uint8) @@ -132,7 +133,8 @@ def test_sint_be_and_padded(self): raw = struct.pack(">2h", -3, 7) col = np.frombuffer(raw, dtype=np.uint8).reshape(2, 2) np.testing.assert_allclose( - convert_values(col, SINT_BE, 16, 0, 2), [-3.0, 7.0], + convert_values(col, SINT_BE, 16, 0, 2), + [-3.0, 7.0], ) raw32 = struct.pack(" 0 def test_rle_helpers_edge_cases(self): @@ -344,10 +381,14 @@ def test_rle_integration_small_partition(self): d, files = sample_mdf_dir() if not files: pytest.skip("no samples") - reader = MdfSignalsReader({ - "path": d, "files": files[0], "target_partition_mb": "0.0001", - "run_length_encoding": "true", - }) + reader = MdfSignalsReader( + { + "path": d, + "files": files[0], + "target_partition_mb": "0.0001", + "run_length_encoding": "true", + } + ) rows = sum(b.num_rows for p in reader.partitions() for b in reader.read(p)) assert rows > 0 @@ -356,6 +397,7 @@ def test_signals_float32_and_masters_schema(self): if not files: pytest.skip("no samples") from impulse_ds.mdf.datasources import MdfMastersDataSource, MdfSignalsDataSource + opts = {"path": d, "files": files[0], "time_dtype": "float32", "value_dtype": "float32"} assert MdfSignalsDataSource(opts).schema()["value"].dataType.simpleString() == "float" assert MdfMastersDataSource(opts).schema()["timestamp"].dataType.simpleString() == "float" @@ -377,8 +419,11 @@ def _make_cc_block(self, cc_type, params): link_count = 0 length = 24 + len(body) return ( - BLOCK_ID_CC + b"\x00" * 4 + struct.pack("> 4 vals = extract_signal(raw, rs, ch) @@ -548,19 +685,43 @@ def test_extract_signal_slow_path_and_cc(self): def test_extract_timestamps_with_cc(self): raw = struct.pack(" 0 def test_stripe_decompress_failure_skipped(self, monkeypatch): @@ -968,6 +1264,7 @@ def test_stripe_decompress_failure_skipped(self, monkeypatch): pytest.skip("no samples") path = f"{d}/{files[0]}" from impulse_ds.mdf.bin_packer import plan_stripes_for_file + specs = plan_stripes_for_file(path, stripe_target_mb=0.001) def _bad_decompress(*a, **k): @@ -983,10 +1280,14 @@ def test_convert_spec_extent_error_and_empty_slice(self, monkeypatch): path = f"{d}/{files[0]}" from impulse_ds.mdf.bin_packer import plan_partitions from impulse_ds.mdf.mdf4_reader import MDF4Reader + org = MDF4Reader(path).scan_channels_organized() specs = plan_partitions( - path, org["master_channels"], org["signal_channels"], - org["channel_id_map"], target_partition_mb=16, + path, + org["master_channels"], + org["signal_channels"], + org["channel_id_map"], + target_partition_mb=16, ) spec = dict(specs[0]) spec["row_start"] = 0 @@ -1001,11 +1302,15 @@ def _raise(*a, **k): def test_master_spec_zero_record_size(self): spec = { "file_path": "/dev/null", - "masters": [{ - "group_idx": 0, "record_size": 0, "sample_count": 1, - "data_block_addr": 0, - "master_info": {"channel_type": 3, "cc_type": -1, "cc_params": []}, - }], + "masters": [ + { + "group_idx": 0, + "record_size": 0, + "sample_count": 1, + "data_block_addr": 0, + "master_info": {"channel_type": 3, "cc_type": -1, "cc_params": []}, + } + ], } assert list(convert_master_spec_to_arrow_batches(spec)) == [] @@ -1016,10 +1321,14 @@ def test_convert_spec_without_master_info(self): path = f"{d}/{files[0]}" from impulse_ds.mdf.bin_packer import plan_partitions from impulse_ds.mdf.mdf4_reader import MDF4Reader + org = MDF4Reader(path).scan_channels_organized() specs = plan_partitions( - path, org["master_channels"], org["signal_channels"], - org["channel_id_map"], target_partition_mb=16, + path, + org["master_channels"], + org["signal_channels"], + org["channel_id_map"], + target_partition_mb=16, ) spec = dict(specs[0]) ch = dict(spec["channels"][0]) @@ -1035,14 +1344,23 @@ def test_convert_spec_rle_flush_and_float32(self): path = f"{d}/{files[0]}" from impulse_ds.mdf.bin_packer import plan_partitions from impulse_ds.mdf.mdf4_reader import MDF4Reader + org = MDF4Reader(path).scan_channels_organized() specs = plan_partitions( - path, org["master_channels"], org["signal_channels"], - org["channel_id_map"], target_partition_mb=16, + path, + org["master_channels"], + org["signal_channels"], + org["channel_id_map"], + target_partition_mb=16, + ) + batches = list( + convert_spec_to_arrow_batches( + specs[0], + run_length_encoding=True, + time_dtype="float32", + value_dtype="float32", + ) ) - batches = list(convert_spec_to_arrow_batches( - specs[0], run_length_encoding=True, time_dtype="float32", value_dtype="float32", - )) assert batches def test_stripe_unsorted_decompress_failure(self, monkeypatch): @@ -1067,10 +1385,15 @@ def test_stripe_unsorted_decompress_failure(self, monkeypatch): "cg_record_sizes": cg_sizes, }, }, - "subblocks": [{ - "group_idx": 0, "abs_off": 0, "on_disk_len": len(blob), - "rec_start": 0, "rec_count": 3, - }], + "subblocks": [ + { + "group_idx": 0, + "abs_off": 0, + "on_disk_len": len(blob), + "rec_start": 0, + "rec_count": 3, + } + ], } def _bad(*a, **k): @@ -1084,30 +1407,60 @@ def _bad(*a, **k): def test_emit_prepared_skips_vlsd_channel(self): import logging import time + prof = {"decode": 0} log = logging.getLogger("t") now = time.perf_counter_ns vlsd = { - "channel_id": 2, "channel_type": 1, "data_type": FLOAT_LE, - "bit_count": 64, "byte_offset": 0, "bit_offset": 0, - "cn_flags": 0, "invalidation_bytes": 0, "data_bytes": 8, - "cc_type": -1, "cc_params": [], + "channel_id": 2, + "channel_type": 1, + "data_type": FLOAT_LE, + "bit_count": 64, + "byte_offset": 0, + "bit_offset": 0, + "cn_flags": 0, + "invalidation_bytes": 0, + "data_bytes": 8, + "cc_type": -1, + "cc_params": [], } good = { - "channel_id": 1, "channel_type": 0, "data_type": FLOAT_LE, - "bit_count": 64, "byte_offset": 0, "bit_offset": 0, - "cn_flags": 0, "invalidation_bytes": 0, "data_bytes": 8, - "cc_type": -1, "cc_params": [], + "channel_id": 1, + "channel_type": 0, + "data_type": FLOAT_LE, + "bit_count": 64, + "byte_offset": 0, + "bit_offset": 0, + "cn_flags": 0, + "invalidation_bytes": 0, + "data_bytes": 8, + "cc_type": -1, + "cc_params": [], } raw = struct.pack(" str: dt += payload fd, path = tempfile.mkstemp(suffix=".mf4") import os + os.write(fd, dt) os.close(fd) return path @@ -189,15 +214,27 @@ def test_signal_and_timestamps_from_filtered_bytes(self): cg_record_sizes=cg_sizes, ) master = { - "byte_offset": 4, "bit_offset": 0, "bit_count": 64, - "data_type": 4, "channel_type": 2, "cc_type": -1, "cc_params": [], + "byte_offset": 4, + "bit_offset": 0, + "bit_count": 64, + "data_type": 4, + "channel_type": 2, + "cc_type": -1, + "cc_params": [], } ch = { - "channel_type": 0, "data_type": 4, "bit_count": 64, - "byte_offset": 12, "bit_offset": 0, "record_size": record_size, - "cn_flags": 0, "invalidation_bit_pos": 0, - "invalidation_bytes": 0, "data_bytes": 16, - "cc_type": -1, "cc_params": [], + "channel_type": 0, + "data_type": 4, + "bit_count": 64, + "byte_offset": 12, + "bit_offset": 0, + "record_size": record_size, + "cn_flags": 0, + "invalidation_bit_pos": 0, + "invalidation_bytes": 0, + "data_bytes": 16, + "cc_type": -1, + "cc_params": [], } ts = extract_timestamps(prepared, record_size, master, index_offset=offset) vals = extract_signal(prepared, record_size, ch) From 7e66ccffff8dc8d70b240c3b714d26c49275e31c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Br=C3=A4uer?= Date: Tue, 4 Aug 2026 08:56:58 +0200 Subject: [PATCH 6/8] reset uv.lock --- uv.lock | 1116 +++++++++++++++++++++++++++---------------------------- 1 file changed, 558 insertions(+), 558 deletions(-) diff --git a/uv.lock b/uv.lock index 82c530e2..2104348b 100644 --- a/uv.lock +++ b/uv.lock @@ -5,16 +5,16 @@ requires-python = "==3.12.*" [[package]] name = "annotated-types" version = "0.7.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", upload-time = "2024-05-20T21:33:25.928Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", upload-time = "2024-05-20T21:33:25.928Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", upload-time = "2024-05-20T21:33:24.1Z" }, + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", upload-time = "2024-05-20T21:33:24.1Z" }, ] [[package]] name = "asammdf" version = "8.0.1" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "canmatrix", extra = ["arxml"] }, { name = "isal", marker = "platform_machine == 'AMD64' or platform_machine == 'x86_64'" }, @@ -26,26 +26,26 @@ dependencies = [ { name = "python-dateutil" }, { name = "typing-extensions" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/6a/5c/5173d96d95dbb75f2700baf2e30ab71d91326b9187c993b44ad2730a8733/asammdf-8.0.1.tar.gz", hash = "sha256:aa40bb4103aefbea75777ff4888c8ee20089e62f0c141f7e07c01de1beb93247", upload-time = "2024-10-01T13:28:29.812Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/5c/5173d96d95dbb75f2700baf2e30ab71d91326b9187c993b44ad2730a8733/asammdf-8.0.1.tar.gz", hash = "sha256:aa40bb4103aefbea75777ff4888c8ee20089e62f0c141f7e07c01de1beb93247", upload-time = "2024-10-01T13:28:29.812Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/52/38/db219cbbe76dbcb1d32dba768fc4fca192c098b6fca1862805a06e0c1fc0/asammdf-8.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e70cfc85a16e96569d45e304796d4401b5e3796d7f846d6f66da44b6baf77aec", upload-time = "2024-10-01T13:27:59.663Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/44/8c/5b2385bc3b0511a2a96ed8e1643df64dcf190d60cfb95849625a9ab7c8b4/asammdf-8.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a07ebbbf1f4f6f724a2f992eaff809a4f6000e7e9a1796657e9857e589529e57", upload-time = "2024-10-01T13:28:06.293Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/f4/a9/6ad9208ed9f5ed077dddca45c12b192e3b1c9641e959742cdede549c0e49/asammdf-8.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:d9685e07503671816680b485c7032716acac72fd31e247a6acb059a775cd2100", upload-time = "2024-10-01T13:28:13.363Z" }, + { url = "https://files.pythonhosted.org/packages/52/38/db219cbbe76dbcb1d32dba768fc4fca192c098b6fca1862805a06e0c1fc0/asammdf-8.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e70cfc85a16e96569d45e304796d4401b5e3796d7f846d6f66da44b6baf77aec", upload-time = "2024-10-01T13:27:59.663Z" }, + { url = "https://files.pythonhosted.org/packages/44/8c/5b2385bc3b0511a2a96ed8e1643df64dcf190d60cfb95849625a9ab7c8b4/asammdf-8.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a07ebbbf1f4f6f724a2f992eaff809a4f6000e7e9a1796657e9857e589529e57", upload-time = "2024-10-01T13:28:06.293Z" }, + { url = "https://files.pythonhosted.org/packages/f4/a9/6ad9208ed9f5ed077dddca45c12b192e3b1c9641e959742cdede549c0e49/asammdf-8.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:d9685e07503671816680b485c7032716acac72fd31e247a6acb059a775cd2100", upload-time = "2024-10-01T13:28:13.363Z" }, ] [[package]] name = "attrs" version = "26.1.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", upload-time = "2026-03-19T14:22:25.026Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", upload-time = "2026-03-19T14:22:25.026Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", upload-time = "2026-03-19T14:22:23.645Z" }, + { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", upload-time = "2026-03-19T14:22:23.645Z" }, ] [[package]] name = "black" version = "26.3.1" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "mypy-extensions" }, @@ -54,27 +54,27 @@ dependencies = [ { name = "platformdirs" }, { name = "pytokens" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/e1/c5/61175d618685d42b005847464b8fb4743a67b1b8fdb75e50e5a96c31a27a/black-26.3.1.tar.gz", hash = "sha256:2c50f5063a9641c7eed7795014ba37b0f5fa227f3d408b968936e24bc0566b07", upload-time = "2026-03-12T03:36:03.593Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/c5/61175d618685d42b005847464b8fb4743a67b1b8fdb75e50e5a96c31a27a/black-26.3.1.tar.gz", hash = "sha256:2c50f5063a9641c7eed7795014ba37b0f5fa227f3d408b968936e24bc0566b07", upload-time = "2026-03-12T03:36:03.593Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/dc/f8/da5eae4fc75e78e6dceb60624e1b9662ab00d6b452996046dfa9b8a6025b/black-26.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e6f89631eb88a7302d416594a32faeee9fb8fb848290da9d0a5f2903519fc1", upload-time = "2026-03-12T03:40:13.921Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/2c/9f/04e6f26534da2e1629b2b48255c264cabf5eedc5141d04516d9d68a24111/black-26.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41cd2012d35b47d589cb8a16faf8a32ef7a336f56356babd9fcf70939ad1897f", upload-time = "2026-03-12T03:40:15.239Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/04/91/a5935b2a63e31b331060c4a9fdb5a6c725840858c599032a6f3aac94055f/black-26.3.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f76ff19ec5297dd8e66eb64deda23631e642c9393ab592826fd4bdc97a4bce7", upload-time = "2026-03-12T03:40:17.124Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/e7/0a/86e462cdd311a3c2a8ece708d22aba17d0b2a0d5348ca34b40cdcbea512e/black-26.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:ddb113db38838eb9f043623ba274cfaf7d51d5b0c22ecb30afe58b1bb8322983", upload-time = "2026-03-12T03:40:18.83Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/5b/e5/22515a19cb7eaee3440325a6b0d95d2c0e88dd180cb011b12ae488e031d1/black-26.3.1-cp312-cp312-win_arm64.whl", hash = "sha256:dfdd51fc3e64ea4f35873d1b3fb25326773d55d2329ff8449139ebaad7357efb", upload-time = "2026-03-12T03:40:20.425Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/8e/0d/52d98722666d6fc6c3dd4c76df339501d6efd40e0ff95e6186a7b7f0befd/black-26.3.1-py3-none-any.whl", hash = "sha256:2bd5aa94fc267d38bb21a70d7410a89f1a1d318841855f698746f8e7f51acd1b", upload-time = "2026-03-12T03:36:01.668Z" }, + { url = "https://files.pythonhosted.org/packages/dc/f8/da5eae4fc75e78e6dceb60624e1b9662ab00d6b452996046dfa9b8a6025b/black-26.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e6f89631eb88a7302d416594a32faeee9fb8fb848290da9d0a5f2903519fc1", upload-time = "2026-03-12T03:40:13.921Z" }, + { url = "https://files.pythonhosted.org/packages/2c/9f/04e6f26534da2e1629b2b48255c264cabf5eedc5141d04516d9d68a24111/black-26.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41cd2012d35b47d589cb8a16faf8a32ef7a336f56356babd9fcf70939ad1897f", upload-time = "2026-03-12T03:40:15.239Z" }, + { url = "https://files.pythonhosted.org/packages/04/91/a5935b2a63e31b331060c4a9fdb5a6c725840858c599032a6f3aac94055f/black-26.3.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f76ff19ec5297dd8e66eb64deda23631e642c9393ab592826fd4bdc97a4bce7", upload-time = "2026-03-12T03:40:17.124Z" }, + { url = "https://files.pythonhosted.org/packages/e7/0a/86e462cdd311a3c2a8ece708d22aba17d0b2a0d5348ca34b40cdcbea512e/black-26.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:ddb113db38838eb9f043623ba274cfaf7d51d5b0c22ecb30afe58b1bb8322983", upload-time = "2026-03-12T03:40:18.83Z" }, + { url = "https://files.pythonhosted.org/packages/5b/e5/22515a19cb7eaee3440325a6b0d95d2c0e88dd180cb011b12ae488e031d1/black-26.3.1-cp312-cp312-win_arm64.whl", hash = "sha256:dfdd51fc3e64ea4f35873d1b3fb25326773d55d2329ff8449139ebaad7357efb", upload-time = "2026-03-12T03:40:20.425Z" }, + { url = "https://files.pythonhosted.org/packages/8e/0d/52d98722666d6fc6c3dd4c76df339501d6efd40e0ff95e6186a7b7f0befd/black-26.3.1-py3-none-any.whl", hash = "sha256:2bd5aa94fc267d38bb21a70d7410a89f1a1d318841855f698746f8e7f51acd1b", upload-time = "2026-03-12T03:36:01.668Z" }, ] [[package]] name = "canmatrix" version = "1.2" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "click" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/8a/ed/a05ab5923cd2a6e239317992cf876753cbb8d4f9ff729ce916599dcd0abb/canmatrix-1.2.tar.gz", hash = "sha256:19d5ba3fd69974bd41985b90198503bfde6ae3639dfc8ce6a2f7a0338787dbf7", upload-time = "2025-02-17T10:22:40.154Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8a/ed/a05ab5923cd2a6e239317992cf876753cbb8d4f9ff729ce916599dcd0abb/canmatrix-1.2.tar.gz", hash = "sha256:19d5ba3fd69974bd41985b90198503bfde6ae3639dfc8ce6a2f7a0338787dbf7", upload-time = "2025-02-17T10:22:40.154Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/f2/9c/6c2dc03d2aa30176985257b64bf3393c77d28bc019db28654c8c514493f2/canmatrix-1.2-py3-none-any.whl", hash = "sha256:9fbb03c58404489f7d2832ec31b8b10f3e7d5525f15456f60f852b89e721ebf9", upload-time = "2025-02-17T10:22:38.13Z" }, + { url = "https://files.pythonhosted.org/packages/f2/9c/6c2dc03d2aa30176985257b64bf3393c77d28bc019db28654c8c514493f2/canmatrix-1.2-py3-none-any.whl", hash = "sha256:9fbb03c58404489f7d2832ec31b8b10f3e7d5525f15456f60f852b89e721ebf9", upload-time = "2025-02-17T10:22:38.13Z" }, ] [package.optional-dependencies] @@ -85,188 +85,188 @@ arxml = [ [[package]] name = "certifi" version = "2026.4.22" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/25/ee/6caf7a40c36a1220410afe15a1cc64993a1f864871f698c0f93acb72842a/certifi-2026.4.22.tar.gz", hash = "sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580", upload-time = "2026-04-22T11:26:11.191Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/25/ee/6caf7a40c36a1220410afe15a1cc64993a1f864871f698c0f93acb72842a/certifi-2026.4.22.tar.gz", hash = "sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580", upload-time = "2026-04-22T11:26:11.191Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/22/30/7cd8fdcdfbc5b869528b079bfb76dcdf6056b1a2097a662e5e8c04f42965/certifi-2026.4.22-py3-none-any.whl", hash = "sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a", upload-time = "2026-04-22T11:26:09.372Z" }, + { url = "https://files.pythonhosted.org/packages/22/30/7cd8fdcdfbc5b869528b079bfb76dcdf6056b1a2097a662e5e8c04f42965/certifi-2026.4.22-py3-none-any.whl", hash = "sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a", upload-time = "2026-04-22T11:26:09.372Z" }, ] [[package]] name = "cffi" version = "2.0.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycparser", marker = "implementation_name != 'PyPy'" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", upload-time = "2025-09-08T23:24:04.541Z" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", upload-time = "2025-09-08T23:24:04.541Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", upload-time = "2025-09-08T23:22:44.795Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", upload-time = "2025-09-08T23:22:45.938Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", upload-time = "2025-09-08T23:22:47.349Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", upload-time = "2025-09-08T23:22:48.677Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", upload-time = "2025-09-08T23:22:50.06Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", upload-time = "2025-09-08T23:22:51.364Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", upload-time = "2025-09-08T23:22:52.902Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", upload-time = "2025-09-08T23:22:54.518Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", upload-time = "2025-09-08T23:22:55.867Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", upload-time = "2025-09-08T23:22:57.188Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", upload-time = "2025-09-08T23:22:58.351Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", upload-time = "2025-09-08T23:22:59.668Z" }, ] [[package]] name = "cfgv" version = "3.5.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", upload-time = "2025-11-19T20:55:51.612Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", upload-time = "2025-11-19T20:55:51.612Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", upload-time = "2025-11-19T20:55:50.744Z" }, + { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", upload-time = "2025-11-19T20:55:50.744Z" }, ] [[package]] name = "charset-normalizer" version = "3.4.7" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", upload-time = "2026-04-02T09:28:39.342Z" } -wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", upload-time = "2026-04-02T09:26:24.331Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/f8/e3/0fadc706008ac9d7b9b5be6dc767c05f9d3e5df51744ce4cc9605de7b9f4/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", upload-time = "2026-04-02T09:26:25.568Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/42/f0/3dd1045c47f4a4604df85ec18ad093912ae1344ac706993aff91d38773a2/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", upload-time = "2026-04-02T09:26:26.865Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/dc/67/675a46eb016118a2fbde5a277a5d15f4f69d5f3f5f338e5ee2f8948fcf43/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a", upload-time = "2026-04-02T09:26:28.044Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/4b/f8/d0118a2f5f23b02cd166fa385c60f9b0d4f9194f574e2b31cef350ad7223/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116", upload-time = "2026-04-02T09:26:29.239Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/b1/f1/6d2b0b261b6c4ceef0fcb0d17a01cc5bc53586c2d4796fa04b5c540bc13d/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb", upload-time = "2026-04-02T09:26:30.5Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/6f/c0/7b1f943f7e87cc3db9626ba17807d042c38645f0a1d4415c7a14afb5591f/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1", upload-time = "2026-04-02T09:26:31.709Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/38/dd/5a9ab159fe45c6e72079398f277b7d2b523e7f716acc489726115a910097/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15", upload-time = "2026-04-02T09:26:33.282Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/d5/ff/531a1cad5ca855d1c1a8b69cb71abfd6d85c0291580146fda7c82857caa1/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5", upload-time = "2026-04-02T09:26:34.845Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/c1/4c/a5fb52d528a8ca41f7598cb619409ece30a169fbdf9cdce592e53b46c3a6/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d", upload-time = "2026-04-02T09:26:36.152Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/59/7a/071feed8124111a32b316b33ae4de83d36923039ef8cf48120266844285b/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7", upload-time = "2026-04-02T09:26:37.672Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/fd/35/f7dba3994312d7ba508e041eaac39a36b120f32d4c8662b8814dab876431/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464", upload-time = "2026-04-02T09:26:38.93Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/8a/2d/a572df5c9204ab7688ec1edc895a73ebded3b023bb07364710b05dd1c9be/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49", upload-time = "2026-04-02T09:26:40.17Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/86/eb/890922a8b03a568ca2f336c36585a4713c55d4d67bf0f0c78924be6315ca/charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c", upload-time = "2026-04-02T09:26:41.416Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/35/d9/0e7dffa06c5ab081f75b1b786f0aefc88365825dfcd0ac544bdb7b2b6853/charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6", upload-time = "2026-04-02T09:26:42.554Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/9e/5d/481bcc2a7c88ea6b0878c299547843b2521ccbc40980cb406267088bc701/charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d", upload-time = "2026-04-02T09:26:44.075Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", upload-time = "2026-04-02T09:28:37.794Z" }, +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", upload-time = "2026-04-02T09:28:39.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", upload-time = "2026-04-02T09:26:24.331Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e3/0fadc706008ac9d7b9b5be6dc767c05f9d3e5df51744ce4cc9605de7b9f4/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", upload-time = "2026-04-02T09:26:25.568Z" }, + { url = "https://files.pythonhosted.org/packages/42/f0/3dd1045c47f4a4604df85ec18ad093912ae1344ac706993aff91d38773a2/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", upload-time = "2026-04-02T09:26:26.865Z" }, + { url = "https://files.pythonhosted.org/packages/dc/67/675a46eb016118a2fbde5a277a5d15f4f69d5f3f5f338e5ee2f8948fcf43/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a", upload-time = "2026-04-02T09:26:28.044Z" }, + { url = "https://files.pythonhosted.org/packages/4b/f8/d0118a2f5f23b02cd166fa385c60f9b0d4f9194f574e2b31cef350ad7223/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116", upload-time = "2026-04-02T09:26:29.239Z" }, + { url = "https://files.pythonhosted.org/packages/b1/f1/6d2b0b261b6c4ceef0fcb0d17a01cc5bc53586c2d4796fa04b5c540bc13d/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb", upload-time = "2026-04-02T09:26:30.5Z" }, + { url = "https://files.pythonhosted.org/packages/6f/c0/7b1f943f7e87cc3db9626ba17807d042c38645f0a1d4415c7a14afb5591f/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1", upload-time = "2026-04-02T09:26:31.709Z" }, + { url = "https://files.pythonhosted.org/packages/38/dd/5a9ab159fe45c6e72079398f277b7d2b523e7f716acc489726115a910097/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15", upload-time = "2026-04-02T09:26:33.282Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ff/531a1cad5ca855d1c1a8b69cb71abfd6d85c0291580146fda7c82857caa1/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5", upload-time = "2026-04-02T09:26:34.845Z" }, + { url = "https://files.pythonhosted.org/packages/c1/4c/a5fb52d528a8ca41f7598cb619409ece30a169fbdf9cdce592e53b46c3a6/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d", upload-time = "2026-04-02T09:26:36.152Z" }, + { url = "https://files.pythonhosted.org/packages/59/7a/071feed8124111a32b316b33ae4de83d36923039ef8cf48120266844285b/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7", upload-time = "2026-04-02T09:26:37.672Z" }, + { url = "https://files.pythonhosted.org/packages/fd/35/f7dba3994312d7ba508e041eaac39a36b120f32d4c8662b8814dab876431/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464", upload-time = "2026-04-02T09:26:38.93Z" }, + { url = "https://files.pythonhosted.org/packages/8a/2d/a572df5c9204ab7688ec1edc895a73ebded3b023bb07364710b05dd1c9be/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49", upload-time = "2026-04-02T09:26:40.17Z" }, + { url = "https://files.pythonhosted.org/packages/86/eb/890922a8b03a568ca2f336c36585a4713c55d4d67bf0f0c78924be6315ca/charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c", upload-time = "2026-04-02T09:26:41.416Z" }, + { url = "https://files.pythonhosted.org/packages/35/d9/0e7dffa06c5ab081f75b1b786f0aefc88365825dfcd0ac544bdb7b2b6853/charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6", upload-time = "2026-04-02T09:26:42.554Z" }, + { url = "https://files.pythonhosted.org/packages/9e/5d/481bcc2a7c88ea6b0878c299547843b2521ccbc40980cb406267088bc701/charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d", upload-time = "2026-04-02T09:26:44.075Z" }, + { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", upload-time = "2026-04-02T09:28:37.794Z" }, ] [[package]] name = "click" version = "8.3.3" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/bb/63/f9e1ea081ce35720d8b92acde70daaedace594dc93b693c869e0d5910718/click-8.3.3.tar.gz", hash = "sha256:398329ad4837b2ff7cbe1dd166a4c0f8900c3ca3a218de04466f38f6497f18a2", upload-time = "2026-04-22T15:11:27.506Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/63/f9e1ea081ce35720d8b92acde70daaedace594dc93b693c869e0d5910718/click-8.3.3.tar.gz", hash = "sha256:398329ad4837b2ff7cbe1dd166a4c0f8900c3ca3a218de04466f38f6497f18a2", upload-time = "2026-04-22T15:11:27.506Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/ae/44/c1221527f6a71a01ec6fbad7fa78f1d50dfa02217385cf0fa3eec7087d59/click-8.3.3-py3-none-any.whl", hash = "sha256:a2bf429bb3033c89fa4936ffb35d5cb471e3719e1f3c8a7c3fff0b8314305613", upload-time = "2026-04-22T15:11:25.044Z" }, + { url = "https://files.pythonhosted.org/packages/ae/44/c1221527f6a71a01ec6fbad7fa78f1d50dfa02217385cf0fa3eec7087d59/click-8.3.3-py3-none-any.whl", hash = "sha256:a2bf429bb3033c89fa4936ffb35d5cb471e3719e1f3c8a7c3fff0b8314305613", upload-time = "2026-04-22T15:11:25.044Z" }, ] [[package]] name = "colorama" version = "0.4.6" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", upload-time = "2022-10-25T02:36:22.414Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", upload-time = "2022-10-25T02:36:22.414Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", upload-time = "2022-10-25T02:36:20.889Z" }, + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", upload-time = "2022-10-25T02:36:20.889Z" }, ] [[package]] name = "contourpy" version = "1.3.3" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", upload-time = "2025-07-26T12:03:12.549Z" } +sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", upload-time = "2025-07-26T12:03:12.549Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/be/45/adfee365d9ea3d853550b2e735f9d66366701c65db7855cd07621732ccfc/contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb", upload-time = "2025-07-26T12:01:21.16Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6", upload-time = "2025-07-26T12:01:22.448Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/d4/1c/a12359b9b2ca3a845e8f7f9ac08bdf776114eb931392fcad91743e2ea17b/contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7", upload-time = "2025-07-26T12:01:24.155Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/63/12/897aeebfb475b7748ea67b61e045accdfcf0d971f8a588b67108ed7f5512/contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8", upload-time = "2025-07-26T12:01:25.91Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/43/8a/a8c584b82deb248930ce069e71576fc09bd7174bbd35183b7943fb1064fd/contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea", upload-time = "2025-07-26T12:01:27.152Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1", upload-time = "2025-07-26T12:01:28.808Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/05/0a/a3fe3be3ee2dceb3e615ebb4df97ae6f3828aa915d3e10549ce016302bd1/contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7", upload-time = "2025-07-26T12:01:31.198Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/33/1d/acad9bd4e97f13f3e2b18a3977fe1b4a37ecf3d38d815333980c6c72e963/contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411", upload-time = "2025-07-26T12:01:33.947Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/cf/8f/5847f44a7fddf859704217a99a23a4f6417b10e5ab1256a179264561540e/contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69", upload-time = "2025-07-26T12:01:35.64Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b", upload-time = "2025-07-26T12:01:36.804Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/d1/e2/f05240d2c39a1ed228d8328a78b6f44cd695f7ef47beb3e684cf93604f86/contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc", upload-time = "2025-07-26T12:01:37.999Z" }, + { url = "https://files.pythonhosted.org/packages/be/45/adfee365d9ea3d853550b2e735f9d66366701c65db7855cd07621732ccfc/contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb", upload-time = "2025-07-26T12:01:21.16Z" }, + { url = "https://files.pythonhosted.org/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6", upload-time = "2025-07-26T12:01:22.448Z" }, + { url = "https://files.pythonhosted.org/packages/d4/1c/a12359b9b2ca3a845e8f7f9ac08bdf776114eb931392fcad91743e2ea17b/contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7", upload-time = "2025-07-26T12:01:24.155Z" }, + { url = "https://files.pythonhosted.org/packages/63/12/897aeebfb475b7748ea67b61e045accdfcf0d971f8a588b67108ed7f5512/contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8", upload-time = "2025-07-26T12:01:25.91Z" }, + { url = "https://files.pythonhosted.org/packages/43/8a/a8c584b82deb248930ce069e71576fc09bd7174bbd35183b7943fb1064fd/contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea", upload-time = "2025-07-26T12:01:27.152Z" }, + { url = "https://files.pythonhosted.org/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1", upload-time = "2025-07-26T12:01:28.808Z" }, + { url = "https://files.pythonhosted.org/packages/05/0a/a3fe3be3ee2dceb3e615ebb4df97ae6f3828aa915d3e10549ce016302bd1/contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7", upload-time = "2025-07-26T12:01:31.198Z" }, + { url = "https://files.pythonhosted.org/packages/33/1d/acad9bd4e97f13f3e2b18a3977fe1b4a37ecf3d38d815333980c6c72e963/contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411", upload-time = "2025-07-26T12:01:33.947Z" }, + { url = "https://files.pythonhosted.org/packages/cf/8f/5847f44a7fddf859704217a99a23a4f6417b10e5ab1256a179264561540e/contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69", upload-time = "2025-07-26T12:01:35.64Z" }, + { url = "https://files.pythonhosted.org/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b", upload-time = "2025-07-26T12:01:36.804Z" }, + { url = "https://files.pythonhosted.org/packages/d1/e2/f05240d2c39a1ed228d8328a78b6f44cd695f7ef47beb3e684cf93604f86/contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc", upload-time = "2025-07-26T12:01:37.999Z" }, ] [[package]] name = "coverage" version = "7.13.5" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/9d/e0/70553e3000e345daff267cec284ce4cbf3fc141b6da229ac52775b5428f1/coverage-7.13.5.tar.gz", hash = "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179", upload-time = "2026-03-17T10:33:18.341Z" } -wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/a0/c3/a396306ba7db865bf96fc1fb3b7fd29bcbf3d829df642e77b13555163cd6/coverage-7.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:460cf0114c5016fa841214ff5564aa4864f11948da9440bc97e21ad1f4ba1e01", upload-time = "2026-03-17T10:30:42.208Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/a6/16/a68a19e5384e93f811dccc51034b1fd0b865841c390e3c931dcc4699e035/coverage-7.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e223ce4b4ed47f065bfb123687686512e37629be25cc63728557ae7db261422", upload-time = "2026-03-17T10:30:43.906Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/29/72/20b917c6793af3a5ceb7fb9c50033f3ec7865f2911a1416b34a7cfa0813b/coverage-7.13.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6e3370441f4513c6252bf042b9c36d22491142385049243253c7e48398a15a9f", upload-time = "2026-03-17T10:30:45.545Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/8c/49/cd14b789536ac6a4778c453c6a2338bc0a2fb60c5a5a41b4008328b9acc1/coverage-7.13.5-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:03ccc709a17a1de074fb1d11f217342fb0d2b1582ed544f554fc9fc3f07e95f5", upload-time = "2026-03-17T10:30:47.204Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/9d/00/7b0edcfe64e2ed4c0340dac14a52ad0f4c9bd0b8b5e531af7d55b703db7c/coverage-7.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3f4818d065964db3c1c66dc0fbdac5ac692ecbc875555e13374fdbe7eedb4376", upload-time = "2026-03-17T10:30:48.812Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/93/89/7ffc4ba0f5d0a55c1e84ea7cee39c9fc06af7b170513d83fbf3bbefce280/coverage-7.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:012d5319e66e9d5a218834642d6c35d265515a62f01157a45bcc036ecf947256", upload-time = "2026-03-17T10:30:50.77Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/81/bd/73ddf85f93f7e6fa83e77ccecb6162d9415c79007b4bc124008a4995e4a7/coverage-7.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8dd02af98971bdb956363e4827d34425cb3df19ee550ef92855b0acb9c7ce51c", upload-time = "2026-03-17T10:30:52.5Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/a0/81/278aff4e8dec4926a0bcb9486320752811f543a3ce5b602cc7a29978d073/coverage-7.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f08fd75c50a760c7eb068ae823777268daaf16a80b918fa58eea888f8e3919f5", upload-time = "2026-03-17T10:30:54.543Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/70/ee/fe1621488e2e0a58d7e94c4800f0d96f79671553488d401a612bebae324b/coverage-7.13.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:843ea8643cf967d1ac7e8ecd4bb00c99135adf4816c0c0593fdcc47b597fcf09", upload-time = "2026-03-17T10:30:56.663Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/37/a6/f79fb37aa104b562207cc23cb5711ab6793608e246cae1e93f26b2236ed9/coverage-7.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:9d44d7aa963820b1b971dbecd90bfe5fe8f81cff79787eb6cca15750bd2f79b9", upload-time = "2026-03-17T10:30:58.427Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/75/f0/ed15262a58ec81ce457ceb717b7f78752a1713556b19081b76e90896e8d4/coverage-7.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7132bed4bd7b836200c591410ae7d97bf7ae8be6fc87d160b2bd881df929e7bf", upload-time = "2026-03-17T10:31:00.093Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/0f/e9/9129958f20e7e9d4d56d51d42ccf708d15cac355ff4ac6e736e97a9393d2/coverage-7.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a698e363641b98843c517817db75373c83254781426e94ada3197cabbc2c919c", upload-time = "2026-03-17T10:31:01.916Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/a4/d7/0ad9b15812d81272db94379fe4c6df8fd17781cc7671fdfa30c76ba5ff7b/coverage-7.13.5-cp312-cp312-win32.whl", hash = "sha256:bdba0a6b8812e8c7df002d908a9a2ea3c36e92611b5708633c50869e6d922fdf", upload-time = "2026-03-17T10:31:03.642Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/29/3d/821a9a5799fac2556bcf0bd37a70d1d11fa9e49784b6d22e92e8b2f85f18/coverage-7.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:d2c87e0c473a10bffe991502eac389220533024c8082ec1ce849f4218dded810", upload-time = "2026-03-17T10:31:05.651Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/d4/fa/2238c2ad08e35cf4f020ea721f717e09ec3152aea75d191a7faf3ef009a8/coverage-7.13.5-cp312-cp312-win_arm64.whl", hash = "sha256:bf69236a9a81bdca3bff53796237aab096cdbf8d78a66ad61e992d9dac7eb2de", upload-time = "2026-03-17T10:31:07.293Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/9e/ee/a4cf96b8ce1e566ed238f0659ac2d3f007ed1d14b181bcb684e19561a69a/coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61", upload-time = "2026-03-17T10:33:15.691Z" }, +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/e0/70553e3000e345daff267cec284ce4cbf3fc141b6da229ac52775b5428f1/coverage-7.13.5.tar.gz", hash = "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179", upload-time = "2026-03-17T10:33:18.341Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/c3/a396306ba7db865bf96fc1fb3b7fd29bcbf3d829df642e77b13555163cd6/coverage-7.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:460cf0114c5016fa841214ff5564aa4864f11948da9440bc97e21ad1f4ba1e01", upload-time = "2026-03-17T10:30:42.208Z" }, + { url = "https://files.pythonhosted.org/packages/a6/16/a68a19e5384e93f811dccc51034b1fd0b865841c390e3c931dcc4699e035/coverage-7.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e223ce4b4ed47f065bfb123687686512e37629be25cc63728557ae7db261422", upload-time = "2026-03-17T10:30:43.906Z" }, + { url = "https://files.pythonhosted.org/packages/29/72/20b917c6793af3a5ceb7fb9c50033f3ec7865f2911a1416b34a7cfa0813b/coverage-7.13.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6e3370441f4513c6252bf042b9c36d22491142385049243253c7e48398a15a9f", upload-time = "2026-03-17T10:30:45.545Z" }, + { url = "https://files.pythonhosted.org/packages/8c/49/cd14b789536ac6a4778c453c6a2338bc0a2fb60c5a5a41b4008328b9acc1/coverage-7.13.5-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:03ccc709a17a1de074fb1d11f217342fb0d2b1582ed544f554fc9fc3f07e95f5", upload-time = "2026-03-17T10:30:47.204Z" }, + { url = "https://files.pythonhosted.org/packages/9d/00/7b0edcfe64e2ed4c0340dac14a52ad0f4c9bd0b8b5e531af7d55b703db7c/coverage-7.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3f4818d065964db3c1c66dc0fbdac5ac692ecbc875555e13374fdbe7eedb4376", upload-time = "2026-03-17T10:30:48.812Z" }, + { url = "https://files.pythonhosted.org/packages/93/89/7ffc4ba0f5d0a55c1e84ea7cee39c9fc06af7b170513d83fbf3bbefce280/coverage-7.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:012d5319e66e9d5a218834642d6c35d265515a62f01157a45bcc036ecf947256", upload-time = "2026-03-17T10:30:50.77Z" }, + { url = "https://files.pythonhosted.org/packages/81/bd/73ddf85f93f7e6fa83e77ccecb6162d9415c79007b4bc124008a4995e4a7/coverage-7.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8dd02af98971bdb956363e4827d34425cb3df19ee550ef92855b0acb9c7ce51c", upload-time = "2026-03-17T10:30:52.5Z" }, + { url = "https://files.pythonhosted.org/packages/a0/81/278aff4e8dec4926a0bcb9486320752811f543a3ce5b602cc7a29978d073/coverage-7.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f08fd75c50a760c7eb068ae823777268daaf16a80b918fa58eea888f8e3919f5", upload-time = "2026-03-17T10:30:54.543Z" }, + { url = "https://files.pythonhosted.org/packages/70/ee/fe1621488e2e0a58d7e94c4800f0d96f79671553488d401a612bebae324b/coverage-7.13.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:843ea8643cf967d1ac7e8ecd4bb00c99135adf4816c0c0593fdcc47b597fcf09", upload-time = "2026-03-17T10:30:56.663Z" }, + { url = "https://files.pythonhosted.org/packages/37/a6/f79fb37aa104b562207cc23cb5711ab6793608e246cae1e93f26b2236ed9/coverage-7.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:9d44d7aa963820b1b971dbecd90bfe5fe8f81cff79787eb6cca15750bd2f79b9", upload-time = "2026-03-17T10:30:58.427Z" }, + { url = "https://files.pythonhosted.org/packages/75/f0/ed15262a58ec81ce457ceb717b7f78752a1713556b19081b76e90896e8d4/coverage-7.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7132bed4bd7b836200c591410ae7d97bf7ae8be6fc87d160b2bd881df929e7bf", upload-time = "2026-03-17T10:31:00.093Z" }, + { url = "https://files.pythonhosted.org/packages/0f/e9/9129958f20e7e9d4d56d51d42ccf708d15cac355ff4ac6e736e97a9393d2/coverage-7.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a698e363641b98843c517817db75373c83254781426e94ada3197cabbc2c919c", upload-time = "2026-03-17T10:31:01.916Z" }, + { url = "https://files.pythonhosted.org/packages/a4/d7/0ad9b15812d81272db94379fe4c6df8fd17781cc7671fdfa30c76ba5ff7b/coverage-7.13.5-cp312-cp312-win32.whl", hash = "sha256:bdba0a6b8812e8c7df002d908a9a2ea3c36e92611b5708633c50869e6d922fdf", upload-time = "2026-03-17T10:31:03.642Z" }, + { url = "https://files.pythonhosted.org/packages/29/3d/821a9a5799fac2556bcf0bd37a70d1d11fa9e49784b6d22e92e8b2f85f18/coverage-7.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:d2c87e0c473a10bffe991502eac389220533024c8082ec1ce849f4218dded810", upload-time = "2026-03-17T10:31:05.651Z" }, + { url = "https://files.pythonhosted.org/packages/d4/fa/2238c2ad08e35cf4f020ea721f717e09ec3152aea75d191a7faf3ef009a8/coverage-7.13.5-cp312-cp312-win_arm64.whl", hash = "sha256:bf69236a9a81bdca3bff53796237aab096cdbf8d78a66ad61e992d9dac7eb2de", upload-time = "2026-03-17T10:31:07.293Z" }, + { url = "https://files.pythonhosted.org/packages/9e/ee/a4cf96b8ce1e566ed238f0659ac2d3f007ed1d14b181bcb684e19561a69a/coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61", upload-time = "2026-03-17T10:33:15.691Z" }, ] [[package]] name = "cryptography" version = "47.0.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/ef/b2/7ffa7fe8207a8c42147ffe70c3e360b228160c1d85dc3faff16aaa3244c0/cryptography-47.0.0.tar.gz", hash = "sha256:9f8e55fe4e63613a5e1cc5819030f27b97742d720203a087802ce4ce9ceb52bb", upload-time = "2026-04-24T19:54:57.056Z" } -wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/a4/98/40dfe932134bdcae4f6ab5927c87488754bf9eb79297d7e0070b78dd58e9/cryptography-47.0.0-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:160ad728f128972d362e714054f6ba0067cab7fb350c5202a9ae8ae4ce3ef1a0", upload-time = "2026-04-24T19:53:03.864Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/34/c6/2733531243fba725f58611b918056b277692f1033373dcc8bd01af1c05d4/cryptography-47.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b9a8943e359b7615db1a3ba587994618e094ff3d6fa5a390c73d079ce18b3973", upload-time = "2026-04-24T19:53:06.909Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/00/e3/b27be1a670a9b87f855d211cf0e1174a5d721216b7616bd52d8581d912ed/cryptography-47.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f5c15764f261394b22aef6b00252f5195f46f2ca300bec57149474e2538b31f8", upload-time = "2026-04-24T19:53:09.053Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/81/b9/8443cfe5d17d482d348cee7048acf502bb89a51b6382f06240fd290d4ca3/cryptography-47.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9c59ab0e0fa3a180a5a9c59f3a5abe3ef90d474bc56d7fadfbe80359491b615b", upload-time = "2026-04-24T19:53:11.217Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/5d/5e/13ed0cdd0eb88ba159d6dd5ebfece8cb901dbcf1ae5ac4072e28b55d3153/cryptography-47.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:34b4358b925a5ea3e14384ca781a2c0ef7ac219b57bb9eacc4457078e2b19f92", upload-time = "2026-04-24T19:53:13.532Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/64/16/ed058e1df0f33d440217cd120d41d5dda9dd215a80b8187f68483185af82/cryptography-47.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0024b87d47ae2399165a6bfb20d24888881eeab83ae2566d62467c5ff0030ce7", upload-time = "2026-04-24T19:53:15.618Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/02/e0/3d30986b30fdbd9e969abbdf8ba00ed0618615144341faeb57f395a084fe/cryptography-47.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:1e47422b5557bb82d3fff997e8d92cff4e28b9789576984f08c248d2b3535d93", upload-time = "2026-04-24T19:53:17.755Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/df/fd/32db38e3ad0cb331f0691cb4c7a8a6f176f679124dee746b3af6633db4d9/cryptography-47.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:6f29f36582e6151d9686235e586dd35bb67491f024767d10b842e520dc6a07ac", upload-time = "2026-04-24T19:53:20.062Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/86/53/5395d944dfd48cb1f67917f533c609c34347185ef15eb4308024c876f274/cryptography-47.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:a9b761f012a943b7de0e828843c5688d0de94a0578d44d6c85a1bae32f87791f", upload-time = "2026-04-24T19:53:22.498Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/34/4f/e5711b28e1901f7d480a2b1b688b645aa4c77c73f10731ed17e7f7db3f0d/cryptography-47.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4e1de79e047e25d6e9f8cea71c86b4a53aced64134f0f003bbcbf3655fd172c8", upload-time = "2026-04-24T19:53:24.356Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/22/22/c8ddc25de3010fc8da447648f5a092c40e7a8fadf01dd6d255d9c0b9373d/cryptography-47.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef6b3634087f18d2155b1e8ce264e5345a753da2c5fa9815e7d41315c90f8318", upload-time = "2026-04-24T19:53:26.665Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/66/b6/d4a68f4ea999c6d89e8498579cba1c5fcba4276284de7773b17e4fa69293/cryptography-47.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:11dbb9f50a0f1bb9757b3d8c27c1101780efb8f0bdecfb12439c22a74d64c001", upload-time = "2026-04-24T19:53:28.686Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/54/ed/5f524db1fade9c013aa618e1c99c6ed05e8ffc9ceee6cda22fed22dda3f4/cryptography-47.0.0-cp311-abi3-win32.whl", hash = "sha256:7fda2f02c9015db3f42bb8a22324a454516ed10a8c29ca6ece6cdbb5efe2a203", upload-time = "2026-04-24T19:53:31.058Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/b2/dc/1b901990b174786569029f67542b3edf72ac068b6c3c8683c17e6a2f5363/cryptography-47.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:f5c3296dab66202f1b18a91fa266be93d6aa0c2806ea3d67762c69f60adc71aa", upload-time = "2026-04-24T19:53:33.054Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:14432c8a9bcb37009784f9594a62fae211a2ae9543e96c92b2a8e4c3cd5cd0c4", upload-time = "2026-04-24T19:54:06.411Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/01/64/d7b1e54fdb69f22d24a64bb3e88dc718b31c7fb10ef0b9691a3cf7eeea6e/cryptography-47.0.0-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:07efe86201817e7d3c18781ca9770bc0db04e1e48c994be384e4602bc38f8f27", upload-time = "2026-04-24T19:54:08.519Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/8b/7b/cca826391fb2a94efdcdfe4631eb69306ee1cff0b22f664a412c90713877/cryptography-47.0.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2b45761c6ec22b7c726d6a829558777e32d0f1c8be7c3f3480f9c912d5ee8a10", upload-time = "2026-04-24T19:54:10.795Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/4c/65/4b57bcc823f42a991627c51c2f68c9fd6eb1393c1756aac876cba2accae2/cryptography-47.0.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:edd4da498015da5b9f26d38d3bfc2e90257bfa9cbed1f6767c282a0025ae649b", upload-time = "2026-04-24T19:54:13.275Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/f4/c4/2c5fbeea70adbbca2bbae865e1d605d6a4a7f8dbd9d33eaf69645087f06c/cryptography-47.0.0-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:9af828c0d5a65c70ec729cd7495a4bf1a67ecb66417b8f02ff125ab8a6326a74", upload-time = "2026-04-24T19:54:15.18Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/7e/b8/ac57107ef32749d2b244e36069bb688792a363aaaa3acc9e3cf84c130315/cryptography-47.0.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:256d07c78a04d6b276f5df935a9923275f53bd1522f214447fdf365494e2d515", upload-time = "2026-04-24T19:54:17.835Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/56/fc/9f1de22ff8be99d991f240a46863c52d475404c408886c5a38d2b5c3bb26/cryptography-47.0.0-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:5d0e362ff51041b0c0d219cc7d6924d7b8996f57ce5712bdcef71eb3c65a59cc", upload-time = "2026-04-24T19:54:19.963Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/00/68/d70c852797aa68e8e48d12e5a87170c43f67bb4a59403627259dd57d15de/cryptography-47.0.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:1581aef4219f7ca2849d0250edaa3866212fb74bf5667284f46aa92f9e65c1ca", upload-time = "2026-04-24T19:54:21.818Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/a5/51/661cbee74f594c5d97ff82d34f10d5551c085ca4668645f4606ebd22bd5d/cryptography-47.0.0-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:a49a3eb5341b9503fa3000a9a0db033161db90d47285291f53c2a9d2cd1b7f76", upload-time = "2026-04-24T19:54:24.376Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/94/87/f2b6c374a82cf076cfa1416992ac8e8ec94d79facc37aec87c1a5cb72352/cryptography-47.0.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:2207a498b03275d0051589e326b79d4cf59985c99031b05bb292ac52631c37fe", upload-time = "2026-04-24T19:54:26.946Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/14/e2/8b7462f4acf21ec509616f0245018bb197194ab0b65c2ea21a0bdd53c0eb/cryptography-47.0.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7a02675e2fabd0c0fc04c868b8781863cbf1967691543c22f5470500ff840b31", upload-time = "2026-04-24T19:54:28.926Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/70/75/158e494e4c08dc05e039da5bb48553826bd26c23930cf8d3cd5f21fa8921/cryptography-47.0.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80887c5cbd1774683cb126f0ab4184567f080071d5acf62205acb354b4b753b7", upload-time = "2026-04-24T19:54:30.869Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/06/bd/0a9d3edbf5eadbac926d7b9b3cd0c4be584eeeae4a003d24d9eda4affbbd/cryptography-47.0.0-cp38-abi3-win32.whl", hash = "sha256:ed67ea4e0cfb5faa5bc7ecb6e2b8838f3807a03758eec239d6c21c8769355310", upload-time = "2026-04-24T19:54:33.494Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/60/80/5681af756d0da3a599b7bdb586fac5a1540f1bcefd2717a20e611ddade45/cryptography-47.0.0-cp38-abi3-win_amd64.whl", hash = "sha256:835d2d7f47cdc53b3224e90810fb1d36ca94ea29cc1801fb4c1bc43876735769", upload-time = "2026-04-24T19:54:35.408Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/ef/b2/7ffa7fe8207a8c42147ffe70c3e360b228160c1d85dc3faff16aaa3244c0/cryptography-47.0.0.tar.gz", hash = "sha256:9f8e55fe4e63613a5e1cc5819030f27b97742d720203a087802ce4ce9ceb52bb", upload-time = "2026-04-24T19:54:57.056Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/98/40dfe932134bdcae4f6ab5927c87488754bf9eb79297d7e0070b78dd58e9/cryptography-47.0.0-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:160ad728f128972d362e714054f6ba0067cab7fb350c5202a9ae8ae4ce3ef1a0", upload-time = "2026-04-24T19:53:03.864Z" }, + { url = "https://files.pythonhosted.org/packages/34/c6/2733531243fba725f58611b918056b277692f1033373dcc8bd01af1c05d4/cryptography-47.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b9a8943e359b7615db1a3ba587994618e094ff3d6fa5a390c73d079ce18b3973", upload-time = "2026-04-24T19:53:06.909Z" }, + { url = "https://files.pythonhosted.org/packages/00/e3/b27be1a670a9b87f855d211cf0e1174a5d721216b7616bd52d8581d912ed/cryptography-47.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f5c15764f261394b22aef6b00252f5195f46f2ca300bec57149474e2538b31f8", upload-time = "2026-04-24T19:53:09.053Z" }, + { url = "https://files.pythonhosted.org/packages/81/b9/8443cfe5d17d482d348cee7048acf502bb89a51b6382f06240fd290d4ca3/cryptography-47.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9c59ab0e0fa3a180a5a9c59f3a5abe3ef90d474bc56d7fadfbe80359491b615b", upload-time = "2026-04-24T19:53:11.217Z" }, + { url = "https://files.pythonhosted.org/packages/5d/5e/13ed0cdd0eb88ba159d6dd5ebfece8cb901dbcf1ae5ac4072e28b55d3153/cryptography-47.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:34b4358b925a5ea3e14384ca781a2c0ef7ac219b57bb9eacc4457078e2b19f92", upload-time = "2026-04-24T19:53:13.532Z" }, + { url = "https://files.pythonhosted.org/packages/64/16/ed058e1df0f33d440217cd120d41d5dda9dd215a80b8187f68483185af82/cryptography-47.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0024b87d47ae2399165a6bfb20d24888881eeab83ae2566d62467c5ff0030ce7", upload-time = "2026-04-24T19:53:15.618Z" }, + { url = "https://files.pythonhosted.org/packages/02/e0/3d30986b30fdbd9e969abbdf8ba00ed0618615144341faeb57f395a084fe/cryptography-47.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:1e47422b5557bb82d3fff997e8d92cff4e28b9789576984f08c248d2b3535d93", upload-time = "2026-04-24T19:53:17.755Z" }, + { url = "https://files.pythonhosted.org/packages/df/fd/32db38e3ad0cb331f0691cb4c7a8a6f176f679124dee746b3af6633db4d9/cryptography-47.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:6f29f36582e6151d9686235e586dd35bb67491f024767d10b842e520dc6a07ac", upload-time = "2026-04-24T19:53:20.062Z" }, + { url = "https://files.pythonhosted.org/packages/86/53/5395d944dfd48cb1f67917f533c609c34347185ef15eb4308024c876f274/cryptography-47.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:a9b761f012a943b7de0e828843c5688d0de94a0578d44d6c85a1bae32f87791f", upload-time = "2026-04-24T19:53:22.498Z" }, + { url = "https://files.pythonhosted.org/packages/34/4f/e5711b28e1901f7d480a2b1b688b645aa4c77c73f10731ed17e7f7db3f0d/cryptography-47.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4e1de79e047e25d6e9f8cea71c86b4a53aced64134f0f003bbcbf3655fd172c8", upload-time = "2026-04-24T19:53:24.356Z" }, + { url = "https://files.pythonhosted.org/packages/22/22/c8ddc25de3010fc8da447648f5a092c40e7a8fadf01dd6d255d9c0b9373d/cryptography-47.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef6b3634087f18d2155b1e8ce264e5345a753da2c5fa9815e7d41315c90f8318", upload-time = "2026-04-24T19:53:26.665Z" }, + { url = "https://files.pythonhosted.org/packages/66/b6/d4a68f4ea999c6d89e8498579cba1c5fcba4276284de7773b17e4fa69293/cryptography-47.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:11dbb9f50a0f1bb9757b3d8c27c1101780efb8f0bdecfb12439c22a74d64c001", upload-time = "2026-04-24T19:53:28.686Z" }, + { url = "https://files.pythonhosted.org/packages/54/ed/5f524db1fade9c013aa618e1c99c6ed05e8ffc9ceee6cda22fed22dda3f4/cryptography-47.0.0-cp311-abi3-win32.whl", hash = "sha256:7fda2f02c9015db3f42bb8a22324a454516ed10a8c29ca6ece6cdbb5efe2a203", upload-time = "2026-04-24T19:53:31.058Z" }, + { url = "https://files.pythonhosted.org/packages/b2/dc/1b901990b174786569029f67542b3edf72ac068b6c3c8683c17e6a2f5363/cryptography-47.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:f5c3296dab66202f1b18a91fa266be93d6aa0c2806ea3d67762c69f60adc71aa", upload-time = "2026-04-24T19:53:33.054Z" }, + { url = "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:14432c8a9bcb37009784f9594a62fae211a2ae9543e96c92b2a8e4c3cd5cd0c4", upload-time = "2026-04-24T19:54:06.411Z" }, + { url = "https://files.pythonhosted.org/packages/01/64/d7b1e54fdb69f22d24a64bb3e88dc718b31c7fb10ef0b9691a3cf7eeea6e/cryptography-47.0.0-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:07efe86201817e7d3c18781ca9770bc0db04e1e48c994be384e4602bc38f8f27", upload-time = "2026-04-24T19:54:08.519Z" }, + { url = "https://files.pythonhosted.org/packages/8b/7b/cca826391fb2a94efdcdfe4631eb69306ee1cff0b22f664a412c90713877/cryptography-47.0.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2b45761c6ec22b7c726d6a829558777e32d0f1c8be7c3f3480f9c912d5ee8a10", upload-time = "2026-04-24T19:54:10.795Z" }, + { url = "https://files.pythonhosted.org/packages/4c/65/4b57bcc823f42a991627c51c2f68c9fd6eb1393c1756aac876cba2accae2/cryptography-47.0.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:edd4da498015da5b9f26d38d3bfc2e90257bfa9cbed1f6767c282a0025ae649b", upload-time = "2026-04-24T19:54:13.275Z" }, + { url = "https://files.pythonhosted.org/packages/f4/c4/2c5fbeea70adbbca2bbae865e1d605d6a4a7f8dbd9d33eaf69645087f06c/cryptography-47.0.0-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:9af828c0d5a65c70ec729cd7495a4bf1a67ecb66417b8f02ff125ab8a6326a74", upload-time = "2026-04-24T19:54:15.18Z" }, + { url = "https://files.pythonhosted.org/packages/7e/b8/ac57107ef32749d2b244e36069bb688792a363aaaa3acc9e3cf84c130315/cryptography-47.0.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:256d07c78a04d6b276f5df935a9923275f53bd1522f214447fdf365494e2d515", upload-time = "2026-04-24T19:54:17.835Z" }, + { url = "https://files.pythonhosted.org/packages/56/fc/9f1de22ff8be99d991f240a46863c52d475404c408886c5a38d2b5c3bb26/cryptography-47.0.0-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:5d0e362ff51041b0c0d219cc7d6924d7b8996f57ce5712bdcef71eb3c65a59cc", upload-time = "2026-04-24T19:54:19.963Z" }, + { url = "https://files.pythonhosted.org/packages/00/68/d70c852797aa68e8e48d12e5a87170c43f67bb4a59403627259dd57d15de/cryptography-47.0.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:1581aef4219f7ca2849d0250edaa3866212fb74bf5667284f46aa92f9e65c1ca", upload-time = "2026-04-24T19:54:21.818Z" }, + { url = "https://files.pythonhosted.org/packages/a5/51/661cbee74f594c5d97ff82d34f10d5551c085ca4668645f4606ebd22bd5d/cryptography-47.0.0-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:a49a3eb5341b9503fa3000a9a0db033161db90d47285291f53c2a9d2cd1b7f76", upload-time = "2026-04-24T19:54:24.376Z" }, + { url = "https://files.pythonhosted.org/packages/94/87/f2b6c374a82cf076cfa1416992ac8e8ec94d79facc37aec87c1a5cb72352/cryptography-47.0.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:2207a498b03275d0051589e326b79d4cf59985c99031b05bb292ac52631c37fe", upload-time = "2026-04-24T19:54:26.946Z" }, + { url = "https://files.pythonhosted.org/packages/14/e2/8b7462f4acf21ec509616f0245018bb197194ab0b65c2ea21a0bdd53c0eb/cryptography-47.0.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7a02675e2fabd0c0fc04c868b8781863cbf1967691543c22f5470500ff840b31", upload-time = "2026-04-24T19:54:28.926Z" }, + { url = "https://files.pythonhosted.org/packages/70/75/158e494e4c08dc05e039da5bb48553826bd26c23930cf8d3cd5f21fa8921/cryptography-47.0.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80887c5cbd1774683cb126f0ab4184567f080071d5acf62205acb354b4b753b7", upload-time = "2026-04-24T19:54:30.869Z" }, + { url = "https://files.pythonhosted.org/packages/06/bd/0a9d3edbf5eadbac926d7b9b3cd0c4be584eeeae4a003d24d9eda4affbbd/cryptography-47.0.0-cp38-abi3-win32.whl", hash = "sha256:ed67ea4e0cfb5faa5bc7ecb6e2b8838f3807a03758eec239d6c21c8769355310", upload-time = "2026-04-24T19:54:33.494Z" }, + { url = "https://files.pythonhosted.org/packages/60/80/5681af756d0da3a599b7bdb586fac5a1540f1bcefd2717a20e611ddade45/cryptography-47.0.0-cp38-abi3-win_amd64.whl", hash = "sha256:835d2d7f47cdc53b3224e90810fb1d36ca94ea29cc1801fb4c1bc43876735769", upload-time = "2026-04-24T19:54:35.408Z" }, ] [[package]] name = "cycler" version = "0.12.1" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", upload-time = "2023-10-07T05:32:18.335Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", upload-time = "2023-10-07T05:32:18.335Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", upload-time = "2023-10-07T05:32:16.783Z" }, + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", upload-time = "2023-10-07T05:32:16.783Z" }, ] [[package]] name = "databind" version = "4.5.4" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "deprecated" }, { name = "nr-date" }, @@ -274,33 +274,33 @@ dependencies = [ { name = "typeapi" }, { name = "typing-extensions" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/71/9e/835a5211eeb7228a0e3870d54def48dd7951dbd951f51b30900020a5f9fc/databind-4.5.4.tar.gz", hash = "sha256:342e170a219b1661e5c1b20778b532aecfa67e46560ba75beb7e2c6faa2150b5", upload-time = "2026-04-02T22:21:47.318Z" } +sdist = { url = "https://files.pythonhosted.org/packages/71/9e/835a5211eeb7228a0e3870d54def48dd7951dbd951f51b30900020a5f9fc/databind-4.5.4.tar.gz", hash = "sha256:342e170a219b1661e5c1b20778b532aecfa67e46560ba75beb7e2c6faa2150b5", upload-time = "2026-04-02T22:21:47.318Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/e2/db/3b8eb860b5baef89b72c7aadcc5072e1648ca0c98d6ba4b9e4eabbdc2cf5/databind-4.5.4-py3-none-any.whl", hash = "sha256:78467f874a3e80bcd1d3de349167587a0d369831bc64c03798520be86074f96e", upload-time = "2026-04-02T22:21:45.389Z" }, + { url = "https://files.pythonhosted.org/packages/e2/db/3b8eb860b5baef89b72c7aadcc5072e1648ca0c98d6ba4b9e4eabbdc2cf5/databind-4.5.4-py3-none-any.whl", hash = "sha256:78467f874a3e80bcd1d3de349167587a0d369831bc64c03798520be86074f96e", upload-time = "2026-04-02T22:21:45.389Z" }, ] [[package]] name = "databind-core" version = "4.5.4" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "databind" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/9e/dc/b63a6f6a404146e8e3f1226c9243a5cb30784a1f75218d014cafce9a411f/databind_core-4.5.4.tar.gz", hash = "sha256:a7a47af183d4a8046c893fc19fa9c085f287a15e57a05e58345016086ce0f807", upload-time = "2026-04-02T22:21:56.588Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9e/dc/b63a6f6a404146e8e3f1226c9243a5cb30784a1f75218d014cafce9a411f/databind_core-4.5.4.tar.gz", hash = "sha256:a7a47af183d4a8046c893fc19fa9c085f287a15e57a05e58345016086ce0f807", upload-time = "2026-04-02T22:21:56.588Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/fa/cf/1d1f4d37b4112f26ea5086d54200837d1dcbddaa536f3a70bb1d8b48ed9a/databind_core-4.5.4-py3-none-any.whl", hash = "sha256:25482c352f4f6fcade7c106c665553a18febeccda2972c00cf5af19f473960ab", upload-time = "2026-04-02T22:21:55.504Z" }, + { url = "https://files.pythonhosted.org/packages/fa/cf/1d1f4d37b4112f26ea5086d54200837d1dcbddaa536f3a70bb1d8b48ed9a/databind_core-4.5.4-py3-none-any.whl", hash = "sha256:25482c352f4f6fcade7c106c665553a18febeccda2972c00cf5af19f473960ab", upload-time = "2026-04-02T22:21:55.504Z" }, ] [[package]] name = "databind-json" version = "4.5.4" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "databind" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/ab/72/9af59950a23ff6a03062acd85879de289595168ec43d6cec57253d00497c/databind_json-4.5.4.tar.gz", hash = "sha256:2c714f9c3039a81e42fc3826e47d7826ef020d93131c34daf4c9ae0483108e4d", upload-time = "2026-04-02T22:22:05.538Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ab/72/9af59950a23ff6a03062acd85879de289595168ec43d6cec57253d00497c/databind_json-4.5.4.tar.gz", hash = "sha256:2c714f9c3039a81e42fc3826e47d7826ef020d93131c34daf4c9ae0483108e4d", upload-time = "2026-04-02T22:22:05.538Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/b3/d4/e00d531202314e29d90c9496f6b4730e3647128b9866180b8ce8ebb79394/databind_json-4.5.4-py3-none-any.whl", hash = "sha256:22e6faaeb6f2ec5cf815fd597a539dfe1f4846b80b618760112f4fe59a0898cc", upload-time = "2026-04-02T22:22:04.204Z" }, + { url = "https://files.pythonhosted.org/packages/b3/d4/e00d531202314e29d90c9496f6b4730e3647128b9866180b8ce8ebb79394/databind_json-4.5.4-py3-none-any.whl", hash = "sha256:22e6faaeb6f2ec5cf815fd597a539dfe1f4846b80b618760112f4fe59a0898cc", upload-time = "2026-04-02T22:22:04.204Z" }, ] [[package]] @@ -371,279 +371,279 @@ test = [{ name = "asammdf", specifier = "==8.0.1" }] [[package]] name = "databricks-sdk" version = "0.106.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-auth" }, { name = "protobuf" }, { name = "requests" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/b5/b7/ef86e7b8c3d135c844f972e06efb628e147eed0a7b9a0ecbf9511437a3c2/databricks_sdk-0.106.0.tar.gz", hash = "sha256:6bbd492cb8593747aced037b9186f8632e9d553fc358e6f3d83b7e959851d9d3", upload-time = "2026-04-30T12:33:19.601Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/b7/ef86e7b8c3d135c844f972e06efb628e147eed0a7b9a0ecbf9511437a3c2/databricks_sdk-0.106.0.tar.gz", hash = "sha256:6bbd492cb8593747aced037b9186f8632e9d553fc358e6f3d83b7e959851d9d3", upload-time = "2026-04-30T12:33:19.601Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/07/a9/63b4f6ef3078e4d060faaad85c4e43667189c3429edd68d5cbddc45187ca/databricks_sdk-0.106.0-py3-none-any.whl", hash = "sha256:db9de5566279ae80dfea0ecd37231e8968523ef984e83cbe4bd77e50c59aa6a5", upload-time = "2026-04-30T12:33:18.116Z" }, + { url = "https://files.pythonhosted.org/packages/07/a9/63b4f6ef3078e4d060faaad85c4e43667189c3429edd68d5cbddc45187ca/databricks_sdk-0.106.0-py3-none-any.whl", hash = "sha256:db9de5566279ae80dfea0ecd37231e8968523ef984e83cbe4bd77e50c59aa6a5", upload-time = "2026-04-30T12:33:18.116Z" }, ] [[package]] name = "delta-spark" version = "4.0.1" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "importlib-metadata" }, { name = "pyspark" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/8f/4d/9670c5b109fb1c7a84814525cb116203cc36a6112eca546785d617f41a08/delta_spark-4.0.1.tar.gz", hash = "sha256:066512d723f615c9a900e1aa4d83bbc7d0f27a1703e1d5dc52606ea51b8733cc", upload-time = "2026-01-10T02:40:50.315Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8f/4d/9670c5b109fb1c7a84814525cb116203cc36a6112eca546785d617f41a08/delta_spark-4.0.1.tar.gz", hash = "sha256:066512d723f615c9a900e1aa4d83bbc7d0f27a1703e1d5dc52606ea51b8733cc", upload-time = "2026-01-10T02:40:50.315Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/13/22/a3716bc5ea86786be5f0afd09f62b20e6a111fa2d78868e930b19367a88c/delta_spark-4.0.1-py3-none-any.whl", hash = "sha256:ae0707eda68f05c6ec20b841c8966bb1201d1a5f124d9e94e8c2232162139be8", upload-time = "2026-01-10T02:40:49.047Z" }, + { url = "https://files.pythonhosted.org/packages/13/22/a3716bc5ea86786be5f0afd09f62b20e6a111fa2d78868e930b19367a88c/delta_spark-4.0.1-py3-none-any.whl", hash = "sha256:ae0707eda68f05c6ec20b841c8966bb1201d1a5f124d9e94e8c2232162139be8", upload-time = "2026-01-10T02:40:49.047Z" }, ] [[package]] name = "deprecated" version = "1.3.1" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wrapt" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", upload-time = "2025-10-30T08:19:02.757Z" } +sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", upload-time = "2025-10-30T08:19:02.757Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", upload-time = "2025-10-30T08:19:00.758Z" }, + { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", upload-time = "2025-10-30T08:19:00.758Z" }, ] [[package]] name = "distlib" version = "0.4.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", upload-time = "2025-07-17T16:52:00.465Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", upload-time = "2025-07-17T16:52:00.465Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", upload-time = "2025-07-17T16:51:58.613Z" }, + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", upload-time = "2025-07-17T16:51:58.613Z" }, ] [[package]] name = "docspec" version = "2.2.1" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "databind-core" }, { name = "databind-json" }, { name = "deprecated" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/3c/39/7a71382107445b2cd50c67c6194e3e584f19748a817c3b29e8be8a14f00f/docspec-2.2.1.tar.gz", hash = "sha256:4854e77edc0e2de40e785e57e95880f7095a05fe978f8b54cef7a269586e15ff", upload-time = "2023-05-28T11:24:18.68Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3c/39/7a71382107445b2cd50c67c6194e3e584f19748a817c3b29e8be8a14f00f/docspec-2.2.1.tar.gz", hash = "sha256:4854e77edc0e2de40e785e57e95880f7095a05fe978f8b54cef7a269586e15ff", upload-time = "2023-05-28T11:24:18.68Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/33/aa/0c9d71cc9d450afd3993d09835e2910810a45b0703f585e1aee1d9b78969/docspec-2.2.1-py3-none-any.whl", hash = "sha256:7538f750095a9688c6980ff9a4e029a823a500f64bd00b6b4bdb27951feb31cb", upload-time = "2023-05-28T11:24:15.419Z" }, + { url = "https://files.pythonhosted.org/packages/33/aa/0c9d71cc9d450afd3993d09835e2910810a45b0703f585e1aee1d9b78969/docspec-2.2.1-py3-none-any.whl", hash = "sha256:7538f750095a9688c6980ff9a4e029a823a500f64bd00b6b4bdb27951feb31cb", upload-time = "2023-05-28T11:24:15.419Z" }, ] [[package]] name = "docspec-python" version = "2.2.2" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "black" }, { name = "docspec" }, { name = "nr-util" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/ea/ea/e6d9d9c2f805c6ac8072d0e3ee5b1da2dd61886c662327df937dec9f282c/docspec_python-2.2.2.tar.gz", hash = "sha256:429be834d09549461b95bf45eb53c16859f3dfb3e9220408b3bfb12812ccb3fb", upload-time = "2025-05-06T12:40:33.286Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ea/ea/e6d9d9c2f805c6ac8072d0e3ee5b1da2dd61886c662327df937dec9f282c/docspec_python-2.2.2.tar.gz", hash = "sha256:429be834d09549461b95bf45eb53c16859f3dfb3e9220408b3bfb12812ccb3fb", upload-time = "2025-05-06T12:40:33.286Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/03/c2/b3226746fb6b91893da270a60e77bb420d59cf33a7b9a4e719a236955971/docspec_python-2.2.2-py3-none-any.whl", hash = "sha256:caa32dc1e8c470af8a5ecad67cca614e68c1563ac01dab0c0486c4d7f709d6b1", upload-time = "2025-05-06T12:40:31.554Z" }, + { url = "https://files.pythonhosted.org/packages/03/c2/b3226746fb6b91893da270a60e77bb420d59cf33a7b9a4e719a236955971/docspec_python-2.2.2-py3-none-any.whl", hash = "sha256:caa32dc1e8c470af8a5ecad67cca614e68c1563ac01dab0c0486c4d7f709d6b1", upload-time = "2025-05-06T12:40:31.554Z" }, ] [[package]] name = "docstring-parser" version = "0.11" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/a2/ce/5d6a3782b9f88097ce3e579265015db3372ae78d12f67629b863a9208c96/docstring_parser-0.11.tar.gz", hash = "sha256:93b3f8f481c7d24e37c5d9f30293c89e2933fa209421c8abd731dd3ef0715ecb", upload-time = "2021-09-30T07:44:10.288Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/ce/5d6a3782b9f88097ce3e579265015db3372ae78d12f67629b863a9208c96/docstring_parser-0.11.tar.gz", hash = "sha256:93b3f8f481c7d24e37c5d9f30293c89e2933fa209421c8abd731dd3ef0715ecb", upload-time = "2021-09-30T07:44:10.288Z" } [[package]] name = "filelock" version = "3.29.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/b5/fe/997687a931ab51049acce6fa1f23e8f01216374ea81374ddee763c493db5/filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90", upload-time = "2026-04-19T15:39:10.068Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/fe/997687a931ab51049acce6fa1f23e8f01216374ea81374ddee763c493db5/filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90", upload-time = "2026-04-19T15:39:10.068Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258", upload-time = "2026-04-19T15:39:08.752Z" }, + { url = "https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258", upload-time = "2026-04-19T15:39:08.752Z" }, ] [[package]] name = "fonttools" version = "4.62.1" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/9a/08/7012b00a9a5874311b639c3920270c36ee0c445b69d9989a85e5c92ebcb0/fonttools-4.62.1.tar.gz", hash = "sha256:e54c75fd6041f1122476776880f7c3c3295ffa31962dc6ebe2543c00dca58b5d", upload-time = "2026-03-13T13:54:25.52Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/08/7012b00a9a5874311b639c3920270c36ee0c445b69d9989a85e5c92ebcb0/fonttools-4.62.1.tar.gz", hash = "sha256:e54c75fd6041f1122476776880f7c3c3295ffa31962dc6ebe2543c00dca58b5d", upload-time = "2026-03-13T13:54:25.52Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/47/d4/dbacced3953544b9a93088cc10ef2b596d348c983d5c67a404fa41ec51ba/fonttools-4.62.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:90365821debbd7db678809c7491ca4acd1e0779b9624cdc6ddaf1f31992bf974", upload-time = "2026-03-13T13:52:53.664Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/66/9e/a769c8e99b81e5a87ab7e5e7236684de4e96246aae17274e5347d11ebd78/fonttools-4.62.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12859ff0b47dd20f110804c3e0d0970f7b832f561630cd879969011541a464a9", upload-time = "2026-03-13T13:52:56.493Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/69/64/f19a9e3911968c37e1e620e14dfc5778299e1474f72f4e57c5ec771d9489/fonttools-4.62.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c125ffa00c3d9003cdaaf7f2c79e6e535628093e14b5de1dccb08859b680936", upload-time = "2026-03-13T13:52:59.179Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/9b/8a/99c8b3c3888c5c474c08dbfd7c8899786de9604b727fcefb055b42c84bba/fonttools-4.62.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:149f7d84afca659d1a97e39a4778794a2f83bf344c5ee5134e09995086cc2392", upload-time = "2026-03-13T13:53:02.761Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/d1/c6/0f904540d3e6ab463c1243a0d803504826a11604c72dd58c2949796a1762/fonttools-4.62.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0aa72c43a601cfa9273bb1ae0518f1acadc01ee181a6fc60cd758d7fdadffc04", upload-time = "2026-03-13T13:53:05.678Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/29/0b/5cbef6588dc9bd6b5c9ad6a4d5a8ca384d0cea089da31711bbeb4f9654a6/fonttools-4.62.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:19177c8d96c7c36359266e571c5173bcee9157b59cfc8cb0153c5673dc5a3a7d", upload-time = "2026-03-13T13:53:08.662Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/4a/47/b3a5342d381595ef439adec67848bed561ab7fdb1019fa522e82101b7d9c/fonttools-4.62.1-cp312-cp312-win32.whl", hash = "sha256:a24decd24d60744ee8b4679d38e88b8303d86772053afc29b19d23bb8207803c", upload-time = "2026-03-13T13:53:10.998Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/28/b1/0c2ab56a16f409c6c8a68816e6af707827ad5d629634691ff60a52879792/fonttools-4.62.1-cp312-cp312-win_amd64.whl", hash = "sha256:9e7863e10b3de72376280b515d35b14f5eeed639d1aa7824f4cf06779ec65e42", upload-time = "2026-03-13T13:53:13.992Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/fd/ba/56147c165442cc5ba7e82ecf301c9a68353cede498185869e6e02b4c264f/fonttools-4.62.1-py3-none-any.whl", hash = "sha256:7487782e2113861f4ddcc07c3436450659e3caa5e470b27dc2177cade2d8e7fd", upload-time = "2026-03-13T13:54:22.735Z" }, + { url = "https://files.pythonhosted.org/packages/47/d4/dbacced3953544b9a93088cc10ef2b596d348c983d5c67a404fa41ec51ba/fonttools-4.62.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:90365821debbd7db678809c7491ca4acd1e0779b9624cdc6ddaf1f31992bf974", upload-time = "2026-03-13T13:52:53.664Z" }, + { url = "https://files.pythonhosted.org/packages/66/9e/a769c8e99b81e5a87ab7e5e7236684de4e96246aae17274e5347d11ebd78/fonttools-4.62.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12859ff0b47dd20f110804c3e0d0970f7b832f561630cd879969011541a464a9", upload-time = "2026-03-13T13:52:56.493Z" }, + { url = "https://files.pythonhosted.org/packages/69/64/f19a9e3911968c37e1e620e14dfc5778299e1474f72f4e57c5ec771d9489/fonttools-4.62.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c125ffa00c3d9003cdaaf7f2c79e6e535628093e14b5de1dccb08859b680936", upload-time = "2026-03-13T13:52:59.179Z" }, + { url = "https://files.pythonhosted.org/packages/9b/8a/99c8b3c3888c5c474c08dbfd7c8899786de9604b727fcefb055b42c84bba/fonttools-4.62.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:149f7d84afca659d1a97e39a4778794a2f83bf344c5ee5134e09995086cc2392", upload-time = "2026-03-13T13:53:02.761Z" }, + { url = "https://files.pythonhosted.org/packages/d1/c6/0f904540d3e6ab463c1243a0d803504826a11604c72dd58c2949796a1762/fonttools-4.62.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0aa72c43a601cfa9273bb1ae0518f1acadc01ee181a6fc60cd758d7fdadffc04", upload-time = "2026-03-13T13:53:05.678Z" }, + { url = "https://files.pythonhosted.org/packages/29/0b/5cbef6588dc9bd6b5c9ad6a4d5a8ca384d0cea089da31711bbeb4f9654a6/fonttools-4.62.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:19177c8d96c7c36359266e571c5173bcee9157b59cfc8cb0153c5673dc5a3a7d", upload-time = "2026-03-13T13:53:08.662Z" }, + { url = "https://files.pythonhosted.org/packages/4a/47/b3a5342d381595ef439adec67848bed561ab7fdb1019fa522e82101b7d9c/fonttools-4.62.1-cp312-cp312-win32.whl", hash = "sha256:a24decd24d60744ee8b4679d38e88b8303d86772053afc29b19d23bb8207803c", upload-time = "2026-03-13T13:53:10.998Z" }, + { url = "https://files.pythonhosted.org/packages/28/b1/0c2ab56a16f409c6c8a68816e6af707827ad5d629634691ff60a52879792/fonttools-4.62.1-cp312-cp312-win_amd64.whl", hash = "sha256:9e7863e10b3de72376280b515d35b14f5eeed639d1aa7824f4cf06779ec65e42", upload-time = "2026-03-13T13:53:13.992Z" }, + { url = "https://files.pythonhosted.org/packages/fd/ba/56147c165442cc5ba7e82ecf301c9a68353cede498185869e6e02b4c264f/fonttools-4.62.1-py3-none-any.whl", hash = "sha256:7487782e2113861f4ddcc07c3436450659e3caa5e470b27dc2177cade2d8e7fd", upload-time = "2026-03-13T13:54:22.735Z" }, ] [[package]] name = "google-auth" version = "2.49.2" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, { name = "pyasn1-modules" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/c6/fc/e925290a1ad95c975c459e2df070fac2b90954e13a0370ac505dff78cb99/google_auth-2.49.2.tar.gz", hash = "sha256:c1ae38500e73065dcae57355adb6278cf8b5c8e391994ae9cbadbcb9631ab409", upload-time = "2026-04-10T00:41:21.888Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c6/fc/e925290a1ad95c975c459e2df070fac2b90954e13a0370ac505dff78cb99/google_auth-2.49.2.tar.gz", hash = "sha256:c1ae38500e73065dcae57355adb6278cf8b5c8e391994ae9cbadbcb9631ab409", upload-time = "2026-04-10T00:41:21.888Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/73/76/d241a5c927433420507215df6cac1b1fa4ac0ba7a794df42a84326c68da8/google_auth-2.49.2-py3-none-any.whl", hash = "sha256:c2720924dfc82dedb962c9f52cabb2ab16714fd0a6a707e40561d217574ed6d5", upload-time = "2026-04-10T00:41:14.501Z" }, + { url = "https://files.pythonhosted.org/packages/73/76/d241a5c927433420507215df6cac1b1fa4ac0ba7a794df42a84326c68da8/google_auth-2.49.2-py3-none-any.whl", hash = "sha256:c2720924dfc82dedb962c9f52cabb2ab16714fd0a6a707e40561d217574ed6d5", upload-time = "2026-04-10T00:41:14.501Z" }, ] [[package]] name = "identify" version = "2.6.19" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/52/63/51723b5f116cc04b061cb6f5a561790abf249d25931d515cd375e063e0f4/identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842", upload-time = "2026-04-17T18:39:50.265Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/52/63/51723b5f116cc04b061cb6f5a561790abf249d25931d515cd375e063e0f4/identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842", upload-time = "2026-04-17T18:39:50.265Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a", upload-time = "2026-04-17T18:39:49.221Z" }, + { url = "https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a", upload-time = "2026-04-17T18:39:49.221Z" }, ] [[package]] name = "idna" version = "3.13" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/ce/cc/762dfb036166873f0059f3b7de4565e1b5bc3d6f28a414c13da27e442f99/idna-3.13.tar.gz", hash = "sha256:585ea8fe5d69b9181ec1afba340451fba6ba764af97026f92a91d4eef164a242", upload-time = "2026-04-22T16:42:42.314Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ce/cc/762dfb036166873f0059f3b7de4565e1b5bc3d6f28a414c13da27e442f99/idna-3.13.tar.gz", hash = "sha256:585ea8fe5d69b9181ec1afba340451fba6ba764af97026f92a91d4eef164a242", upload-time = "2026-04-22T16:42:42.314Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/5d/13/ad7d7ca3808a898b4612b6fe93cde56b53f3034dcde235acb1f0e1df24c6/idna-3.13-py3-none-any.whl", hash = "sha256:892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3", upload-time = "2026-04-22T16:42:40.909Z" }, + { url = "https://files.pythonhosted.org/packages/5d/13/ad7d7ca3808a898b4612b6fe93cde56b53f3034dcde235acb1f0e1df24c6/idna-3.13-py3-none-any.whl", hash = "sha256:892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3", upload-time = "2026-04-22T16:42:40.909Z" }, ] [[package]] name = "importlib-metadata" version = "9.0.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "zipp" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/a9/01/15bb152d77b21318514a96f43af312635eb2500c96b55398d020c93d86ea/importlib_metadata-9.0.0.tar.gz", hash = "sha256:a4f57ab599e6a2e3016d7595cfd72eb4661a5106e787a95bcc90c7105b831efc", upload-time = "2026-03-20T06:42:56.999Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/01/15bb152d77b21318514a96f43af312635eb2500c96b55398d020c93d86ea/importlib_metadata-9.0.0.tar.gz", hash = "sha256:a4f57ab599e6a2e3016d7595cfd72eb4661a5106e787a95bcc90c7105b831efc", upload-time = "2026-03-20T06:42:56.999Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl", hash = "sha256:2d21d1cc5a017bd0559e36150c21c830ab1dc304dedd1b7ea85d20f45ef3edd7", upload-time = "2026-03-20T06:42:55.665Z" }, + { url = "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl", hash = "sha256:2d21d1cc5a017bd0559e36150c21c830ab1dc304dedd1b7ea85d20f45ef3edd7", upload-time = "2026-03-20T06:42:55.665Z" }, ] [[package]] name = "iniconfig" version = "2.3.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", upload-time = "2025-10-18T21:55:43.219Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", upload-time = "2025-10-18T21:55:43.219Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", upload-time = "2025-10-18T21:55:41.639Z" }, + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", upload-time = "2025-10-18T21:55:41.639Z" }, ] [[package]] name = "isal" version = "1.8.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/9c/35/40ff3eabd401036f792cf55ba9cd19dcd5e3cb79aa5798332885ab0ff1b9/isal-1.8.0.tar.gz", hash = "sha256:124233e9a31a62030a07aafd48c26689561926f4e10417ed3ea46c211218f2b4", upload-time = "2025-09-10T08:47:12.653Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9c/35/40ff3eabd401036f792cf55ba9cd19dcd5e3cb79aa5798332885ab0ff1b9/isal-1.8.0.tar.gz", hash = "sha256:124233e9a31a62030a07aafd48c26689561926f4e10417ed3ea46c211218f2b4", upload-time = "2025-09-10T08:47:12.653Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/58/6f/e170e758293712e4f7ac1d0cf92290a80816d0eea8eb0871d82877ca7372/isal-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3255b5dd6ac0238d410a6d630761e3826d4360400e88d6106e8ad85fe9042966", upload-time = "2025-09-10T08:47:31.57Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/29/92/c10343738c170c31a5e25f0a1d024f8160ec107c5a2935a1a07587821100/isal-1.8.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3c28ff61f2f300e498ea0f50cb1528d8c14631fce4cdfce191ed05775952de3", upload-time = "2025-09-10T08:47:01.294Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/9f/72/5cbc30d59821bcf93be44eab758ca999794fbd6e47b67954193d11e92000/isal-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ce55960f53603145d35188ca6363848b79675d81c95a3ff2cfb4b2cb806873e", upload-time = "2025-09-10T08:47:02.178Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/63/a0/3cdaac7caab7e5e2660afbf03d16616f8c3fb91ec3b75596e2388d42b90b/isal-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d376b7644434d50fedfb670483150ece64082212b6e1f23976f92a91fa1b99b", upload-time = "2025-09-10T08:49:15.206Z" }, + { url = "https://files.pythonhosted.org/packages/58/6f/e170e758293712e4f7ac1d0cf92290a80816d0eea8eb0871d82877ca7372/isal-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3255b5dd6ac0238d410a6d630761e3826d4360400e88d6106e8ad85fe9042966", upload-time = "2025-09-10T08:47:31.57Z" }, + { url = "https://files.pythonhosted.org/packages/29/92/c10343738c170c31a5e25f0a1d024f8160ec107c5a2935a1a07587821100/isal-1.8.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3c28ff61f2f300e498ea0f50cb1528d8c14631fce4cdfce191ed05775952de3", upload-time = "2025-09-10T08:47:01.294Z" }, + { url = "https://files.pythonhosted.org/packages/9f/72/5cbc30d59821bcf93be44eab758ca999794fbd6e47b67954193d11e92000/isal-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ce55960f53603145d35188ca6363848b79675d81c95a3ff2cfb4b2cb806873e", upload-time = "2025-09-10T08:47:02.178Z" }, + { url = "https://files.pythonhosted.org/packages/63/a0/3cdaac7caab7e5e2660afbf03d16616f8c3fb91ec3b75596e2388d42b90b/isal-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d376b7644434d50fedfb670483150ece64082212b6e1f23976f92a91fa1b99b", upload-time = "2025-09-10T08:49:15.206Z" }, ] [[package]] name = "jinja2" version = "3.1.6" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", upload-time = "2025-03-05T20:05:02.478Z" } +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", upload-time = "2025-03-05T20:05:02.478Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", upload-time = "2025-03-05T20:05:00.369Z" }, + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", upload-time = "2025-03-05T20:05:00.369Z" }, ] [[package]] name = "kiwisolver" version = "1.5.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/d0/67/9c61eccb13f0bdca9307614e782fec49ffdde0f7a2314935d489fa93cd9c/kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a", upload-time = "2026-03-09T13:15:53.382Z" } -wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/4d/b2/818b74ebea34dabe6d0c51cb1c572e046730e64844da6ed646d5298c40ce/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4e9750bc21b886308024f8a54ccb9a2cc38ac9fa813bf4348434e3d54f337ff9", upload-time = "2026-03-09T13:13:23.127Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/bf/d9/405320f8077e8e1c5c4bd6adc45e1e6edf6d727b6da7f2e2533cf58bff71/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72ec46b7eba5b395e0a7b63025490d3214c11013f4aacb4f5e8d6c3041829588", upload-time = "2026-03-09T13:13:24.765Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/99/9f/795fedf35634f746151ca8839d05681ceb6287fbed6cc1c9bf235f7887c2/kiwisolver-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ed3a984b31da7481b103f68776f7128a89ef26ed40f4dc41a2223cda7fb24819", upload-time = "2026-03-09T13:13:25.878Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/c4/13/680c54afe3e65767bed7ec1a15571e1a2f1257128733851ade24abcefbcc/kiwisolver-1.5.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb5136fb5352d3f422df33f0c879a1b0c204004324150cc3b5e3c4f310c9049f", upload-time = "2026-03-09T13:13:27.166Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/c8/2f/cebfcdb60fd6a9b0f6b47a9337198bcbad6fbe15e68189b7011fd914911f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2af221f268f5af85e776a73d62b0845fc8baf8ef0abfae79d29c77d0e776aaf", upload-time = "2026-03-09T13:13:28.707Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/f2/0d/9b782923aada3fafb1d6b84e13121954515c669b18af0c26e7d21f579855/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b0f172dc8ffaccb8522d7c5d899de00133f2f1ca7b0a49b7da98e901de87bf2d", upload-time = "2026-03-09T13:13:30.528Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/27/70/83241b6634b04fe44e892688d5208332bde130f38e610c0418f9ede47ded/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6ab8ba9152203feec73758dad83af9a0bbe05001eb4639e547207c40cfb52083", upload-time = "2026-03-09T13:13:32.818Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/e4/db/30ed226fb271ae1a6431fc0fe0edffb2efe23cadb01e798caeb9f2ceae8f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:cdee07c4d7f6d72008d3f73b9bf027f4e11550224c7c50d8df1ae4a37c1402a6", upload-time = "2026-03-09T13:13:34.435Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/ec/bd/c314595208e4c9587652d50959ead9e461995389664e490f4dce7ff0f782/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7c60d3c9b06fb23bd9c6139281ccbdc384297579ae037f08ae90c69f6845c0b1", upload-time = "2026-03-09T13:13:36.4Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/c1/43/0499cec932d935229b5543d073c2b87c9c22846aab48881e9d8d6e742a2d/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e315e5ec90d88e140f57696ff85b484ff68bb311e36f2c414aa4286293e6dee0", upload-time = "2026-03-09T13:13:38.204Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/3d/6f/79b0d760907965acfd9d61826a3d41f8f093c538f55cd2633d3f0db269f6/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:1465387ac63576c3e125e5337a6892b9e99e0627d52317f3ca79e6930d889d15", upload-time = "2026-03-09T13:13:39.966Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/ab/31/01d0537c41cb75a551a438c3c7a80d0c60d60b81f694dac83dd436aec0d0/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:530a3fd64c87cffa844d4b6b9768774763d9caa299e9b75d8eca6a4423b31314", upload-time = "2026-03-09T13:13:41.698Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/e4/34/8aefdd0be9cfd00a44509251ba864f5caf2991e36772e61c408007e7f417/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1d9daea4ea6b9be74fe2f01f7fbade8d6ffab263e781274cffca0dba9be9eec9", upload-time = "2026-03-09T13:13:43.343Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/ad/cf/0348374369ca588f8fe9c338fae49fa4e16eeb10ffb3d012f23a54578a9e/kiwisolver-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:f18c2d9782259a6dc132fdc7a63c168cbc74b35284b6d75c673958982a378384", upload-time = "2026-03-09T13:13:45.792Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/28/26/192b26196e2316e2bd29deef67e37cdf9870d9af8e085e521afff0fed526/kiwisolver-1.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:f7c7553b13f69c1b29a5bde08ddc6d9d0c8bfb84f9ed01c30db25944aeb852a7", upload-time = "2026-03-09T13:13:46.878Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/1c/fa/2910df836372d8761bb6eff7d8bdcb1613b5c2e03f260efe7abe34d388a7/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_10_13_x86_64.whl", hash = "sha256:5ae8e62c147495b01a0f4765c878e9bfdf843412446a247e28df59936e99e797", upload-time = "2026-03-09T13:15:35.629Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/0f/41/c5f71f9f00aabcc71fee8b7475e3f64747282580c2fe748961ba29b18385/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f6764a4ccab3078db14a632420930f6186058750df066b8ea2a7106df91d3203", upload-time = "2026-03-09T13:15:36.894Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/fa/06/7399a607f434119c6e1fdc8ec89a8d51ccccadf3341dee4ead6bd14caaf5/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c31c13da98624f957b0fb1b5bae5383b2333c2c3f6793d9825dd5ce79b525cb7", upload-time = "2026-03-09T13:15:38.22Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/b5/91/53255615acd2a1eaca307ede3c90eb550bae9c94581f8c00081b6b1c8f44/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-win_amd64.whl", hash = "sha256:1f1489f769582498610e015a8ef2d36f28f505ab3096d0e16b4858a9ec214f57", upload-time = "2026-03-09T13:15:39.65Z" }, +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/67/9c61eccb13f0bdca9307614e782fec49ffdde0f7a2314935d489fa93cd9c/kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a", upload-time = "2026-03-09T13:15:53.382Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/b2/818b74ebea34dabe6d0c51cb1c572e046730e64844da6ed646d5298c40ce/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4e9750bc21b886308024f8a54ccb9a2cc38ac9fa813bf4348434e3d54f337ff9", upload-time = "2026-03-09T13:13:23.127Z" }, + { url = "https://files.pythonhosted.org/packages/bf/d9/405320f8077e8e1c5c4bd6adc45e1e6edf6d727b6da7f2e2533cf58bff71/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72ec46b7eba5b395e0a7b63025490d3214c11013f4aacb4f5e8d6c3041829588", upload-time = "2026-03-09T13:13:24.765Z" }, + { url = "https://files.pythonhosted.org/packages/99/9f/795fedf35634f746151ca8839d05681ceb6287fbed6cc1c9bf235f7887c2/kiwisolver-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ed3a984b31da7481b103f68776f7128a89ef26ed40f4dc41a2223cda7fb24819", upload-time = "2026-03-09T13:13:25.878Z" }, + { url = "https://files.pythonhosted.org/packages/c4/13/680c54afe3e65767bed7ec1a15571e1a2f1257128733851ade24abcefbcc/kiwisolver-1.5.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb5136fb5352d3f422df33f0c879a1b0c204004324150cc3b5e3c4f310c9049f", upload-time = "2026-03-09T13:13:27.166Z" }, + { url = "https://files.pythonhosted.org/packages/c8/2f/cebfcdb60fd6a9b0f6b47a9337198bcbad6fbe15e68189b7011fd914911f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2af221f268f5af85e776a73d62b0845fc8baf8ef0abfae79d29c77d0e776aaf", upload-time = "2026-03-09T13:13:28.707Z" }, + { url = "https://files.pythonhosted.org/packages/f2/0d/9b782923aada3fafb1d6b84e13121954515c669b18af0c26e7d21f579855/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b0f172dc8ffaccb8522d7c5d899de00133f2f1ca7b0a49b7da98e901de87bf2d", upload-time = "2026-03-09T13:13:30.528Z" }, + { url = "https://files.pythonhosted.org/packages/27/70/83241b6634b04fe44e892688d5208332bde130f38e610c0418f9ede47ded/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6ab8ba9152203feec73758dad83af9a0bbe05001eb4639e547207c40cfb52083", upload-time = "2026-03-09T13:13:32.818Z" }, + { url = "https://files.pythonhosted.org/packages/e4/db/30ed226fb271ae1a6431fc0fe0edffb2efe23cadb01e798caeb9f2ceae8f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:cdee07c4d7f6d72008d3f73b9bf027f4e11550224c7c50d8df1ae4a37c1402a6", upload-time = "2026-03-09T13:13:34.435Z" }, + { url = "https://files.pythonhosted.org/packages/ec/bd/c314595208e4c9587652d50959ead9e461995389664e490f4dce7ff0f782/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7c60d3c9b06fb23bd9c6139281ccbdc384297579ae037f08ae90c69f6845c0b1", upload-time = "2026-03-09T13:13:36.4Z" }, + { url = "https://files.pythonhosted.org/packages/c1/43/0499cec932d935229b5543d073c2b87c9c22846aab48881e9d8d6e742a2d/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e315e5ec90d88e140f57696ff85b484ff68bb311e36f2c414aa4286293e6dee0", upload-time = "2026-03-09T13:13:38.204Z" }, + { url = "https://files.pythonhosted.org/packages/3d/6f/79b0d760907965acfd9d61826a3d41f8f093c538f55cd2633d3f0db269f6/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:1465387ac63576c3e125e5337a6892b9e99e0627d52317f3ca79e6930d889d15", upload-time = "2026-03-09T13:13:39.966Z" }, + { url = "https://files.pythonhosted.org/packages/ab/31/01d0537c41cb75a551a438c3c7a80d0c60d60b81f694dac83dd436aec0d0/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:530a3fd64c87cffa844d4b6b9768774763d9caa299e9b75d8eca6a4423b31314", upload-time = "2026-03-09T13:13:41.698Z" }, + { url = "https://files.pythonhosted.org/packages/e4/34/8aefdd0be9cfd00a44509251ba864f5caf2991e36772e61c408007e7f417/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1d9daea4ea6b9be74fe2f01f7fbade8d6ffab263e781274cffca0dba9be9eec9", upload-time = "2026-03-09T13:13:43.343Z" }, + { url = "https://files.pythonhosted.org/packages/ad/cf/0348374369ca588f8fe9c338fae49fa4e16eeb10ffb3d012f23a54578a9e/kiwisolver-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:f18c2d9782259a6dc132fdc7a63c168cbc74b35284b6d75c673958982a378384", upload-time = "2026-03-09T13:13:45.792Z" }, + { url = "https://files.pythonhosted.org/packages/28/26/192b26196e2316e2bd29deef67e37cdf9870d9af8e085e521afff0fed526/kiwisolver-1.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:f7c7553b13f69c1b29a5bde08ddc6d9d0c8bfb84f9ed01c30db25944aeb852a7", upload-time = "2026-03-09T13:13:46.878Z" }, + { url = "https://files.pythonhosted.org/packages/1c/fa/2910df836372d8761bb6eff7d8bdcb1613b5c2e03f260efe7abe34d388a7/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_10_13_x86_64.whl", hash = "sha256:5ae8e62c147495b01a0f4765c878e9bfdf843412446a247e28df59936e99e797", upload-time = "2026-03-09T13:15:35.629Z" }, + { url = "https://files.pythonhosted.org/packages/0f/41/c5f71f9f00aabcc71fee8b7475e3f64747282580c2fe748961ba29b18385/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f6764a4ccab3078db14a632420930f6186058750df066b8ea2a7106df91d3203", upload-time = "2026-03-09T13:15:36.894Z" }, + { url = "https://files.pythonhosted.org/packages/fa/06/7399a607f434119c6e1fdc8ec89a8d51ccccadf3341dee4ead6bd14caaf5/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c31c13da98624f957b0fb1b5bae5383b2333c2c3f6793d9825dd5ce79b525cb7", upload-time = "2026-03-09T13:15:38.22Z" }, + { url = "https://files.pythonhosted.org/packages/b5/91/53255615acd2a1eaca307ede3c90eb550bae9c94581f8c00081b6b1c8f44/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-win_amd64.whl", hash = "sha256:1f1489f769582498610e015a8ef2d36f28f505ab3096d0e16b4858a9ec214f57", upload-time = "2026-03-09T13:15:39.65Z" }, ] [[package]] name = "lxml" version = "6.1.1" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/05/3b/aab6728cae887456f409b4d75e8a01856e4f04bd510de38052a47768b680/lxml-6.1.1.tar.gz", hash = "sha256:ba96ae44888e0185281e937633a743ea90d5a196c6000f82565ebb0580012d40", upload-time = "2026-05-18T19:19:06.424Z" } -wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/6a/6e/c4add832b6fc1e887125b96f880d7b9b70aae5248718e046b1704bcac4b9/lxml-6.1.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:104c09bda8d2a562824c0e319d0768ce26a779b7601e0931d33b09b53c392ef7", upload-time = "2026-05-18T19:17:42.068Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/22/00/ff3009c88e65de8011630acf8ab5a09cb2becd2aaf47fba2f3449f6224e9/lxml-6.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:25c6997a9a534e016695a0ba06b2f07945de682731ff01065b6d5a4474179da1", upload-time = "2026-05-18T19:17:47.897Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/42/95/bb63f0fd62e554fe078e1fb3c8fe9083c14ddc7ad7fa178d10e57e071ac7/lxml-6.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c921ba5c51e4e9f63b8b00267d06566e1f63407408a0496da2d1d0bfc819c7fc", upload-time = "2026-05-18T19:18:29.637Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/eb/99/0013e8d9b5960f4f041cf0b73e2f80c23eb5205b1f7bfb20203243651359/lxml-6.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:54a7f95e4de5fb94e2f9f4b9055c6ba33bf3d628fd77a1d647c5923caa2cdcdc", upload-time = "2026-05-18T19:18:34.168Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/29/91/317b332636bfc7bddcff828d41b3307f50043f4b237e40849c333d80fa1a/lxml-6.1.1-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f2ec43df44b1f76249ee0a615334f9b5b060e1c8bd90e706dad2d14d02f383", upload-time = "2026-05-18T19:18:39.798Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/42/2f/cc9bf06afe70f9c9093ae60855d9759da9db601ec4080f7473319666ffd7/lxml-6.1.1-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:70ef8a7e102a1508f8121aae5b0867abd663f72c14f0a9c937e6554cb4587b7b", upload-time = "2026-05-18T19:18:44.858Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/08/f6/af32e23e563971ffb0fb86be52bc5be5c2c118858ffc119bf6a9039b173d/lxml-6.1.1-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ebe6af670449830d6d9b752c256a983291c766a1365ba5d5460048f9e33a7818", upload-time = "2026-05-18T19:18:49.217Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/78/83/8555d40948b09ce86f1bd0c68a7ac31d07b1929f92cc1b074006c97ef2d2/lxml-6.1.1-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:27acc820660aaffa4f7c087f29120e12980f7779d56d8492d263170111284740", upload-time = "2026-05-18T19:18:52.779Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/63/75/5d92da93729b7bad783689e6496049fa40927b45bec7bf183c981de3ca70/lxml-6.1.1-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:1db753c9115ec7100d073b744d17e25e88a8f90f5c39b2f5dd878149af59671f", upload-time = "2026-05-18T19:18:55.139Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/c5/b5/3aad415a9a25b822e783f15deeb4dffccf5113030f1afa2222dd929313d9/lxml-6.1.1-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c4f469aebd783bb741c2ecb2a681008fd26bfe5c16a9a72ed5467f834e810df2", upload-time = "2026-05-18T19:19:01.28Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/f1/a1/5fcf7eb9904b80086aa47dcf0027de07b1bb990afad2e6823144c368ae04/lxml-6.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:766b010012d59470072c1816b5b6c69f1d243e5db36ea5968e94accf430a4635", upload-time = "2026-05-18T19:18:12.67Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/77/74/1f601b63c7a69fcdf10fa9b148c81da8442204194f6c55509cc485c786b9/lxml-6.1.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b8d812c6011c08b8111a15e54dd990b8923692d80adf35488bee34026c35accf", upload-time = "2026-05-18T19:18:15.928Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/a2/b9/7a78f51aec95b1bf780d78e12705a9f6533284f8693dc5c0e6724fa53d3f/lxml-6.1.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:fe0306bd29505a9177aac19f1877174b0e7422c222a59f70b2cd41633448c3dc", upload-time = "2026-05-18T19:18:23.223Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/a5/6e/98a7b7ad54e4e74fa1f20fff776913980619d0ebe5558232d7da6580bdd8/lxml-6.1.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:5ba186ad207446c65d3bb3d3e0412b032b1d9f595e59861e2354798c5703d955", upload-time = "2026-05-18T19:18:31.433Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/65/d1/bc0ed2427bf609f2ee10da303a6a226f9c8bce94f945dc29a32ce55de6e4/lxml-6.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aa366a1e55b8ebfe8ca8ddc3cfe75c8ebade181aeb0f661d0cb05986b647f72a", upload-time = "2026-05-18T19:18:37.091Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/69/8b/6772e1a4b513fc50a8d931f19edde0e13ae6918510a1e13ff67864f3e5ed/lxml-6.1.1-cp312-cp312-win32.whl", hash = "sha256:126c93f7f56f0eda92f6d8c619edc463a4f23d9252f1c9d0405a76f25fa9f11a", upload-time = "2026-05-18T19:17:18.37Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/1b/89/45198e9624762af2dfd2cb8782598477ceb29f6e59caab560388ae1f4ec1/lxml-6.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:26e6eda8d38c1fcab1090dd196ee87cbd13788e531937610e2589085de074e77", upload-time = "2026-05-18T19:17:56.781Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/90/a9/7a54b6834088d9ae528a7b780584ba6a39a9457b0ac330479f20ffbc9449/lxml-6.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:6540377fbd53fe1b629172288c464fb18db11ce1fa7dc15891da10aa9dcc3e7f", upload-time = "2026-05-19T19:22:50.843Z" }, +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/3b/aab6728cae887456f409b4d75e8a01856e4f04bd510de38052a47768b680/lxml-6.1.1.tar.gz", hash = "sha256:ba96ae44888e0185281e937633a743ea90d5a196c6000f82565ebb0580012d40", upload-time = "2026-05-18T19:19:06.424Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/6e/c4add832b6fc1e887125b96f880d7b9b70aae5248718e046b1704bcac4b9/lxml-6.1.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:104c09bda8d2a562824c0e319d0768ce26a779b7601e0931d33b09b53c392ef7", upload-time = "2026-05-18T19:17:42.068Z" }, + { url = "https://files.pythonhosted.org/packages/22/00/ff3009c88e65de8011630acf8ab5a09cb2becd2aaf47fba2f3449f6224e9/lxml-6.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:25c6997a9a534e016695a0ba06b2f07945de682731ff01065b6d5a4474179da1", upload-time = "2026-05-18T19:17:47.897Z" }, + { url = "https://files.pythonhosted.org/packages/42/95/bb63f0fd62e554fe078e1fb3c8fe9083c14ddc7ad7fa178d10e57e071ac7/lxml-6.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c921ba5c51e4e9f63b8b00267d06566e1f63407408a0496da2d1d0bfc819c7fc", upload-time = "2026-05-18T19:18:29.637Z" }, + { url = "https://files.pythonhosted.org/packages/eb/99/0013e8d9b5960f4f041cf0b73e2f80c23eb5205b1f7bfb20203243651359/lxml-6.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:54a7f95e4de5fb94e2f9f4b9055c6ba33bf3d628fd77a1d647c5923caa2cdcdc", upload-time = "2026-05-18T19:18:34.168Z" }, + { url = "https://files.pythonhosted.org/packages/29/91/317b332636bfc7bddcff828d41b3307f50043f4b237e40849c333d80fa1a/lxml-6.1.1-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f2ec43df44b1f76249ee0a615334f9b5b060e1c8bd90e706dad2d14d02f383", upload-time = "2026-05-18T19:18:39.798Z" }, + { url = "https://files.pythonhosted.org/packages/42/2f/cc9bf06afe70f9c9093ae60855d9759da9db601ec4080f7473319666ffd7/lxml-6.1.1-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:70ef8a7e102a1508f8121aae5b0867abd663f72c14f0a9c937e6554cb4587b7b", upload-time = "2026-05-18T19:18:44.858Z" }, + { url = "https://files.pythonhosted.org/packages/08/f6/af32e23e563971ffb0fb86be52bc5be5c2c118858ffc119bf6a9039b173d/lxml-6.1.1-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ebe6af670449830d6d9b752c256a983291c766a1365ba5d5460048f9e33a7818", upload-time = "2026-05-18T19:18:49.217Z" }, + { url = "https://files.pythonhosted.org/packages/78/83/8555d40948b09ce86f1bd0c68a7ac31d07b1929f92cc1b074006c97ef2d2/lxml-6.1.1-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:27acc820660aaffa4f7c087f29120e12980f7779d56d8492d263170111284740", upload-time = "2026-05-18T19:18:52.779Z" }, + { url = "https://files.pythonhosted.org/packages/63/75/5d92da93729b7bad783689e6496049fa40927b45bec7bf183c981de3ca70/lxml-6.1.1-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:1db753c9115ec7100d073b744d17e25e88a8f90f5c39b2f5dd878149af59671f", upload-time = "2026-05-18T19:18:55.139Z" }, + { url = "https://files.pythonhosted.org/packages/c5/b5/3aad415a9a25b822e783f15deeb4dffccf5113030f1afa2222dd929313d9/lxml-6.1.1-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c4f469aebd783bb741c2ecb2a681008fd26bfe5c16a9a72ed5467f834e810df2", upload-time = "2026-05-18T19:19:01.28Z" }, + { url = "https://files.pythonhosted.org/packages/f1/a1/5fcf7eb9904b80086aa47dcf0027de07b1bb990afad2e6823144c368ae04/lxml-6.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:766b010012d59470072c1816b5b6c69f1d243e5db36ea5968e94accf430a4635", upload-time = "2026-05-18T19:18:12.67Z" }, + { url = "https://files.pythonhosted.org/packages/77/74/1f601b63c7a69fcdf10fa9b148c81da8442204194f6c55509cc485c786b9/lxml-6.1.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b8d812c6011c08b8111a15e54dd990b8923692d80adf35488bee34026c35accf", upload-time = "2026-05-18T19:18:15.928Z" }, + { url = "https://files.pythonhosted.org/packages/a2/b9/7a78f51aec95b1bf780d78e12705a9f6533284f8693dc5c0e6724fa53d3f/lxml-6.1.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:fe0306bd29505a9177aac19f1877174b0e7422c222a59f70b2cd41633448c3dc", upload-time = "2026-05-18T19:18:23.223Z" }, + { url = "https://files.pythonhosted.org/packages/a5/6e/98a7b7ad54e4e74fa1f20fff776913980619d0ebe5558232d7da6580bdd8/lxml-6.1.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:5ba186ad207446c65d3bb3d3e0412b032b1d9f595e59861e2354798c5703d955", upload-time = "2026-05-18T19:18:31.433Z" }, + { url = "https://files.pythonhosted.org/packages/65/d1/bc0ed2427bf609f2ee10da303a6a226f9c8bce94f945dc29a32ce55de6e4/lxml-6.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aa366a1e55b8ebfe8ca8ddc3cfe75c8ebade181aeb0f661d0cb05986b647f72a", upload-time = "2026-05-18T19:18:37.091Z" }, + { url = "https://files.pythonhosted.org/packages/69/8b/6772e1a4b513fc50a8d931f19edde0e13ae6918510a1e13ff67864f3e5ed/lxml-6.1.1-cp312-cp312-win32.whl", hash = "sha256:126c93f7f56f0eda92f6d8c619edc463a4f23d9252f1c9d0405a76f25fa9f11a", upload-time = "2026-05-18T19:17:18.37Z" }, + { url = "https://files.pythonhosted.org/packages/1b/89/45198e9624762af2dfd2cb8782598477ceb29f6e59caab560388ae1f4ec1/lxml-6.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:26e6eda8d38c1fcab1090dd196ee87cbd13788e531937610e2589085de074e77", upload-time = "2026-05-18T19:17:56.781Z" }, + { url = "https://files.pythonhosted.org/packages/90/a9/7a54b6834088d9ae528a7b780584ba6a39a9457b0ac330479f20ffbc9449/lxml-6.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:6540377fbd53fe1b629172288c464fb18db11ce1fa7dc15891da10aa9dcc3e7f", upload-time = "2026-05-19T19:22:50.843Z" }, ] [[package]] name = "lz4" version = "4.4.5" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/57/51/f1b86d93029f418033dddf9b9f79c8d2641e7454080478ee2aab5123173e/lz4-4.4.5.tar.gz", hash = "sha256:5f0b9e53c1e82e88c10d7c180069363980136b9d7a8306c4dca4f760d60c39f0", upload-time = "2025-11-03T13:02:36.061Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/57/51/f1b86d93029f418033dddf9b9f79c8d2641e7454080478ee2aab5123173e/lz4-4.4.5.tar.gz", hash = "sha256:5f0b9e53c1e82e88c10d7c180069363980136b9d7a8306c4dca4f760d60c39f0", upload-time = "2025-11-03T13:02:36.061Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/1b/ac/016e4f6de37d806f7cc8f13add0a46c9a7cfc41a5ddc2bc831d7954cf1ce/lz4-4.4.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:df5aa4cead2044bab83e0ebae56e0944cc7fcc1505c7787e9e1057d6d549897e", upload-time = "2025-11-03T13:01:45.895Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/8d/df/0fadac6e5bd31b6f34a1a8dbd4db6a7606e70715387c27368586455b7fc9/lz4-4.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d0bf51e7745484d2092b3a51ae6eb58c3bd3ce0300cf2b2c14f76c536d5697a", upload-time = "2025-11-03T13:01:47.205Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/b7/17/34e36cc49bb16ca73fb57fbd4c5eaa61760c6b64bce91fcb4e0f4a97f852/lz4-4.4.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7b62f94b523c251cf32aa4ab555f14d39bd1a9df385b72443fd76d7c7fb051f5", upload-time = "2025-11-03T13:01:48.667Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/90/1c/b1d8e3741e9fc89ed3b5f7ef5f22586c07ed6bb04e8343c2e98f0fa7ff04/lz4-4.4.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c3ea562c3af274264444819ae9b14dbbf1ab070aff214a05e97db6896c7597e", upload-time = "2025-11-03T13:01:50.159Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/55/d9/e3867222474f6c1b76e89f3bd914595af69f55bf2c1866e984c548afdc15/lz4-4.4.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24092635f47538b392c4eaeff14c7270d2c8e806bf4be2a6446a378591c5e69e", upload-time = "2025-11-03T13:01:51.273Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/b2/e7/d667d337367686311c38b580d1ca3d5a23a6617e129f26becd4f5dc458df/lz4-4.4.5-cp312-cp312-win32.whl", hash = "sha256:214e37cfe270948ea7eb777229e211c601a3e0875541c1035ab408fbceaddf50", upload-time = "2025-11-03T13:01:52.605Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/a5/0b/a54cd7406995ab097fceb907c7eb13a6ddd49e0b231e448f1a81a50af65c/lz4-4.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:713a777de88a73425cf08eb11f742cd2c98628e79a8673d6a52e3c5f0c116f33", upload-time = "2025-11-03T13:01:53.477Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/6a/7e/dc28a952e4bfa32ca16fa2eb026e7a6ce5d1411fcd5986cd08c74ec187b9/lz4-4.4.5-cp312-cp312-win_arm64.whl", hash = "sha256:a88cbb729cc333334ccfb52f070463c21560fca63afcf636a9f160a55fac3301", upload-time = "2025-11-03T13:01:54.419Z" }, + { url = "https://files.pythonhosted.org/packages/1b/ac/016e4f6de37d806f7cc8f13add0a46c9a7cfc41a5ddc2bc831d7954cf1ce/lz4-4.4.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:df5aa4cead2044bab83e0ebae56e0944cc7fcc1505c7787e9e1057d6d549897e", upload-time = "2025-11-03T13:01:45.895Z" }, + { url = "https://files.pythonhosted.org/packages/8d/df/0fadac6e5bd31b6f34a1a8dbd4db6a7606e70715387c27368586455b7fc9/lz4-4.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d0bf51e7745484d2092b3a51ae6eb58c3bd3ce0300cf2b2c14f76c536d5697a", upload-time = "2025-11-03T13:01:47.205Z" }, + { url = "https://files.pythonhosted.org/packages/b7/17/34e36cc49bb16ca73fb57fbd4c5eaa61760c6b64bce91fcb4e0f4a97f852/lz4-4.4.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7b62f94b523c251cf32aa4ab555f14d39bd1a9df385b72443fd76d7c7fb051f5", upload-time = "2025-11-03T13:01:48.667Z" }, + { url = "https://files.pythonhosted.org/packages/90/1c/b1d8e3741e9fc89ed3b5f7ef5f22586c07ed6bb04e8343c2e98f0fa7ff04/lz4-4.4.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c3ea562c3af274264444819ae9b14dbbf1ab070aff214a05e97db6896c7597e", upload-time = "2025-11-03T13:01:50.159Z" }, + { url = "https://files.pythonhosted.org/packages/55/d9/e3867222474f6c1b76e89f3bd914595af69f55bf2c1866e984c548afdc15/lz4-4.4.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24092635f47538b392c4eaeff14c7270d2c8e806bf4be2a6446a378591c5e69e", upload-time = "2025-11-03T13:01:51.273Z" }, + { url = "https://files.pythonhosted.org/packages/b2/e7/d667d337367686311c38b580d1ca3d5a23a6617e129f26becd4f5dc458df/lz4-4.4.5-cp312-cp312-win32.whl", hash = "sha256:214e37cfe270948ea7eb777229e211c601a3e0875541c1035ab408fbceaddf50", upload-time = "2025-11-03T13:01:52.605Z" }, + { url = "https://files.pythonhosted.org/packages/a5/0b/a54cd7406995ab097fceb907c7eb13a6ddd49e0b231e448f1a81a50af65c/lz4-4.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:713a777de88a73425cf08eb11f742cd2c98628e79a8673d6a52e3c5f0c116f33", upload-time = "2025-11-03T13:01:53.477Z" }, + { url = "https://files.pythonhosted.org/packages/6a/7e/dc28a952e4bfa32ca16fa2eb026e7a6ce5d1411fcd5986cd08c74ec187b9/lz4-4.4.5-cp312-cp312-win_arm64.whl", hash = "sha256:a88cbb729cc333334ccfb52f070463c21560fca63afcf636a9f160a55fac3301", upload-time = "2025-11-03T13:01:54.419Z" }, ] [[package]] name = "markupsafe" version = "3.0.3" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", upload-time = "2025-09-27T18:37:40.426Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", upload-time = "2025-09-27T18:37:40.426Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", upload-time = "2025-09-27T18:36:30.854Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", upload-time = "2025-09-27T18:36:31.971Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", upload-time = "2025-09-27T18:36:32.813Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", upload-time = "2025-09-27T18:36:33.86Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", upload-time = "2025-09-27T18:36:35.099Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", upload-time = "2025-09-27T18:36:36.001Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", upload-time = "2025-09-27T18:36:36.906Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", upload-time = "2025-09-27T18:36:37.868Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", upload-time = "2025-09-27T18:36:38.761Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", upload-time = "2025-09-27T18:36:39.701Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", upload-time = "2025-09-27T18:36:40.689Z" }, + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", upload-time = "2025-09-27T18:36:40.689Z" }, ] [[package]] name = "matplotlib" version = "3.10.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "contourpy" }, { name = "cycler" }, @@ -655,192 +655,192 @@ dependencies = [ { name = "pyparsing" }, { name = "python-dateutil" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/68/dd/fa2e1a45fce2d09f4aea3cee169760e672c8262325aa5796c49d543dc7e6/matplotlib-3.10.0.tar.gz", hash = "sha256:b886d02a581b96704c9d1ffe55709e49b4d2d52709ccebc4be42db856e511278", upload-time = "2024-12-14T06:32:51.547Z" } +sdist = { url = "https://files.pythonhosted.org/packages/68/dd/fa2e1a45fce2d09f4aea3cee169760e672c8262325aa5796c49d543dc7e6/matplotlib-3.10.0.tar.gz", hash = "sha256:b886d02a581b96704c9d1ffe55709e49b4d2d52709ccebc4be42db856e511278", upload-time = "2024-12-14T06:32:51.547Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/44/c7/6b2d8cb7cc251d53c976799cacd3200add56351c175ba89ab9cbd7c1e68a/matplotlib-3.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4659665bc7c9b58f8c00317c3c2a299f7f258eeae5a5d56b4c64226fca2f7c59", upload-time = "2024-12-14T06:31:24.727Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/42/2a/6d66d0fba41e13e9ca6512a0a51170f43e7e7ed3a8dfa036324100775612/matplotlib-3.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d44cb942af1693cced2604c33a9abcef6205601c445f6d0dc531d813af8a2f5a", upload-time = "2024-12-14T06:31:28.55Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/90/60/2a60342b27b90a16bada939a85e29589902b41073f59668b904b15ea666c/matplotlib-3.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a994f29e968ca002b50982b27168addfd65f0105610b6be7fa515ca4b5307c95", upload-time = "2024-12-14T06:31:32.223Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/a7/b2/d872fc3d753516870d520595ddd8ce4dd44fa797a240999f125f58521ad7/matplotlib-3.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b0558bae37f154fffda54d779a592bc97ca8b4701f1c710055b609a3bac44c8", upload-time = "2024-12-14T06:31:34.894Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/f4/bd/b2f60cf7f57d014ab33e4f74602a2b5bdc657976db8196bbc022185f6f9c/matplotlib-3.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:503feb23bd8c8acc75541548a1d709c059b7184cde26314896e10a9f14df5f12", upload-time = "2024-12-14T06:31:39.552Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/9f/6e/264673e64001b99d747aff5a288eca82826c024437a3694e19aed1decf46/matplotlib-3.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:c40ba2eb08b3f5de88152c2333c58cee7edcead0a2a0d60fcafa116b17117adc", upload-time = "2024-12-14T06:31:44.128Z" }, + { url = "https://files.pythonhosted.org/packages/44/c7/6b2d8cb7cc251d53c976799cacd3200add56351c175ba89ab9cbd7c1e68a/matplotlib-3.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4659665bc7c9b58f8c00317c3c2a299f7f258eeae5a5d56b4c64226fca2f7c59", upload-time = "2024-12-14T06:31:24.727Z" }, + { url = "https://files.pythonhosted.org/packages/42/2a/6d66d0fba41e13e9ca6512a0a51170f43e7e7ed3a8dfa036324100775612/matplotlib-3.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d44cb942af1693cced2604c33a9abcef6205601c445f6d0dc531d813af8a2f5a", upload-time = "2024-12-14T06:31:28.55Z" }, + { url = "https://files.pythonhosted.org/packages/90/60/2a60342b27b90a16bada939a85e29589902b41073f59668b904b15ea666c/matplotlib-3.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a994f29e968ca002b50982b27168addfd65f0105610b6be7fa515ca4b5307c95", upload-time = "2024-12-14T06:31:32.223Z" }, + { url = "https://files.pythonhosted.org/packages/a7/b2/d872fc3d753516870d520595ddd8ce4dd44fa797a240999f125f58521ad7/matplotlib-3.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b0558bae37f154fffda54d779a592bc97ca8b4701f1c710055b609a3bac44c8", upload-time = "2024-12-14T06:31:34.894Z" }, + { url = "https://files.pythonhosted.org/packages/f4/bd/b2f60cf7f57d014ab33e4f74602a2b5bdc657976db8196bbc022185f6f9c/matplotlib-3.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:503feb23bd8c8acc75541548a1d709c059b7184cde26314896e10a9f14df5f12", upload-time = "2024-12-14T06:31:39.552Z" }, + { url = "https://files.pythonhosted.org/packages/9f/6e/264673e64001b99d747aff5a288eca82826c024437a3694e19aed1decf46/matplotlib-3.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:c40ba2eb08b3f5de88152c2333c58cee7edcead0a2a0d60fcafa116b17117adc", upload-time = "2024-12-14T06:31:44.128Z" }, ] [[package]] name = "mypy-extensions" version = "1.1.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", upload-time = "2025-04-22T14:54:24.164Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", upload-time = "2025-04-22T14:54:24.164Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", upload-time = "2025-04-22T14:54:22.983Z" }, + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", upload-time = "2025-04-22T14:54:22.983Z" }, ] [[package]] name = "nodeenv" version = "1.10.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", upload-time = "2025-12-20T14:08:54.006Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", upload-time = "2025-12-20T14:08:54.006Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", upload-time = "2025-12-20T14:08:52.782Z" }, + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", upload-time = "2025-12-20T14:08:52.782Z" }, ] [[package]] name = "nptyping" version = "2.5.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/e1/b7/ffe533358c32506b1708feec0fb04ba0a35a959a94163fff5333671909da/nptyping-2.5.0.tar.gz", hash = "sha256:e3d35b53af967e6fb407c3016ff9abae954d3a0568f7cc13a461084224e8e20a", upload-time = "2023-02-20T21:57:11.814Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/b7/ffe533358c32506b1708feec0fb04ba0a35a959a94163fff5333671909da/nptyping-2.5.0.tar.gz", hash = "sha256:e3d35b53af967e6fb407c3016ff9abae954d3a0568f7cc13a461084224e8e20a", upload-time = "2023-02-20T21:57:11.814Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/b1/28/92edc05378175de13a3d4986cee7531853634a22b7e5e21a988fa84fde3f/nptyping-2.5.0-py3-none-any.whl", hash = "sha256:764e51836faae33a7ae2e928af574cfb701355647accadcc89f2ad793630b7c8", upload-time = "2023-02-20T21:57:09.61Z" }, + { url = "https://files.pythonhosted.org/packages/b1/28/92edc05378175de13a3d4986cee7531853634a22b7e5e21a988fa84fde3f/nptyping-2.5.0-py3-none-any.whl", hash = "sha256:764e51836faae33a7ae2e928af574cfb701355647accadcc89f2ad793630b7c8", upload-time = "2023-02-20T21:57:09.61Z" }, ] [[package]] name = "nr-date" version = "2.1.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/a0/92/08110dd3d7ff5e2b852a220752eb6c40183839f5b7cc91f9f38dd2298e7d/nr_date-2.1.0.tar.gz", hash = "sha256:0643aea13bcdc2a8bc56af9d5e6a89ef244c9744a1ef00cdc735902ba7f7d2e6", upload-time = "2023-08-16T13:46:04.114Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a0/92/08110dd3d7ff5e2b852a220752eb6c40183839f5b7cc91f9f38dd2298e7d/nr_date-2.1.0.tar.gz", hash = "sha256:0643aea13bcdc2a8bc56af9d5e6a89ef244c9744a1ef00cdc735902ba7f7d2e6", upload-time = "2023-08-16T13:46:04.114Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/f9/10/1d2b00172537c1522fe64bbc6fb16b015632a02f7b3864e788ccbcb4dd85/nr_date-2.1.0-py3-none-any.whl", hash = "sha256:bd672a9dfbdcf7c4b9289fea6750c42490eaee08036a72059dcc78cb236ed568", upload-time = "2023-08-16T13:46:02.627Z" }, + { url = "https://files.pythonhosted.org/packages/f9/10/1d2b00172537c1522fe64bbc6fb16b015632a02f7b3864e788ccbcb4dd85/nr_date-2.1.0-py3-none-any.whl", hash = "sha256:bd672a9dfbdcf7c4b9289fea6750c42490eaee08036a72059dcc78cb236ed568", upload-time = "2023-08-16T13:46:02.627Z" }, ] [[package]] name = "nr-stream" version = "1.1.5" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/b7/37/e4d36d852c441233c306c5fbd98147685dce3ac9b0a8bbf4a587d0ea29ea/nr_stream-1.1.5.tar.gz", hash = "sha256:eb0216c6bfc61a46d4568dba3b588502c610ec8ddef4ac98f3932a2bd7264f65", upload-time = "2023-02-14T22:44:09.074Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b7/37/e4d36d852c441233c306c5fbd98147685dce3ac9b0a8bbf4a587d0ea29ea/nr_stream-1.1.5.tar.gz", hash = "sha256:eb0216c6bfc61a46d4568dba3b588502c610ec8ddef4ac98f3932a2bd7264f65", upload-time = "2023-02-14T22:44:09.074Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/1d/e1/f93485fe09aa36c0e1a3b76363efa1791241f7f863a010f725c95e8a74fe/nr_stream-1.1.5-py3-none-any.whl", hash = "sha256:47e12150b331ad2cb729cfd9d2abd281c9949809729ba461c6aa87dd9927b2d4", upload-time = "2023-02-14T22:44:07.72Z" }, + { url = "https://files.pythonhosted.org/packages/1d/e1/f93485fe09aa36c0e1a3b76363efa1791241f7f863a010f725c95e8a74fe/nr_stream-1.1.5-py3-none-any.whl", hash = "sha256:47e12150b331ad2cb729cfd9d2abd281c9949809729ba461c6aa87dd9927b2d4", upload-time = "2023-02-14T22:44:07.72Z" }, ] [[package]] name = "nr-util" version = "0.8.12" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "deprecated" }, { name = "typing-extensions" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/20/0c/078c567d95e25564bc1ede3c2cf6ce1c91f50648c83786354b47224326da/nr.util-0.8.12.tar.gz", hash = "sha256:a4549c2033d99d2f0379b3f3d233fd2a8ade286bbf0b3ad0cc7cea16022214f4", upload-time = "2022-06-20T13:29:29.192Z" } +sdist = { url = "https://files.pythonhosted.org/packages/20/0c/078c567d95e25564bc1ede3c2cf6ce1c91f50648c83786354b47224326da/nr.util-0.8.12.tar.gz", hash = "sha256:a4549c2033d99d2f0379b3f3d233fd2a8ade286bbf0b3ad0cc7cea16022214f4", upload-time = "2022-06-20T13:29:29.192Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/ba/58/eab08df9dbd69d9e21fc5e7be6f67454f386336ec71e6b64e378a2dddea4/nr.util-0.8.12-py3-none-any.whl", hash = "sha256:91da02ac9795eb8e015372275c1efe54bac9051231ee9b0e7e6f96b0b4e7d2bb", upload-time = "2022-06-20T13:29:27.312Z" }, + { url = "https://files.pythonhosted.org/packages/ba/58/eab08df9dbd69d9e21fc5e7be6f67454f386336ec71e6b64e378a2dddea4/nr.util-0.8.12-py3-none-any.whl", hash = "sha256:91da02ac9795eb8e015372275c1efe54bac9051231ee9b0e7e6f96b0b4e7d2bb", upload-time = "2022-06-20T13:29:27.312Z" }, ] [[package]] name = "numexpr" version = "2.14.1" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/cb/2f/fdba158c9dbe5caca9c3eca3eaffffb251f2fb8674bf8e2d0aed5f38d319/numexpr-2.14.1.tar.gz", hash = "sha256:4be00b1086c7b7a5c32e31558122b7b80243fe098579b170967da83f3152b48b", upload-time = "2025-10-13T16:17:27.351Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cb/2f/fdba158c9dbe5caca9c3eca3eaffffb251f2fb8674bf8e2d0aed5f38d319/numexpr-2.14.1.tar.gz", hash = "sha256:4be00b1086c7b7a5c32e31558122b7b80243fe098579b170967da83f3152b48b", upload-time = "2025-10-13T16:17:27.351Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/9d/20/c473fc04a371f5e2f8c5749e04505c13e7a8ede27c09e9f099b2ad6f43d6/numexpr-2.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ebae0ab18c799b0e6b8c5a8d11e1fa3848eb4011271d99848b297468a39430", upload-time = "2025-10-13T16:16:34.903Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/45/93/b6760dd1904c2a498e5f43d1bb436f59383c3ddea3815f1461dfaa259373/numexpr-2.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:47041f2f7b9e69498fb311af672ba914a60e6e6d804011caacb17d66f639e659", upload-time = "2025-10-13T16:16:36.593Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/72/94/cc921e35593b820521e464cbbeaf8212bbdb07f16dc79fe283168df38195/numexpr-2.14.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d686dfb2c1382d9e6e0ee0b7647f943c1886dba3adbf606c625479f35f1956c1", upload-time = "2025-10-13T16:13:29.531Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/d9/43/560e9ba23c02c904b5934496486d061bcb14cd3ebba2e3cf0e2dccb6c22b/numexpr-2.14.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eee6d4fbbbc368e6cdd0772734d6249128d957b3b8ad47a100789009f4de7083", upload-time = "2025-10-13T16:15:02.473Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/7b/6c/78f83b6219f61c2c22d71ab6e6c2d4e5d7381334c6c29b77204e59edb039/numexpr-2.14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3a2839efa25f3c8d4133252ea7342d8f81226c7c4dda81f97a57e090b9d87a48", upload-time = "2025-10-13T16:13:33.464Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/0e/bb/1ccc9dcaf46281568ce769888bf16294c40e98a5158e4b16c241de31d0d3/numexpr-2.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9f9137f1351b310436662b5dc6f4082a245efa8950c3b0d9008028df92fefb9b", upload-time = "2025-10-13T16:15:12.828Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/31/9f/203d82b9e39dadd91d64bca55b3c8ca432e981b822468dcef41a4418626b/numexpr-2.14.1-cp312-cp312-win32.whl", hash = "sha256:36f8d5c1bd1355df93b43d766790f9046cccfc1e32b7c6163f75bcde682cda07", upload-time = "2025-10-13T16:17:10.369Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/1f/67/ffe750b5452eb66de788c34e7d21ec6d886abb4d7c43ad1dc88ceb3d998f/numexpr-2.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:fdd886f4b7dbaf167633ee396478f0d0aa58ea2f9e7ccc3c6431019623e8d68f", upload-time = "2025-10-13T16:17:11.974Z" }, + { url = "https://files.pythonhosted.org/packages/9d/20/c473fc04a371f5e2f8c5749e04505c13e7a8ede27c09e9f099b2ad6f43d6/numexpr-2.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ebae0ab18c799b0e6b8c5a8d11e1fa3848eb4011271d99848b297468a39430", upload-time = "2025-10-13T16:16:34.903Z" }, + { url = "https://files.pythonhosted.org/packages/45/93/b6760dd1904c2a498e5f43d1bb436f59383c3ddea3815f1461dfaa259373/numexpr-2.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:47041f2f7b9e69498fb311af672ba914a60e6e6d804011caacb17d66f639e659", upload-time = "2025-10-13T16:16:36.593Z" }, + { url = "https://files.pythonhosted.org/packages/72/94/cc921e35593b820521e464cbbeaf8212bbdb07f16dc79fe283168df38195/numexpr-2.14.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d686dfb2c1382d9e6e0ee0b7647f943c1886dba3adbf606c625479f35f1956c1", upload-time = "2025-10-13T16:13:29.531Z" }, + { url = "https://files.pythonhosted.org/packages/d9/43/560e9ba23c02c904b5934496486d061bcb14cd3ebba2e3cf0e2dccb6c22b/numexpr-2.14.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eee6d4fbbbc368e6cdd0772734d6249128d957b3b8ad47a100789009f4de7083", upload-time = "2025-10-13T16:15:02.473Z" }, + { url = "https://files.pythonhosted.org/packages/7b/6c/78f83b6219f61c2c22d71ab6e6c2d4e5d7381334c6c29b77204e59edb039/numexpr-2.14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3a2839efa25f3c8d4133252ea7342d8f81226c7c4dda81f97a57e090b9d87a48", upload-time = "2025-10-13T16:13:33.464Z" }, + { url = "https://files.pythonhosted.org/packages/0e/bb/1ccc9dcaf46281568ce769888bf16294c40e98a5158e4b16c241de31d0d3/numexpr-2.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9f9137f1351b310436662b5dc6f4082a245efa8950c3b0d9008028df92fefb9b", upload-time = "2025-10-13T16:15:12.828Z" }, + { url = "https://files.pythonhosted.org/packages/31/9f/203d82b9e39dadd91d64bca55b3c8ca432e981b822468dcef41a4418626b/numexpr-2.14.1-cp312-cp312-win32.whl", hash = "sha256:36f8d5c1bd1355df93b43d766790f9046cccfc1e32b7c6163f75bcde682cda07", upload-time = "2025-10-13T16:17:10.369Z" }, + { url = "https://files.pythonhosted.org/packages/1f/67/ffe750b5452eb66de788c34e7d21ec6d886abb4d7c43ad1dc88ceb3d998f/numexpr-2.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:fdd886f4b7dbaf167633ee396478f0d0aa58ea2f9e7ccc3c6431019623e8d68f", upload-time = "2025-10-13T16:17:11.974Z" }, ] [[package]] name = "numpy" version = "1.26.4" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", upload-time = "2024-02-06T00:26:44.495Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", upload-time = "2024-02-06T00:26:44.495Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/95/12/8f2020a8e8b8383ac0177dc9570aad031a3beb12e38847f7129bacd96228/numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218", upload-time = "2024-02-05T23:55:32.801Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/75/5b/ca6c8bd14007e5ca171c7c03102d17b4f4e0ceb53957e8c44343a9546dcc/numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b", upload-time = "2024-02-05T23:55:56.28Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/79/f8/97f10e6755e2a7d027ca783f63044d5b1bc1ae7acb12afe6a9b4286eac17/numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b", upload-time = "2024-02-05T23:56:20.368Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/0f/50/de23fde84e45f5c4fda2488c759b69990fd4512387a8632860f3ac9cd225/numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed", upload-time = "2024-02-05T23:56:56.054Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/4c/0c/9c603826b6465e82591e05ca230dfc13376da512b25ccd0894709b054ed0/numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a", upload-time = "2024-02-05T23:57:21.56Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/76/8c/2ba3902e1a0fc1c74962ea9bb33a534bb05984ad7ff9515bf8d07527cadd/numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0", upload-time = "2024-02-05T23:57:56.585Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/28/4a/46d9e65106879492374999e76eb85f87b15328e06bd1550668f79f7b18c6/numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110", upload-time = "2024-02-05T23:58:08.963Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/16/2e/86f24451c2d530c88daf997cb8d6ac622c1d40d19f5a031ed68a4b73a374/numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818", upload-time = "2024-02-05T23:58:36.364Z" }, + { url = "https://files.pythonhosted.org/packages/95/12/8f2020a8e8b8383ac0177dc9570aad031a3beb12e38847f7129bacd96228/numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218", upload-time = "2024-02-05T23:55:32.801Z" }, + { url = "https://files.pythonhosted.org/packages/75/5b/ca6c8bd14007e5ca171c7c03102d17b4f4e0ceb53957e8c44343a9546dcc/numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b", upload-time = "2024-02-05T23:55:56.28Z" }, + { url = "https://files.pythonhosted.org/packages/79/f8/97f10e6755e2a7d027ca783f63044d5b1bc1ae7acb12afe6a9b4286eac17/numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b", upload-time = "2024-02-05T23:56:20.368Z" }, + { url = "https://files.pythonhosted.org/packages/0f/50/de23fde84e45f5c4fda2488c759b69990fd4512387a8632860f3ac9cd225/numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed", upload-time = "2024-02-05T23:56:56.054Z" }, + { url = "https://files.pythonhosted.org/packages/4c/0c/9c603826b6465e82591e05ca230dfc13376da512b25ccd0894709b054ed0/numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a", upload-time = "2024-02-05T23:57:21.56Z" }, + { url = "https://files.pythonhosted.org/packages/76/8c/2ba3902e1a0fc1c74962ea9bb33a534bb05984ad7ff9515bf8d07527cadd/numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0", upload-time = "2024-02-05T23:57:56.585Z" }, + { url = "https://files.pythonhosted.org/packages/28/4a/46d9e65106879492374999e76eb85f87b15328e06bd1550668f79f7b18c6/numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110", upload-time = "2024-02-05T23:58:08.963Z" }, + { url = "https://files.pythonhosted.org/packages/16/2e/86f24451c2d530c88daf997cb8d6ac622c1d40d19f5a031ed68a4b73a374/numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818", upload-time = "2024-02-05T23:58:36.364Z" }, ] [[package]] name = "packaging" version = "26.2" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", upload-time = "2026-04-24T20:15:23.917Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", upload-time = "2026-04-24T20:15:23.917Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", upload-time = "2026-04-24T20:15:22.081Z" }, + { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", upload-time = "2026-04-24T20:15:22.081Z" }, ] [[package]] name = "pandas" version = "2.2.3" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, { name = "python-dateutil" }, { name = "pytz" }, { name = "tzdata" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/9c/d6/9f8431bacc2e19dca897724cd097b1bb224a6ad5433784a44b587c7c13af/pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667", upload-time = "2024-09-20T13:10:04.827Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9c/d6/9f8431bacc2e19dca897724cd097b1bb224a6ad5433784a44b587c7c13af/pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667", upload-time = "2024-09-20T13:10:04.827Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/17/a3/fb2734118db0af37ea7433f57f722c0a56687e14b14690edff0cdb4b7e58/pandas-2.2.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9", upload-time = "2024-09-20T13:09:09.655Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/e1/0c/ad295fd74bfac85358fd579e271cded3ac969de81f62dd0142c426b9da91/pandas-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4", upload-time = "2024-09-20T13:09:14.718Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/c6/2a/4bba3f03f7d07207481fed47f5b35f556c7441acddc368ec43d6643c5777/pandas-2.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3", upload-time = "2024-09-20T19:02:03.88Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/38/f8/d8fddee9ed0d0c0f4a2132c1dfcf0e3e53265055da8df952a53e7eaf178c/pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319", upload-time = "2024-09-20T13:09:17.621Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/20/e8/45a05d9c39d2cea61ab175dbe6a2de1d05b679e8de2011da4ee190d7e748/pandas-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8", upload-time = "2024-09-20T19:02:07.094Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/1d/99/617d07a6a5e429ff90c90da64d428516605a1ec7d7bea494235e1c3882de/pandas-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a", upload-time = "2024-09-20T13:09:20.474Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/29/d4/1244ab8edf173a10fd601f7e13b9566c1b525c4f365d6bee918e68381889/pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", upload-time = "2024-09-20T13:09:23.137Z" }, + { url = "https://files.pythonhosted.org/packages/17/a3/fb2734118db0af37ea7433f57f722c0a56687e14b14690edff0cdb4b7e58/pandas-2.2.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9", upload-time = "2024-09-20T13:09:09.655Z" }, + { url = "https://files.pythonhosted.org/packages/e1/0c/ad295fd74bfac85358fd579e271cded3ac969de81f62dd0142c426b9da91/pandas-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4", upload-time = "2024-09-20T13:09:14.718Z" }, + { url = "https://files.pythonhosted.org/packages/c6/2a/4bba3f03f7d07207481fed47f5b35f556c7441acddc368ec43d6643c5777/pandas-2.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3", upload-time = "2024-09-20T19:02:03.88Z" }, + { url = "https://files.pythonhosted.org/packages/38/f8/d8fddee9ed0d0c0f4a2132c1dfcf0e3e53265055da8df952a53e7eaf178c/pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319", upload-time = "2024-09-20T13:09:17.621Z" }, + { url = "https://files.pythonhosted.org/packages/20/e8/45a05d9c39d2cea61ab175dbe6a2de1d05b679e8de2011da4ee190d7e748/pandas-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8", upload-time = "2024-09-20T19:02:07.094Z" }, + { url = "https://files.pythonhosted.org/packages/1d/99/617d07a6a5e429ff90c90da64d428516605a1ec7d7bea494235e1c3882de/pandas-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a", upload-time = "2024-09-20T13:09:20.474Z" }, + { url = "https://files.pythonhosted.org/packages/29/d4/1244ab8edf173a10fd601f7e13b9566c1b525c4f365d6bee918e68381889/pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", upload-time = "2024-09-20T13:09:23.137Z" }, ] [[package]] name = "pathspec" version = "1.1.1" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", upload-time = "2026-04-27T01:46:08.907Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", upload-time = "2026-04-27T01:46:08.907Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", upload-time = "2026-04-27T01:46:07.06Z" }, + { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", upload-time = "2026-04-27T01:46:07.06Z" }, ] [[package]] name = "pillow" version = "12.2.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/8c/21/c2bcdd5906101a30244eaffc1b6e6ce71a31bd0742a01eb89e660ebfac2d/pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5", upload-time = "2026-04-01T14:46:17.687Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/21/c2bcdd5906101a30244eaffc1b6e6ce71a31bd0742a01eb89e660ebfac2d/pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5", upload-time = "2026-04-01T14:46:17.687Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/58/be/7482c8a5ebebbc6470b3eb791812fff7d5e0216c2be3827b30b8bb6603ed/pillow-12.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2d192a155bbcec180f8564f693e6fd9bccff5a7af9b32e2e4bf8c9c69dbad6b5", upload-time = "2026-04-01T14:43:13.246Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/d8/95/0a351b9289c2b5cbde0bacd4a83ebc44023e835490a727b2a3bd60ddc0f4/pillow-12.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3f40b3c5a968281fd507d519e444c35f0ff171237f4fdde090dd60699458421", upload-time = "2026-04-01T14:43:15.584Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/de/af/4e8e6869cbed569d43c416fad3dc4ecb944cb5d9492defaed89ddd6fe871/pillow-12.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:03e7e372d5240cc23e9f07deca4d775c0817bffc641b01e9c3af208dbd300987", upload-time = "2026-04-01T14:43:18.268Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/e9/9e/c05e19657fd57841e476be1ab46c4d501bffbadbafdc31a6d665f8b737b6/pillow-12.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b86024e52a1b269467a802258c25521e6d742349d760728092e1bc2d135b4d76", upload-time = "2026-04-01T14:43:20.716Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/2b/54/1789c455ed10176066b6e7e6da1b01e50e36f94ba584dc68d9eebfe9156d/pillow-12.2.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7371b48c4fa448d20d2714c9a1f775a81155050d383333e0a6c15b1123dda005", upload-time = "2026-04-01T14:43:23.443Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/43/e3/fdc657359e919462369869f1c9f0e973f353f9a9ee295a39b1fea8ee1a77/pillow-12.2.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62f5409336adb0663b7caa0da5c7d9e7bdbaae9ce761d34669420c2a801b2780", upload-time = "2026-04-01T14:43:26.758Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/8b/f8/2f6825e441d5b1959d2ca5adec984210f1ec086435b0ed5f52c19b3b8a6e/pillow-12.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:01afa7cf67f74f09523699b4e88c73fb55c13346d212a59a2db1f86b0a63e8c5", upload-time = "2026-04-01T14:43:29.56Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/67/f9/029a27095ad20f854f9dba026b3ea6428548316e057e6fc3545409e86651/pillow-12.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc3d34d4a8fbec3e88a79b92e5465e0f9b842b628675850d860b8bd300b159f5", upload-time = "2026-04-01T14:43:32.091Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/be/42/025cfe05d1be22dbfdb4f264fe9de1ccda83f66e4fc3aac94748e784af04/pillow-12.2.0-cp312-cp312-win32.whl", hash = "sha256:58f62cc0f00fd29e64b29f4fd923ffdb3859c9f9e6105bfc37ba1d08994e8940", upload-time = "2026-04-01T14:43:34.601Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/5d/7b/25a221d2c761c6a8ae21bfa3874988ff2583e19cf8a27bf2fee358df7942/pillow-12.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:7f84204dee22a783350679a0333981df803dac21a0190d706a50475e361c93f5", upload-time = "2026-04-01T14:43:37.213Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/10/e1/542a474affab20fd4a0f1836cb234e8493519da6b76899e30bcc5d990b8b/pillow-12.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:af73337013e0b3b46f175e79492d96845b16126ddf79c438d7ea7ff27783a414", upload-time = "2026-04-01T14:43:39.421Z" }, + { url = "https://files.pythonhosted.org/packages/58/be/7482c8a5ebebbc6470b3eb791812fff7d5e0216c2be3827b30b8bb6603ed/pillow-12.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2d192a155bbcec180f8564f693e6fd9bccff5a7af9b32e2e4bf8c9c69dbad6b5", upload-time = "2026-04-01T14:43:13.246Z" }, + { url = "https://files.pythonhosted.org/packages/d8/95/0a351b9289c2b5cbde0bacd4a83ebc44023e835490a727b2a3bd60ddc0f4/pillow-12.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3f40b3c5a968281fd507d519e444c35f0ff171237f4fdde090dd60699458421", upload-time = "2026-04-01T14:43:15.584Z" }, + { url = "https://files.pythonhosted.org/packages/de/af/4e8e6869cbed569d43c416fad3dc4ecb944cb5d9492defaed89ddd6fe871/pillow-12.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:03e7e372d5240cc23e9f07deca4d775c0817bffc641b01e9c3af208dbd300987", upload-time = "2026-04-01T14:43:18.268Z" }, + { url = "https://files.pythonhosted.org/packages/e9/9e/c05e19657fd57841e476be1ab46c4d501bffbadbafdc31a6d665f8b737b6/pillow-12.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b86024e52a1b269467a802258c25521e6d742349d760728092e1bc2d135b4d76", upload-time = "2026-04-01T14:43:20.716Z" }, + { url = "https://files.pythonhosted.org/packages/2b/54/1789c455ed10176066b6e7e6da1b01e50e36f94ba584dc68d9eebfe9156d/pillow-12.2.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7371b48c4fa448d20d2714c9a1f775a81155050d383333e0a6c15b1123dda005", upload-time = "2026-04-01T14:43:23.443Z" }, + { url = "https://files.pythonhosted.org/packages/43/e3/fdc657359e919462369869f1c9f0e973f353f9a9ee295a39b1fea8ee1a77/pillow-12.2.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62f5409336adb0663b7caa0da5c7d9e7bdbaae9ce761d34669420c2a801b2780", upload-time = "2026-04-01T14:43:26.758Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f8/2f6825e441d5b1959d2ca5adec984210f1ec086435b0ed5f52c19b3b8a6e/pillow-12.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:01afa7cf67f74f09523699b4e88c73fb55c13346d212a59a2db1f86b0a63e8c5", upload-time = "2026-04-01T14:43:29.56Z" }, + { url = "https://files.pythonhosted.org/packages/67/f9/029a27095ad20f854f9dba026b3ea6428548316e057e6fc3545409e86651/pillow-12.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc3d34d4a8fbec3e88a79b92e5465e0f9b842b628675850d860b8bd300b159f5", upload-time = "2026-04-01T14:43:32.091Z" }, + { url = "https://files.pythonhosted.org/packages/be/42/025cfe05d1be22dbfdb4f264fe9de1ccda83f66e4fc3aac94748e784af04/pillow-12.2.0-cp312-cp312-win32.whl", hash = "sha256:58f62cc0f00fd29e64b29f4fd923ffdb3859c9f9e6105bfc37ba1d08994e8940", upload-time = "2026-04-01T14:43:34.601Z" }, + { url = "https://files.pythonhosted.org/packages/5d/7b/25a221d2c761c6a8ae21bfa3874988ff2583e19cf8a27bf2fee358df7942/pillow-12.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:7f84204dee22a783350679a0333981df803dac21a0190d706a50475e361c93f5", upload-time = "2026-04-01T14:43:37.213Z" }, + { url = "https://files.pythonhosted.org/packages/10/e1/542a474affab20fd4a0f1836cb234e8493519da6b76899e30bcc5d990b8b/pillow-12.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:af73337013e0b3b46f175e79492d96845b16126ddf79c438d7ea7ff27783a414", upload-time = "2026-04-01T14:43:39.421Z" }, ] [[package]] name = "platformdirs" version = "4.9.6" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/9f/4a/0883b8e3802965322523f0b200ecf33d31f10991d0401162f4b23c698b42/platformdirs-4.9.6.tar.gz", hash = "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a", upload-time = "2026-04-09T00:04:10.812Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9f/4a/0883b8e3802965322523f0b200ecf33d31f10991d0401162f4b23c698b42/platformdirs-4.9.6.tar.gz", hash = "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a", upload-time = "2026-04-09T00:04:10.812Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/75/a6/a0a304dc33b49145b21f4808d763822111e67d1c3a32b524a1baf947b6e1/platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917", upload-time = "2026-04-09T00:04:09.463Z" }, + { url = "https://files.pythonhosted.org/packages/75/a6/a0a304dc33b49145b21f4808d763822111e67d1c3a32b524a1baf947b6e1/platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917", upload-time = "2026-04-09T00:04:09.463Z" }, ] [[package]] name = "pluggy" version = "1.6.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", upload-time = "2025-05-15T12:30:07.975Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", upload-time = "2025-05-15T12:30:07.975Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", upload-time = "2025-05-15T12:30:06.134Z" }, + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", upload-time = "2025-05-15T12:30:06.134Z" }, ] [[package]] name = "pre-commit" version = "4.1.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cfgv" }, { name = "identify" }, @@ -848,133 +848,133 @@ dependencies = [ { name = "pyyaml" }, { name = "virtualenv" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/2a/13/b62d075317d8686071eb843f0bb1f195eb332f48869d3c31a4c6f1e063ac/pre_commit-4.1.0.tar.gz", hash = "sha256:ae3f018575a588e30dfddfab9a05448bfbd6b73d78709617b5a2b853549716d4", upload-time = "2025-01-20T18:31:48.681Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2a/13/b62d075317d8686071eb843f0bb1f195eb332f48869d3c31a4c6f1e063ac/pre_commit-4.1.0.tar.gz", hash = "sha256:ae3f018575a588e30dfddfab9a05448bfbd6b73d78709617b5a2b853549716d4", upload-time = "2025-01-20T18:31:48.681Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/43/b3/df14c580d82b9627d173ceea305ba898dca135feb360b6d84019d0803d3b/pre_commit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d29e7cb346295bcc1cc75fc3e92e343495e3ea0196c9ec6ba53f49f10ab6ae7b", upload-time = "2025-01-20T18:31:47.319Z" }, + { url = "https://files.pythonhosted.org/packages/43/b3/df14c580d82b9627d173ceea305ba898dca135feb360b6d84019d0803d3b/pre_commit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d29e7cb346295bcc1cc75fc3e92e343495e3ea0196c9ec6ba53f49f10ab6ae7b", upload-time = "2025-01-20T18:31:47.319Z" }, ] [[package]] name = "protobuf" version = "6.33.6" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/66/70/e908e9c5e52ef7c3a6c7902c9dfbb34c7e29c25d2f81ade3856445fd5c94/protobuf-6.33.6.tar.gz", hash = "sha256:a6768d25248312c297558af96a9f9c929e8c4cee0659cb07e780731095f38135", upload-time = "2026-03-18T19:05:00.988Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/70/e908e9c5e52ef7c3a6c7902c9dfbb34c7e29c25d2f81ade3856445fd5c94/protobuf-6.33.6.tar.gz", hash = "sha256:a6768d25248312c297558af96a9f9c929e8c4cee0659cb07e780731095f38135", upload-time = "2026-03-18T19:05:00.988Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/fc/9f/2f509339e89cfa6f6a4c4ff50438db9ca488dec341f7e454adad60150b00/protobuf-6.33.6-cp310-abi3-win32.whl", hash = "sha256:7d29d9b65f8afef196f8334e80d6bc1d5d4adedb449971fefd3723824e6e77d3", upload-time = "2026-03-18T19:04:48.373Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/76/5d/683efcd4798e0030c1bab27374fd13a89f7c2515fb1f3123efdfaa5eab57/protobuf-6.33.6-cp310-abi3-win_amd64.whl", hash = "sha256:0cd27b587afca21b7cfa59a74dcbd48a50f0a6400cfb59391340ad729d91d326", upload-time = "2026-03-18T19:04:50.381Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:9720e6961b251bde64edfdab7d500725a2af5280f3f4c87e57c0208376aa8c3a", upload-time = "2026-03-18T19:04:51.866Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/ee/90/b3c01fdec7d2f627b3a6884243ba328c1217ed2d978def5c12dc50d328a3/protobuf-6.33.6-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:e2afbae9b8e1825e3529f88d514754e094278bb95eadc0e199751cdd9a2e82a2", upload-time = "2026-03-18T19:04:53.096Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/9b/ca/25afc144934014700c52e05103c2421997482d561f3101ff352e1292fb81/protobuf-6.33.6-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:c96c37eec15086b79762ed265d59ab204dabc53056e3443e702d2681f4b39ce3", upload-time = "2026-03-18T19:04:54.616Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/16/92/d1e32e3e0d894fe00b15ce28ad4944ab692713f2e7f0a99787405e43533a/protobuf-6.33.6-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:e9db7e292e0ab79dd108d7f1a94fe31601ce1ee3f7b79e0692043423020b0593", upload-time = "2026-03-18T19:04:55.768Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/c4/72/02445137af02769918a93807b2b7890047c32bfb9f90371cbc12688819eb/protobuf-6.33.6-py3-none-any.whl", hash = "sha256:77179e006c476e69bf8e8ce866640091ec42e1beb80b213c3900006ecfba6901", upload-time = "2026-03-18T19:04:59.826Z" }, + { url = "https://files.pythonhosted.org/packages/fc/9f/2f509339e89cfa6f6a4c4ff50438db9ca488dec341f7e454adad60150b00/protobuf-6.33.6-cp310-abi3-win32.whl", hash = "sha256:7d29d9b65f8afef196f8334e80d6bc1d5d4adedb449971fefd3723824e6e77d3", upload-time = "2026-03-18T19:04:48.373Z" }, + { url = "https://files.pythonhosted.org/packages/76/5d/683efcd4798e0030c1bab27374fd13a89f7c2515fb1f3123efdfaa5eab57/protobuf-6.33.6-cp310-abi3-win_amd64.whl", hash = "sha256:0cd27b587afca21b7cfa59a74dcbd48a50f0a6400cfb59391340ad729d91d326", upload-time = "2026-03-18T19:04:50.381Z" }, + { url = "https://files.pythonhosted.org/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:9720e6961b251bde64edfdab7d500725a2af5280f3f4c87e57c0208376aa8c3a", upload-time = "2026-03-18T19:04:51.866Z" }, + { url = "https://files.pythonhosted.org/packages/ee/90/b3c01fdec7d2f627b3a6884243ba328c1217ed2d978def5c12dc50d328a3/protobuf-6.33.6-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:e2afbae9b8e1825e3529f88d514754e094278bb95eadc0e199751cdd9a2e82a2", upload-time = "2026-03-18T19:04:53.096Z" }, + { url = "https://files.pythonhosted.org/packages/9b/ca/25afc144934014700c52e05103c2421997482d561f3101ff352e1292fb81/protobuf-6.33.6-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:c96c37eec15086b79762ed265d59ab204dabc53056e3443e702d2681f4b39ce3", upload-time = "2026-03-18T19:04:54.616Z" }, + { url = "https://files.pythonhosted.org/packages/16/92/d1e32e3e0d894fe00b15ce28ad4944ab692713f2e7f0a99787405e43533a/protobuf-6.33.6-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:e9db7e292e0ab79dd108d7f1a94fe31601ce1ee3f7b79e0692043423020b0593", upload-time = "2026-03-18T19:04:55.768Z" }, + { url = "https://files.pythonhosted.org/packages/c4/72/02445137af02769918a93807b2b7890047c32bfb9f90371cbc12688819eb/protobuf-6.33.6-py3-none-any.whl", hash = "sha256:77179e006c476e69bf8e8ce866640091ec42e1beb80b213c3900006ecfba6901", upload-time = "2026-03-18T19:04:59.826Z" }, ] [[package]] name = "py-cpuinfo" version = "9.0.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/37/a8/d832f7293ebb21690860d2e01d8115e5ff6f2ae8bbdc953f0eb0fa4bd2c7/py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690", upload-time = "2022-10-25T20:38:06.303Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/37/a8/d832f7293ebb21690860d2e01d8115e5ff6f2ae8bbdc953f0eb0fa4bd2c7/py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690", upload-time = "2022-10-25T20:38:06.303Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/e0/a9/023730ba63db1e494a271cb018dcd361bd2c917ba7004c3e49d5daf795a2/py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5", upload-time = "2022-10-25T20:38:27.636Z" }, + { url = "https://files.pythonhosted.org/packages/e0/a9/023730ba63db1e494a271cb018dcd361bd2c917ba7004c3e49d5daf795a2/py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5", upload-time = "2022-10-25T20:38:27.636Z" }, ] [[package]] name = "py4j" version = "0.10.9.9" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/38/31/0b210511177070c8d5d3059556194352e5753602fa64b85b7ab81ec1a009/py4j-0.10.9.9.tar.gz", hash = "sha256:f694cad19efa5bd1dee4f3e5270eb406613c974394035e5bfc4ec1aba870b879", upload-time = "2025-01-15T03:53:18.624Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/38/31/0b210511177070c8d5d3059556194352e5753602fa64b85b7ab81ec1a009/py4j-0.10.9.9.tar.gz", hash = "sha256:f694cad19efa5bd1dee4f3e5270eb406613c974394035e5bfc4ec1aba870b879", upload-time = "2025-01-15T03:53:18.624Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl", hash = "sha256:c7c26e4158defb37b0bb124933163641a2ff6e3a3913f7811b0ddbe07ed61533", upload-time = "2025-01-15T03:53:15.648Z" }, + { url = "https://files.pythonhosted.org/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl", hash = "sha256:c7c26e4158defb37b0bb124933163641a2ff6e3a3913f7811b0ddbe07ed61533", upload-time = "2025-01-15T03:53:15.648Z" }, ] [[package]] name = "pyarrow" version = "19.0.1" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/7f/09/a9046344212690f0632b9c709f9bf18506522feb333c894d0de81d62341a/pyarrow-19.0.1.tar.gz", hash = "sha256:3bf266b485df66a400f282ac0b6d1b500b9d2ae73314a153dbe97d6d5cc8a99e", upload-time = "2025-02-18T18:55:57.027Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7f/09/a9046344212690f0632b9c709f9bf18506522feb333c894d0de81d62341a/pyarrow-19.0.1.tar.gz", hash = "sha256:3bf266b485df66a400f282ac0b6d1b500b9d2ae73314a153dbe97d6d5cc8a99e", upload-time = "2025-02-18T18:55:57.027Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/78/b4/94e828704b050e723f67d67c3535cf7076c7432cd4cf046e4bb3b96a9c9d/pyarrow-19.0.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:80b2ad2b193e7d19e81008a96e313fbd53157945c7be9ac65f44f8937a55427b", upload-time = "2025-02-18T18:53:00.062Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/7e/3b/4692965e04bb1df55e2c314c4296f1eb12b4f3052d4cf43d29e076aedf66/pyarrow-19.0.1-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:ee8dec072569f43835932a3b10c55973593abc00936c202707a4ad06af7cb294", upload-time = "2025-02-18T18:53:06.581Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/22/f7/2239af706252c6582a5635c35caa17cb4d401cd74a87821ef702e3888957/pyarrow-19.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d5d1ec7ec5324b98887bdc006f4d2ce534e10e60f7ad995e7875ffa0ff9cb14", upload-time = "2025-02-18T18:53:11.958Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/fb/e3/c9661b2b2849cfefddd9fd65b64e093594b231b472de08ff658f76c732b2/pyarrow-19.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3ad4c0eb4e2a9aeb990af6c09e6fa0b195c8c0e7b272ecc8d4d2b6574809d34", upload-time = "2025-02-18T18:53:17.678Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/fe/4f/a2c0ed309167ef436674782dfee4a124570ba64299c551e38d3fdaf0a17b/pyarrow-19.0.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:d383591f3dcbe545f6cc62daaef9c7cdfe0dff0fb9e1c8121101cabe9098cfa6", upload-time = "2025-02-18T18:53:26.263Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/27/2e/29bb28a7102a6f71026a9d70d1d61df926887e36ec797f2e6acfd2dd3867/pyarrow-19.0.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b4c4156a625f1e35d6c0b2132635a237708944eb41df5fbe7d50f20d20c17832", upload-time = "2025-02-18T18:53:33.063Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/16/33/2a67c0f783251106aeeee516f4806161e7b481f7d744d0d643d2f30230a5/pyarrow-19.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:5bd1618ae5e5476b7654c7b55a6364ae87686d4724538c24185bbb2952679960", upload-time = "2025-02-18T18:53:38.462Z" }, + { url = "https://files.pythonhosted.org/packages/78/b4/94e828704b050e723f67d67c3535cf7076c7432cd4cf046e4bb3b96a9c9d/pyarrow-19.0.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:80b2ad2b193e7d19e81008a96e313fbd53157945c7be9ac65f44f8937a55427b", upload-time = "2025-02-18T18:53:00.062Z" }, + { url = "https://files.pythonhosted.org/packages/7e/3b/4692965e04bb1df55e2c314c4296f1eb12b4f3052d4cf43d29e076aedf66/pyarrow-19.0.1-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:ee8dec072569f43835932a3b10c55973593abc00936c202707a4ad06af7cb294", upload-time = "2025-02-18T18:53:06.581Z" }, + { url = "https://files.pythonhosted.org/packages/22/f7/2239af706252c6582a5635c35caa17cb4d401cd74a87821ef702e3888957/pyarrow-19.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d5d1ec7ec5324b98887bdc006f4d2ce534e10e60f7ad995e7875ffa0ff9cb14", upload-time = "2025-02-18T18:53:11.958Z" }, + { url = "https://files.pythonhosted.org/packages/fb/e3/c9661b2b2849cfefddd9fd65b64e093594b231b472de08ff658f76c732b2/pyarrow-19.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3ad4c0eb4e2a9aeb990af6c09e6fa0b195c8c0e7b272ecc8d4d2b6574809d34", upload-time = "2025-02-18T18:53:17.678Z" }, + { url = "https://files.pythonhosted.org/packages/fe/4f/a2c0ed309167ef436674782dfee4a124570ba64299c551e38d3fdaf0a17b/pyarrow-19.0.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:d383591f3dcbe545f6cc62daaef9c7cdfe0dff0fb9e1c8121101cabe9098cfa6", upload-time = "2025-02-18T18:53:26.263Z" }, + { url = "https://files.pythonhosted.org/packages/27/2e/29bb28a7102a6f71026a9d70d1d61df926887e36ec797f2e6acfd2dd3867/pyarrow-19.0.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b4c4156a625f1e35d6c0b2132635a237708944eb41df5fbe7d50f20d20c17832", upload-time = "2025-02-18T18:53:33.063Z" }, + { url = "https://files.pythonhosted.org/packages/16/33/2a67c0f783251106aeeee516f4806161e7b481f7d744d0d643d2f30230a5/pyarrow-19.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:5bd1618ae5e5476b7654c7b55a6364ae87686d4724538c24185bbb2952679960", upload-time = "2025-02-18T18:53:38.462Z" }, ] [[package]] name = "pyasn1" version = "0.6.3" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/5c/5f/6583902b6f79b399c9c40674ac384fd9cd77805f9e6205075f828ef11fb2/pyasn1-0.6.3.tar.gz", hash = "sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf", upload-time = "2026-03-17T01:06:53.382Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/5f/6583902b6f79b399c9c40674ac384fd9cd77805f9e6205075f828ef11fb2/pyasn1-0.6.3.tar.gz", hash = "sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf", upload-time = "2026-03-17T01:06:53.382Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl", hash = "sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde", upload-time = "2026-03-17T01:06:52.036Z" }, + { url = "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl", hash = "sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde", upload-time = "2026-03-17T01:06:52.036Z" }, ] [[package]] name = "pyasn1-modules" version = "0.4.2" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyasn1" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", upload-time = "2025-03-28T02:41:22.17Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", upload-time = "2025-03-28T02:41:22.17Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", upload-time = "2025-03-28T02:41:19.028Z" }, + { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", upload-time = "2025-03-28T02:41:19.028Z" }, ] [[package]] name = "pycparser" version = "3.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", upload-time = "2026-01-21T14:26:51.89Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", upload-time = "2026-01-21T14:26:51.89Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", upload-time = "2026-01-21T14:26:50.693Z" }, + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", upload-time = "2026-01-21T14:26:50.693Z" }, ] [[package]] name = "pydantic" version = "2.11.7" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-types" }, { name = "pydantic-core" }, { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", upload-time = "2025-06-14T08:33:17.137Z" } +sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", upload-time = "2025-06-14T08:33:17.137Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", upload-time = "2025-06-14T08:33:14.905Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", upload-time = "2025-06-14T08:33:14.905Z" }, ] [[package]] name = "pydantic-core" version = "2.33.2" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", upload-time = "2025-04-23T18:33:52.104Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", upload-time = "2025-04-23T18:33:52.104Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", upload-time = "2025-04-23T18:31:25.863Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", upload-time = "2025-04-23T18:31:27.341Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", upload-time = "2025-04-23T18:31:28.956Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", upload-time = "2025-04-23T18:31:31.025Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", upload-time = "2025-04-23T18:31:32.514Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", upload-time = "2025-04-23T18:31:33.958Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", upload-time = "2025-04-23T18:31:39.095Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", upload-time = "2025-04-23T18:31:41.034Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", upload-time = "2025-04-23T18:31:42.757Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", upload-time = "2025-04-23T18:31:44.304Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", upload-time = "2025-04-23T18:31:45.891Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", upload-time = "2025-04-23T18:31:47.819Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", upload-time = "2025-04-23T18:31:49.635Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", upload-time = "2025-04-23T18:31:51.609Z" }, + { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", upload-time = "2025-04-23T18:31:25.863Z" }, + { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", upload-time = "2025-04-23T18:31:27.341Z" }, + { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", upload-time = "2025-04-23T18:31:28.956Z" }, + { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", upload-time = "2025-04-23T18:31:31.025Z" }, + { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", upload-time = "2025-04-23T18:31:32.514Z" }, + { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", upload-time = "2025-04-23T18:31:33.958Z" }, + { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", upload-time = "2025-04-23T18:31:39.095Z" }, + { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", upload-time = "2025-04-23T18:31:41.034Z" }, + { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", upload-time = "2025-04-23T18:31:42.757Z" }, + { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", upload-time = "2025-04-23T18:31:44.304Z" }, + { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", upload-time = "2025-04-23T18:31:45.891Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", upload-time = "2025-04-23T18:31:47.819Z" }, + { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", upload-time = "2025-04-23T18:31:49.635Z" }, + { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", upload-time = "2025-04-23T18:31:51.609Z" }, ] [[package]] name = "pydoc-markdown" version = "4.8.2" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "databind-core" }, @@ -991,376 +991,376 @@ dependencies = [ { name = "watchdog" }, { name = "yapf" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/e1/8a/2c7f7ad656d22371a596d232fc140327b958d7f1d491b889632ea0cb7e87/pydoc_markdown-4.8.2.tar.gz", hash = "sha256:fb6c927e31386de17472d42f9bd3d3be2905977d026f6216881c65145aa67f0b", upload-time = "2023-06-26T12:37:01.152Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/8a/2c7f7ad656d22371a596d232fc140327b958d7f1d491b889632ea0cb7e87/pydoc_markdown-4.8.2.tar.gz", hash = "sha256:fb6c927e31386de17472d42f9bd3d3be2905977d026f6216881c65145aa67f0b", upload-time = "2023-06-26T12:37:01.152Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/83/5a/ce0b056d9a95fd0c06a6cfa5972477d79353392d19230c748a7ba5a9df04/pydoc_markdown-4.8.2-py3-none-any.whl", hash = "sha256:203f74119e6bb2f9deba43d452422de7c8ec31955b61e0620fa4dd8c2611715f", upload-time = "2023-06-26T12:36:59.502Z" }, + { url = "https://files.pythonhosted.org/packages/83/5a/ce0b056d9a95fd0c06a6cfa5972477d79353392d19230c748a7ba5a9df04/pydoc_markdown-4.8.2-py3-none-any.whl", hash = "sha256:203f74119e6bb2f9deba43d452422de7c8ec31955b61e0620fa4dd8c2611715f", upload-time = "2023-06-26T12:36:59.502Z" }, ] [[package]] name = "pyparsing" version = "3.3.2" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", upload-time = "2026-01-21T03:57:59.36Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", upload-time = "2026-01-21T03:57:59.36Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", upload-time = "2026-01-21T03:57:55.912Z" }, + { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", upload-time = "2026-01-21T03:57:55.912Z" }, ] [[package]] name = "pyspark" version = "4.0.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "py4j" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/9d/0e/5b38d51f1b1c2618cccfbf35093268665af9a3bdb493e5a3ecd991def633/pyspark-4.0.0.tar.gz", hash = "sha256:38db1b4f6095a080d7605e578d775528990e66dc326311d93e94a71cfc24e5a5", upload-time = "2025-05-23T03:29:33.916Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/0e/5b38d51f1b1c2618cccfbf35093268665af9a3bdb493e5a3ecd991def633/pyspark-4.0.0.tar.gz", hash = "sha256:38db1b4f6095a080d7605e578d775528990e66dc326311d93e94a71cfc24e5a5", upload-time = "2025-05-23T03:29:33.916Z" } [[package]] name = "pytest" version = "8.3.5" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "iniconfig" }, { name = "packaging" }, { name = "pluggy" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", upload-time = "2025-03-02T12:54:54.503Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", upload-time = "2025-03-02T12:54:54.503Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", upload-time = "2025-03-02T12:54:52.069Z" }, + { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", upload-time = "2025-03-02T12:54:52.069Z" }, ] [[package]] name = "pytest-benchmark" version = "5.1.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "py-cpuinfo" }, { name = "pytest" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/39/d0/a8bd08d641b393db3be3819b03e2d9bb8760ca8479080a26a5f6e540e99c/pytest-benchmark-5.1.0.tar.gz", hash = "sha256:9ea661cdc292e8231f7cd4c10b0319e56a2118e2c09d9f50e1b3d150d2aca105", upload-time = "2024-10-30T11:51:48.521Z" } +sdist = { url = "https://files.pythonhosted.org/packages/39/d0/a8bd08d641b393db3be3819b03e2d9bb8760ca8479080a26a5f6e540e99c/pytest-benchmark-5.1.0.tar.gz", hash = "sha256:9ea661cdc292e8231f7cd4c10b0319e56a2118e2c09d9f50e1b3d150d2aca105", upload-time = "2024-10-30T11:51:48.521Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/9e/d6/b41653199ea09d5969d4e385df9bbfd9a100f28ca7e824ce7c0a016e3053/pytest_benchmark-5.1.0-py3-none-any.whl", hash = "sha256:922de2dfa3033c227c96da942d1878191afa135a29485fb942e85dff1c592c89", upload-time = "2024-10-30T11:51:45.94Z" }, + { url = "https://files.pythonhosted.org/packages/9e/d6/b41653199ea09d5969d4e385df9bbfd9a100f28ca7e824ce7c0a016e3053/pytest_benchmark-5.1.0-py3-none-any.whl", hash = "sha256:922de2dfa3033c227c96da942d1878191afa135a29485fb942e85dff1c592c89", upload-time = "2024-10-30T11:51:45.94Z" }, ] [[package]] name = "pytest-cov" version = "6.0.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "coverage" }, { name = "pytest" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", upload-time = "2024-10-29T20:13:35.363Z" } +sdist = { url = "https://files.pythonhosted.org/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", upload-time = "2024-10-29T20:13:35.363Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", upload-time = "2024-10-29T20:13:33.215Z" }, + { url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", upload-time = "2024-10-29T20:13:33.215Z" }, ] [[package]] name = "pytest-mock" version = "3.15.1" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/68/14/eb014d26be205d38ad5ad20d9a80f7d201472e08167f0bb4361e251084a9/pytest_mock-3.15.1.tar.gz", hash = "sha256:1849a238f6f396da19762269de72cb1814ab44416fa73a8686deac10b0d87a0f", upload-time = "2025-09-16T16:37:27.081Z" } +sdist = { url = "https://files.pythonhosted.org/packages/68/14/eb014d26be205d38ad5ad20d9a80f7d201472e08167f0bb4361e251084a9/pytest_mock-3.15.1.tar.gz", hash = "sha256:1849a238f6f396da19762269de72cb1814ab44416fa73a8686deac10b0d87a0f", upload-time = "2025-09-16T16:37:27.081Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/5a/cc/06253936f4a7fa2e0f48dfe6d851d9c56df896a9ab09ac019d70b760619c/pytest_mock-3.15.1-py3-none-any.whl", hash = "sha256:0a25e2eb88fe5168d535041d09a4529a188176ae608a6d249ee65abc0949630d", upload-time = "2025-09-16T16:37:25.734Z" }, + { url = "https://files.pythonhosted.org/packages/5a/cc/06253936f4a7fa2e0f48dfe6d851d9c56df896a9ab09ac019d70b760619c/pytest_mock-3.15.1-py3-none-any.whl", hash = "sha256:0a25e2eb88fe5168d535041d09a4529a188176ae608a6d249ee65abc0949630d", upload-time = "2025-09-16T16:37:25.734Z" }, ] [[package]] name = "python-dateutil" version = "2.9.0.post0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", upload-time = "2024-03-01T18:36:20.211Z" } +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", upload-time = "2024-03-01T18:36:20.211Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", upload-time = "2024-03-01T18:36:18.57Z" }, + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", upload-time = "2024-03-01T18:36:18.57Z" }, ] [[package]] name = "python-discovery" version = "1.2.2" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, { name = "platformdirs" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/de/ef/3bae0e537cfe91e8431efcba4434463d2c5a65f5a89edd47c6cf2f03c55f/python_discovery-1.2.2.tar.gz", hash = "sha256:876e9c57139eb757cb5878cbdd9ae5379e5d96266c99ef731119e04fffe533bb", upload-time = "2026-04-07T17:28:49.249Z" } +sdist = { url = "https://files.pythonhosted.org/packages/de/ef/3bae0e537cfe91e8431efcba4434463d2c5a65f5a89edd47c6cf2f03c55f/python_discovery-1.2.2.tar.gz", hash = "sha256:876e9c57139eb757cb5878cbdd9ae5379e5d96266c99ef731119e04fffe533bb", upload-time = "2026-04-07T17:28:49.249Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/d8/db/795879cc3ddfe338599bddea6388cc5100b088db0a4caf6e6c1af1c27e04/python_discovery-1.2.2-py3-none-any.whl", hash = "sha256:e1ae95d9af875e78f15e19aed0c6137ab1bb49c200f21f5061786490c9585c7a", upload-time = "2026-04-07T17:28:48.09Z" }, + { url = "https://files.pythonhosted.org/packages/d8/db/795879cc3ddfe338599bddea6388cc5100b088db0a4caf6e6c1af1c27e04/python_discovery-1.2.2-py3-none-any.whl", hash = "sha256:e1ae95d9af875e78f15e19aed0c6137ab1bb49c200f21f5061786490c9585c7a", upload-time = "2026-04-07T17:28:48.09Z" }, ] [[package]] name = "pytokens" version = "0.4.1" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/b6/34/b4e015b99031667a7b960f888889c5bd34ef585c85e1cb56a594b92836ac/pytokens-0.4.1.tar.gz", hash = "sha256:292052fe80923aae2260c073f822ceba21f3872ced9a68bb7953b348e561179a", upload-time = "2026-01-30T01:03:45.924Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b6/34/b4e015b99031667a7b960f888889c5bd34ef585c85e1cb56a594b92836ac/pytokens-0.4.1.tar.gz", hash = "sha256:292052fe80923aae2260c073f822ceba21f3872ced9a68bb7953b348e561179a", upload-time = "2026-01-30T01:03:45.924Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/41/5d/e44573011401fb82e9d51e97f1290ceb377800fb4eed650b96f4753b499c/pytokens-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:140709331e846b728475786df8aeb27d24f48cbcf7bcd449f8de75cae7a45083", upload-time = "2026-01-30T01:03:06.473Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/f0/e6/5bbc3019f8e6f21d09c41f8b8654536117e5e211a85d89212d59cbdab381/pytokens-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d6c4268598f762bc8e91f5dbf2ab2f61f7b95bdc07953b602db879b3c8c18e1", upload-time = "2026-01-30T01:03:08.177Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/bf/3c/2d5297d82286f6f3d92770289fd439956b201c0a4fc7e72efb9b2293758e/pytokens-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24afde1f53d95348b5a0eb19488661147285ca4dd7ed752bbc3e1c6242a304d1", upload-time = "2026-01-30T01:03:09.756Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/20/01/7436e9ad693cebda0551203e0bf28f7669976c60ad07d6402098208476de/pytokens-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5ad948d085ed6c16413eb5fec6b3e02fa00dc29a2534f088d3302c47eb59adf9", upload-time = "2026-01-30T01:03:10.957Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/2e/df/533c82a3c752ba13ae7ef238b7f8cdd272cf1475f03c63ac6cf3fcfb00b6/pytokens-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:3f901fe783e06e48e8cbdc82d631fca8f118333798193e026a50ce1b3757ea68", upload-time = "2026-01-30T01:03:12.066Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/c6/78/397db326746f0a342855b81216ae1f0a32965deccfd7c830a2dbc66d2483/pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de", upload-time = "2026-01-30T01:03:45.029Z" }, + { url = "https://files.pythonhosted.org/packages/41/5d/e44573011401fb82e9d51e97f1290ceb377800fb4eed650b96f4753b499c/pytokens-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:140709331e846b728475786df8aeb27d24f48cbcf7bcd449f8de75cae7a45083", upload-time = "2026-01-30T01:03:06.473Z" }, + { url = "https://files.pythonhosted.org/packages/f0/e6/5bbc3019f8e6f21d09c41f8b8654536117e5e211a85d89212d59cbdab381/pytokens-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d6c4268598f762bc8e91f5dbf2ab2f61f7b95bdc07953b602db879b3c8c18e1", upload-time = "2026-01-30T01:03:08.177Z" }, + { url = "https://files.pythonhosted.org/packages/bf/3c/2d5297d82286f6f3d92770289fd439956b201c0a4fc7e72efb9b2293758e/pytokens-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24afde1f53d95348b5a0eb19488661147285ca4dd7ed752bbc3e1c6242a304d1", upload-time = "2026-01-30T01:03:09.756Z" }, + { url = "https://files.pythonhosted.org/packages/20/01/7436e9ad693cebda0551203e0bf28f7669976c60ad07d6402098208476de/pytokens-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5ad948d085ed6c16413eb5fec6b3e02fa00dc29a2534f088d3302c47eb59adf9", upload-time = "2026-01-30T01:03:10.957Z" }, + { url = "https://files.pythonhosted.org/packages/2e/df/533c82a3c752ba13ae7ef238b7f8cdd272cf1475f03c63ac6cf3fcfb00b6/pytokens-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:3f901fe783e06e48e8cbdc82d631fca8f118333798193e026a50ce1b3757ea68", upload-time = "2026-01-30T01:03:12.066Z" }, + { url = "https://files.pythonhosted.org/packages/c6/78/397db326746f0a342855b81216ae1f0a32965deccfd7c830a2dbc66d2483/pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de", upload-time = "2026-01-30T01:03:45.029Z" }, ] [[package]] name = "pytz" version = "2026.1.post1" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/56/db/b8721d71d945e6a8ac63c0fc900b2067181dbb50805958d4d4661cf7d277/pytz-2026.1.post1.tar.gz", hash = "sha256:3378dde6a0c3d26719182142c56e60c7f9af7e968076f31aae569d72a0358ee1", upload-time = "2026-03-03T07:47:50.683Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/56/db/b8721d71d945e6a8ac63c0fc900b2067181dbb50805958d4d4661cf7d277/pytz-2026.1.post1.tar.gz", hash = "sha256:3378dde6a0c3d26719182142c56e60c7f9af7e968076f31aae569d72a0358ee1", upload-time = "2026-03-03T07:47:50.683Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/10/99/781fe0c827be2742bcc775efefccb3b048a3a9c6ce9aec0cbf4a101677e5/pytz-2026.1.post1-py2.py3-none-any.whl", hash = "sha256:f2fd16142fda348286a75e1a524be810bb05d444e5a081f37f7affc635035f7a", upload-time = "2026-03-03T07:47:49.167Z" }, + { url = "https://files.pythonhosted.org/packages/10/99/781fe0c827be2742bcc775efefccb3b048a3a9c6ce9aec0cbf4a101677e5/pytz-2026.1.post1-py2.py3-none-any.whl", hash = "sha256:f2fd16142fda348286a75e1a524be810bb05d444e5a081f37f7affc635035f7a", upload-time = "2026-03-03T07:47:49.167Z" }, ] [[package]] name = "pyyaml" version = "6.0.3" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", upload-time = "2025-09-25T21:33:16.546Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", upload-time = "2025-09-25T21:33:16.546Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", upload-time = "2025-09-25T21:32:11.445Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", upload-time = "2025-09-25T21:32:12.492Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", upload-time = "2025-09-25T21:32:13.652Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", upload-time = "2025-09-25T21:32:15.21Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", upload-time = "2025-09-25T21:32:16.431Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", upload-time = "2025-09-25T21:32:17.56Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", upload-time = "2025-09-25T21:32:18.834Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", upload-time = "2025-09-25T21:32:20.209Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", upload-time = "2025-09-25T21:32:21.167Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", upload-time = "2025-09-25T21:32:22.617Z" }, ] [[package]] name = "requests" version = "2.33.1" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "charset-normalizer" }, { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517", upload-time = "2026-03-30T16:09:15.531Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517", upload-time = "2026-03-30T16:09:15.531Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a", upload-time = "2026-03-30T16:09:13.83Z" }, + { url = "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a", upload-time = "2026-03-30T16:09:13.83Z" }, ] [[package]] name = "ruff" version = "0.9.10" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/20/8e/fafaa6f15c332e73425d9c44ada85360501045d5ab0b81400076aff27cf6/ruff-0.9.10.tar.gz", hash = "sha256:9bacb735d7bada9cfb0f2c227d3658fc443d90a727b47f206fb33f52f3c0eac7", upload-time = "2025-03-07T15:27:44.363Z" } -wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/73/b2/af7c2cc9e438cbc19fafeec4f20bfcd72165460fe75b2b6e9a0958c8c62b/ruff-0.9.10-py3-none-linux_armv6l.whl", hash = "sha256:eb4d25532cfd9fe461acc83498361ec2e2252795b4f40b17e80692814329e42d", upload-time = "2025-03-07T15:26:51.268Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/6d/12/03f6dfa1b95ddd47e6969f0225d60d9d7437c91938a310835feb27927ca0/ruff-0.9.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:188a6638dab1aa9bb6228a7302387b2c9954e455fb25d6b4470cb0641d16759d", upload-time = "2025-03-07T15:26:56.104Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/02/49/1c79e0906b6ff551fb0894168763f705bf980864739572b2815ecd3c9df0/ruff-0.9.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5284dcac6b9dbc2fcb71fdfc26a217b2ca4ede6ccd57476f52a587451ebe450d", upload-time = "2025-03-07T15:27:01.385Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/5b/01/85e8082e41585e0e1ceb11e41c054e9e36fed45f4b210991052d8a75089f/ruff-0.9.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47678f39fa2a3da62724851107f438c8229a3470f533894b5568a39b40029c0c", upload-time = "2025-03-07T15:27:04.023Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/a1/90/0bc60bd4e5db051f12445046d0c85cc2c617095c0904f1aa81067dc64aea/ruff-0.9.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99713a6e2766b7a17147b309e8c915b32b07a25c9efd12ada79f217c9c778b3e", upload-time = "2025-03-07T15:27:06.93Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/66/ea/0b7e8c42b1ec608033c4d5a02939c82097ddcb0b3e393e4238584b7054ab/ruff-0.9.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:524ee184d92f7c7304aa568e2db20f50c32d1d0caa235d8ddf10497566ea1a12", upload-time = "2025-03-07T15:27:10.082Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/d5/86/3171d1eff893db4f91755175a6e1163c5887be1f1e2f4f6c0c59527c2bfd/ruff-0.9.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:df92aeac30af821f9acf819fc01b4afc3dfb829d2782884f8739fb52a8119a16", upload-time = "2025-03-07T15:27:12.727Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/89/9e/700ca289f172a38eb0bca752056d0a42637fa17b81649b9331786cb791d7/ruff-0.9.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de42e4edc296f520bb84954eb992a07a0ec5a02fecb834498415908469854a52", upload-time = "2025-03-07T15:27:15.944Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/f2/92/648020b3b5db180f41a931a68b1c8575cca3e63cec86fd26807422a0dbad/ruff-0.9.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d257f95b65806104b6b1ffca0ea53f4ef98454036df65b1eda3693534813ecd1", upload-time = "2025-03-07T15:27:18.996Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/5e/a6/cc472161cd04d30a09d5c90698696b70c169eeba2c41030344194242db45/ruff-0.9.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60dec7201c0b10d6d11be00e8f2dbb6f40ef1828ee75ed739923799513db24c", upload-time = "2025-03-07T15:27:21.655Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/6c/db/d31c361c4025b1b9102b4d032c70a69adb9ee6fde093f6c3bf29f831c85c/ruff-0.9.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d838b60007da7a39c046fcdd317293d10b845001f38bcb55ba766c3875b01e43", upload-time = "2025-03-07T15:27:24.72Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/d1/86/d6374e24a14d4d93ebe120f45edd82ad7dcf3ef999ffc92b197d81cdc2a5/ruff-0.9.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ccaf903108b899beb8e09a63ffae5869057ab649c1e9231c05ae354ebc62066c", upload-time = "2025-03-07T15:27:27.282Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/00/62/a61691f6eaaac1e945a1f3f59f1eea9a218513139d5b6c2b8f88b43b5b8f/ruff-0.9.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f9567d135265d46e59d62dc60c0bfad10e9a6822e231f5b24032dba5a55be6b5", upload-time = "2025-03-07T15:27:30.637Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/ee/94/2c7065e1d92a8a8a46d46d9c3cf07b0aa7e0a1e0153d74baa5e6620b4102/ruff-0.9.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5f202f0d93738c28a89f8ed9eaba01b7be339e5d8d642c994347eaa81c6d75b8", upload-time = "2025-03-07T15:27:33.356Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/a7/8f/1f545ea6f9fcd7bf4368551fb91d2064d8f0577b3079bb3f0ae5779fb773/ruff-0.9.10-py3-none-win32.whl", hash = "sha256:bfb834e87c916521ce46b1788fbb8484966e5113c02df216680102e9eb960029", upload-time = "2025-03-07T15:27:35.994Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/4f/18/fb703603ab108e5c165f52f5b86ee2aa9be43bb781703ec87c66a5f5d604/ruff-0.9.10-py3-none-win_amd64.whl", hash = "sha256:f2160eeef3031bf4b17df74e307d4c5fb689a6f3a26a2de3f7ef4044e3c484f1", upload-time = "2025-03-07T15:27:38.66Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/35/85/338e603dc68e7d9994d5d84f24adbf69bae760ba5efd3e20f5ff2cec18da/ruff-0.9.10-py3-none-win_arm64.whl", hash = "sha256:5fd804c0327a5e5ea26615550e706942f348b197d5475ff34c19733aee4b2e69", upload-time = "2025-03-07T15:27:41.687Z" }, +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/8e/fafaa6f15c332e73425d9c44ada85360501045d5ab0b81400076aff27cf6/ruff-0.9.10.tar.gz", hash = "sha256:9bacb735d7bada9cfb0f2c227d3658fc443d90a727b47f206fb33f52f3c0eac7", upload-time = "2025-03-07T15:27:44.363Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/b2/af7c2cc9e438cbc19fafeec4f20bfcd72165460fe75b2b6e9a0958c8c62b/ruff-0.9.10-py3-none-linux_armv6l.whl", hash = "sha256:eb4d25532cfd9fe461acc83498361ec2e2252795b4f40b17e80692814329e42d", upload-time = "2025-03-07T15:26:51.268Z" }, + { url = "https://files.pythonhosted.org/packages/6d/12/03f6dfa1b95ddd47e6969f0225d60d9d7437c91938a310835feb27927ca0/ruff-0.9.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:188a6638dab1aa9bb6228a7302387b2c9954e455fb25d6b4470cb0641d16759d", upload-time = "2025-03-07T15:26:56.104Z" }, + { url = "https://files.pythonhosted.org/packages/02/49/1c79e0906b6ff551fb0894168763f705bf980864739572b2815ecd3c9df0/ruff-0.9.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5284dcac6b9dbc2fcb71fdfc26a217b2ca4ede6ccd57476f52a587451ebe450d", upload-time = "2025-03-07T15:27:01.385Z" }, + { url = "https://files.pythonhosted.org/packages/5b/01/85e8082e41585e0e1ceb11e41c054e9e36fed45f4b210991052d8a75089f/ruff-0.9.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47678f39fa2a3da62724851107f438c8229a3470f533894b5568a39b40029c0c", upload-time = "2025-03-07T15:27:04.023Z" }, + { url = "https://files.pythonhosted.org/packages/a1/90/0bc60bd4e5db051f12445046d0c85cc2c617095c0904f1aa81067dc64aea/ruff-0.9.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99713a6e2766b7a17147b309e8c915b32b07a25c9efd12ada79f217c9c778b3e", upload-time = "2025-03-07T15:27:06.93Z" }, + { url = "https://files.pythonhosted.org/packages/66/ea/0b7e8c42b1ec608033c4d5a02939c82097ddcb0b3e393e4238584b7054ab/ruff-0.9.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:524ee184d92f7c7304aa568e2db20f50c32d1d0caa235d8ddf10497566ea1a12", upload-time = "2025-03-07T15:27:10.082Z" }, + { url = "https://files.pythonhosted.org/packages/d5/86/3171d1eff893db4f91755175a6e1163c5887be1f1e2f4f6c0c59527c2bfd/ruff-0.9.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:df92aeac30af821f9acf819fc01b4afc3dfb829d2782884f8739fb52a8119a16", upload-time = "2025-03-07T15:27:12.727Z" }, + { url = "https://files.pythonhosted.org/packages/89/9e/700ca289f172a38eb0bca752056d0a42637fa17b81649b9331786cb791d7/ruff-0.9.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de42e4edc296f520bb84954eb992a07a0ec5a02fecb834498415908469854a52", upload-time = "2025-03-07T15:27:15.944Z" }, + { url = "https://files.pythonhosted.org/packages/f2/92/648020b3b5db180f41a931a68b1c8575cca3e63cec86fd26807422a0dbad/ruff-0.9.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d257f95b65806104b6b1ffca0ea53f4ef98454036df65b1eda3693534813ecd1", upload-time = "2025-03-07T15:27:18.996Z" }, + { url = "https://files.pythonhosted.org/packages/5e/a6/cc472161cd04d30a09d5c90698696b70c169eeba2c41030344194242db45/ruff-0.9.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60dec7201c0b10d6d11be00e8f2dbb6f40ef1828ee75ed739923799513db24c", upload-time = "2025-03-07T15:27:21.655Z" }, + { url = "https://files.pythonhosted.org/packages/6c/db/d31c361c4025b1b9102b4d032c70a69adb9ee6fde093f6c3bf29f831c85c/ruff-0.9.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d838b60007da7a39c046fcdd317293d10b845001f38bcb55ba766c3875b01e43", upload-time = "2025-03-07T15:27:24.72Z" }, + { url = "https://files.pythonhosted.org/packages/d1/86/d6374e24a14d4d93ebe120f45edd82ad7dcf3ef999ffc92b197d81cdc2a5/ruff-0.9.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ccaf903108b899beb8e09a63ffae5869057ab649c1e9231c05ae354ebc62066c", upload-time = "2025-03-07T15:27:27.282Z" }, + { url = "https://files.pythonhosted.org/packages/00/62/a61691f6eaaac1e945a1f3f59f1eea9a218513139d5b6c2b8f88b43b5b8f/ruff-0.9.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f9567d135265d46e59d62dc60c0bfad10e9a6822e231f5b24032dba5a55be6b5", upload-time = "2025-03-07T15:27:30.637Z" }, + { url = "https://files.pythonhosted.org/packages/ee/94/2c7065e1d92a8a8a46d46d9c3cf07b0aa7e0a1e0153d74baa5e6620b4102/ruff-0.9.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5f202f0d93738c28a89f8ed9eaba01b7be339e5d8d642c994347eaa81c6d75b8", upload-time = "2025-03-07T15:27:33.356Z" }, + { url = "https://files.pythonhosted.org/packages/a7/8f/1f545ea6f9fcd7bf4368551fb91d2064d8f0577b3079bb3f0ae5779fb773/ruff-0.9.10-py3-none-win32.whl", hash = "sha256:bfb834e87c916521ce46b1788fbb8484966e5113c02df216680102e9eb960029", upload-time = "2025-03-07T15:27:35.994Z" }, + { url = "https://files.pythonhosted.org/packages/4f/18/fb703603ab108e5c165f52f5b86ee2aa9be43bb781703ec87c66a5f5d604/ruff-0.9.10-py3-none-win_amd64.whl", hash = "sha256:f2160eeef3031bf4b17df74e307d4c5fb689a6f3a26a2de3f7ef4044e3c484f1", upload-time = "2025-03-07T15:27:38.66Z" }, + { url = "https://files.pythonhosted.org/packages/35/85/338e603dc68e7d9994d5d84f24adbf69bae760ba5efd3e20f5ff2cec18da/ruff-0.9.10-py3-none-win_arm64.whl", hash = "sha256:5fd804c0327a5e5ea26615550e706942f348b197d5475ff34c19733aee4b2e69", upload-time = "2025-03-07T15:27:41.687Z" }, ] [[package]] name = "scipy" version = "1.15.1" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/76/c6/8eb0654ba0c7d0bb1bf67bf8fbace101a8e4f250f7722371105e8b6f68fc/scipy-1.15.1.tar.gz", hash = "sha256:033a75ddad1463970c96a88063a1df87ccfddd526437136b6ee81ff0312ebdf6", upload-time = "2025-01-11T00:06:16.883Z" } +sdist = { url = "https://files.pythonhosted.org/packages/76/c6/8eb0654ba0c7d0bb1bf67bf8fbace101a8e4f250f7722371105e8b6f68fc/scipy-1.15.1.tar.gz", hash = "sha256:033a75ddad1463970c96a88063a1df87ccfddd526437136b6ee81ff0312ebdf6", upload-time = "2025-01-11T00:06:16.883Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/d8/6e/a9c42d0d39e09ed7fd203d0ac17adfea759cba61ab457671fe66e523dbec/scipy-1.15.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c09aa9d90f3500ea4c9b393ee96f96b0ccb27f2f350d09a47f533293c78ea776", upload-time = "2025-01-11T00:01:53.571Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/04/ee/e3e535c81828618878a7433992fecc92fa4df79393f31a8fea1d05615091/scipy-1.15.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:0ac102ce99934b162914b1e4a6b94ca7da0f4058b6d6fd65b0cef330c0f3346f", upload-time = "2025-01-11T00:02:03.859Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/c4/5e/b1b0124be8e76f87115f16b8915003eec4b7060298117715baf13f51942c/scipy-1.15.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:09c52320c42d7f5c7748b69e9f0389266fd4f82cf34c38485c14ee976cb8cb04", upload-time = "2025-01-11T00:02:12.434Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/14/36/c00cb73eefda85946172c27913ab995c6ad4eee00fa4f007572e8c50cd51/scipy-1.15.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:cdde8414154054763b42b74fe8ce89d7f3d17a7ac5dd77204f0e142cdc9239e9", upload-time = "2025-01-11T00:02:20.237Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/68/94/aff5c51b3799349a9d1e67a056772a0f8a47db371e83b498d43467806557/scipy-1.15.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c9d8fc81d6a3b6844235e6fd175ee1d4c060163905a2becce8e74cb0d7554ce", upload-time = "2025-01-11T00:02:30.21Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/b0/3c/0de11ca154e24a57b579fb648151d901326d3102115bc4f9a7a86526ce54/scipy-1.15.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fb57b30f0017d4afa5fe5f5b150b8f807618819287c21cbe51130de7ccdaed2", upload-time = "2025-01-11T00:02:41.811Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/15/09/472e8d0a6b33199d1bb95e49bedcabc0976c3724edd9b0ef7602ccacf41e/scipy-1.15.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:491d57fe89927fa1aafbe260f4cfa5ffa20ab9f1435025045a5315006a91b8f5", upload-time = "2025-01-11T00:02:53.118Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/ff/ba/31c7a8131152822b3a2cdeba76398ffb404d81d640de98287d236da90c49/scipy-1.15.1-cp312-cp312-win_amd64.whl", hash = "sha256:900f3fa3db87257510f011c292a5779eb627043dd89731b9c461cd16ef76ab3d", upload-time = "2025-01-11T00:03:04.53Z" }, + { url = "https://files.pythonhosted.org/packages/d8/6e/a9c42d0d39e09ed7fd203d0ac17adfea759cba61ab457671fe66e523dbec/scipy-1.15.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c09aa9d90f3500ea4c9b393ee96f96b0ccb27f2f350d09a47f533293c78ea776", upload-time = "2025-01-11T00:01:53.571Z" }, + { url = "https://files.pythonhosted.org/packages/04/ee/e3e535c81828618878a7433992fecc92fa4df79393f31a8fea1d05615091/scipy-1.15.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:0ac102ce99934b162914b1e4a6b94ca7da0f4058b6d6fd65b0cef330c0f3346f", upload-time = "2025-01-11T00:02:03.859Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5e/b1b0124be8e76f87115f16b8915003eec4b7060298117715baf13f51942c/scipy-1.15.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:09c52320c42d7f5c7748b69e9f0389266fd4f82cf34c38485c14ee976cb8cb04", upload-time = "2025-01-11T00:02:12.434Z" }, + { url = "https://files.pythonhosted.org/packages/14/36/c00cb73eefda85946172c27913ab995c6ad4eee00fa4f007572e8c50cd51/scipy-1.15.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:cdde8414154054763b42b74fe8ce89d7f3d17a7ac5dd77204f0e142cdc9239e9", upload-time = "2025-01-11T00:02:20.237Z" }, + { url = "https://files.pythonhosted.org/packages/68/94/aff5c51b3799349a9d1e67a056772a0f8a47db371e83b498d43467806557/scipy-1.15.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c9d8fc81d6a3b6844235e6fd175ee1d4c060163905a2becce8e74cb0d7554ce", upload-time = "2025-01-11T00:02:30.21Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3c/0de11ca154e24a57b579fb648151d901326d3102115bc4f9a7a86526ce54/scipy-1.15.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fb57b30f0017d4afa5fe5f5b150b8f807618819287c21cbe51130de7ccdaed2", upload-time = "2025-01-11T00:02:41.811Z" }, + { url = "https://files.pythonhosted.org/packages/15/09/472e8d0a6b33199d1bb95e49bedcabc0976c3724edd9b0ef7602ccacf41e/scipy-1.15.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:491d57fe89927fa1aafbe260f4cfa5ffa20ab9f1435025045a5315006a91b8f5", upload-time = "2025-01-11T00:02:53.118Z" }, + { url = "https://files.pythonhosted.org/packages/ff/ba/31c7a8131152822b3a2cdeba76398ffb404d81d640de98287d236da90c49/scipy-1.15.1-cp312-cp312-win_amd64.whl", hash = "sha256:900f3fa3db87257510f011c292a5779eb627043dd89731b9c461cd16ef76ab3d", upload-time = "2025-01-11T00:03:04.53Z" }, ] [[package]] name = "setuptools" version = "75.8.2" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/d1/53/43d99d7687e8cdef5ab5f9ec5eaf2c0423c2b35133a2b7e7bc276fc32b21/setuptools-75.8.2.tar.gz", hash = "sha256:4880473a969e5f23f2a2be3646b2dfd84af9028716d398e46192f84bc36900d2", upload-time = "2025-02-26T20:45:19.103Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d1/53/43d99d7687e8cdef5ab5f9ec5eaf2c0423c2b35133a2b7e7bc276fc32b21/setuptools-75.8.2.tar.gz", hash = "sha256:4880473a969e5f23f2a2be3646b2dfd84af9028716d398e46192f84bc36900d2", upload-time = "2025-02-26T20:45:19.103Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/a9/38/7d7362e031bd6dc121e5081d8cb6aa6f6fedf2b67bf889962134c6da4705/setuptools-75.8.2-py3-none-any.whl", hash = "sha256:558e47c15f1811c1fa7adbd0096669bf76c1d3f433f58324df69f3f5ecac4e8f", upload-time = "2025-02-26T20:45:17.259Z" }, + { url = "https://files.pythonhosted.org/packages/a9/38/7d7362e031bd6dc121e5081d8cb6aa6f6fedf2b67bf889962134c6da4705/setuptools-75.8.2-py3-none-any.whl", hash = "sha256:558e47c15f1811c1fa7adbd0096669bf76c1d3f433f58324df69f3f5ecac4e8f", upload-time = "2025-02-26T20:45:17.259Z" }, ] [[package]] name = "six" version = "1.17.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", upload-time = "2024-12-04T17:35:28.174Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", upload-time = "2024-12-04T17:35:28.174Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", upload-time = "2024-12-04T17:35:26.475Z" }, + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", upload-time = "2024-12-04T17:35:26.475Z" }, ] [[package]] name = "tomli" version = "2.4.1" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", upload-time = "2026-03-25T20:22:03.828Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", upload-time = "2026-03-25T20:22:03.828Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", upload-time = "2026-03-25T20:21:21.626Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", upload-time = "2026-03-25T20:21:23.002Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", upload-time = "2026-03-25T20:21:24.04Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", upload-time = "2026-03-25T20:21:25.177Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", upload-time = "2026-03-25T20:21:26.364Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", upload-time = "2026-03-25T20:21:27.46Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", upload-time = "2026-03-25T20:21:28.492Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", upload-time = "2026-03-25T20:21:29.386Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", upload-time = "2026-03-25T20:21:30.677Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", upload-time = "2026-03-25T20:22:03.012Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", upload-time = "2026-03-25T20:21:21.626Z" }, + { url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", upload-time = "2026-03-25T20:21:23.002Z" }, + { url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", upload-time = "2026-03-25T20:21:24.04Z" }, + { url = "https://files.pythonhosted.org/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", upload-time = "2026-03-25T20:21:25.177Z" }, + { url = "https://files.pythonhosted.org/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", upload-time = "2026-03-25T20:21:26.364Z" }, + { url = "https://files.pythonhosted.org/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", upload-time = "2026-03-25T20:21:27.46Z" }, + { url = "https://files.pythonhosted.org/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", upload-time = "2026-03-25T20:21:28.492Z" }, + { url = "https://files.pythonhosted.org/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", upload-time = "2026-03-25T20:21:29.386Z" }, + { url = "https://files.pythonhosted.org/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", upload-time = "2026-03-25T20:21:30.677Z" }, + { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", upload-time = "2026-03-25T20:22:03.012Z" }, ] [[package]] name = "tomli-w" version = "1.2.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/19/75/241269d1da26b624c0d5e110e8149093c759b7a286138f4efd61a60e75fe/tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021", upload-time = "2025-01-15T12:07:24.262Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/19/75/241269d1da26b624c0d5e110e8149093c759b7a286138f4efd61a60e75fe/tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021", upload-time = "2025-01-15T12:07:24.262Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", upload-time = "2025-01-15T12:07:22.074Z" }, + { url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", upload-time = "2025-01-15T12:07:22.074Z" }, ] [[package]] name = "typeapi" version = "2.3.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/d5/92/5a23ad34aa877edf00906166e339bfdc571543ea183ea7ab727bb01516c7/typeapi-2.3.0.tar.gz", hash = "sha256:a60d11f72c5ec27338cfd1c807f035b0b16ed2e3b798fb1c1d34fc5589f544be", upload-time = "2025-10-23T13:44:11.26Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d5/92/5a23ad34aa877edf00906166e339bfdc571543ea183ea7ab727bb01516c7/typeapi-2.3.0.tar.gz", hash = "sha256:a60d11f72c5ec27338cfd1c807f035b0b16ed2e3b798fb1c1d34fc5589f544be", upload-time = "2025-10-23T13:44:11.26Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/d4/84/021bbeb7edb990dd6875cb6ab08d32faaa49fec63453d863730260a01f9e/typeapi-2.3.0-py3-none-any.whl", hash = "sha256:576b7dcb94412e91c5cae107a393674f8f99c10a24beb8be2302e3fed21d5cc2", upload-time = "2025-10-23T13:44:09.833Z" }, + { url = "https://files.pythonhosted.org/packages/d4/84/021bbeb7edb990dd6875cb6ab08d32faaa49fec63453d863730260a01f9e/typeapi-2.3.0-py3-none-any.whl", hash = "sha256:576b7dcb94412e91c5cae107a393674f8f99c10a24beb8be2302e3fed21d5cc2", upload-time = "2025-10-23T13:44:09.833Z" }, ] [[package]] name = "typing-extensions" version = "4.15.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", upload-time = "2025-08-25T13:49:26.313Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", upload-time = "2025-08-25T13:49:26.313Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", upload-time = "2025-08-25T13:49:24.86Z" }, + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", upload-time = "2025-08-25T13:49:24.86Z" }, ] [[package]] name = "typing-inspection" version = "0.4.2" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", upload-time = "2025-10-01T02:14:41.687Z" } +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", upload-time = "2025-10-01T02:14:41.687Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", upload-time = "2025-10-01T02:14:40.154Z" }, + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", upload-time = "2025-10-01T02:14:40.154Z" }, ] [[package]] name = "tzdata" version = "2026.2" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/ba/19/1b9b0e29f30c6d35cb345486df41110984ea67ae69dddbc0e8a100999493/tzdata-2026.2.tar.gz", hash = "sha256:9173fde7d80d9018e02a662e168e5a2d04f87c41ea174b139fbef642eda62d10", upload-time = "2026-04-24T15:22:08.651Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/19/1b9b0e29f30c6d35cb345486df41110984ea67ae69dddbc0e8a100999493/tzdata-2026.2.tar.gz", hash = "sha256:9173fde7d80d9018e02a662e168e5a2d04f87c41ea174b139fbef642eda62d10", upload-time = "2026-04-24T15:22:08.651Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl", hash = "sha256:bbe9af844f658da81a5f95019480da3a89415801f6cc966806612cc7169bffe7", upload-time = "2026-04-24T15:22:05.876Z" }, + { url = "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl", hash = "sha256:bbe9af844f658da81a5f95019480da3a89415801f6cc966806612cc7169bffe7", upload-time = "2026-04-24T15:22:05.876Z" }, ] [[package]] name = "urllib3" version = "2.6.3" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", upload-time = "2026-01-07T16:24:43.925Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", upload-time = "2026-01-07T16:24:43.925Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", upload-time = "2026-01-07T16:24:42.685Z" }, + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", upload-time = "2026-01-07T16:24:42.685Z" }, ] [[package]] name = "virtualenv" version = "21.3.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, { name = "filelock" }, { name = "platformdirs" }, { name = "python-discovery" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/3f/8b/6331f7a7fe70131c301106ec1e7cf23e2501bf7d4ca3636805801ca191bb/virtualenv-21.3.0.tar.gz", hash = "sha256:733750db978ec95c2d8eb4feadaa57091002bce404cb39ba69899cf7bd28944e", upload-time = "2026-04-27T17:05:58.927Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3f/8b/6331f7a7fe70131c301106ec1e7cf23e2501bf7d4ca3636805801ca191bb/virtualenv-21.3.0.tar.gz", hash = "sha256:733750db978ec95c2d8eb4feadaa57091002bce404cb39ba69899cf7bd28944e", upload-time = "2026-04-27T17:05:58.927Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/4b/eb/03bfb1299d4c4510329e470f13f9a4ce793df7fcb5a2fd3510f911066f61/virtualenv-21.3.0-py3-none-any.whl", hash = "sha256:4d28ee41f6d9ec8f1f00cd472b9ffbcedda1b3d3b9a575b5c94a2d004fd51bd7", upload-time = "2026-04-27T17:05:55.468Z" }, + { url = "https://files.pythonhosted.org/packages/4b/eb/03bfb1299d4c4510329e470f13f9a4ce793df7fcb5a2fd3510f911066f61/virtualenv-21.3.0-py3-none-any.whl", hash = "sha256:4d28ee41f6d9ec8f1f00cd472b9ffbcedda1b3d3b9a575b5c94a2d004fd51bd7", upload-time = "2026-04-27T17:05:55.468Z" }, ] [[package]] name = "watchdog" version = "6.0.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", upload-time = "2024-11-01T14:07:13.037Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", upload-time = "2024-11-01T14:07:13.037Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", upload-time = "2024-11-01T14:06:37.745Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", upload-time = "2024-11-01T14:06:39.748Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", upload-time = "2024-11-01T14:06:41.009Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", upload-time = "2024-11-01T14:06:59.472Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", upload-time = "2024-11-01T14:07:01.431Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", upload-time = "2024-11-01T14:07:02.568Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", upload-time = "2024-11-01T14:07:03.893Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", upload-time = "2024-11-01T14:07:05.189Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", upload-time = "2024-11-01T14:07:06.376Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", upload-time = "2024-11-01T14:07:07.547Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", upload-time = "2024-11-01T14:07:09.525Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", upload-time = "2024-11-01T14:07:10.686Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", upload-time = "2024-11-01T14:07:11.845Z" }, + { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", upload-time = "2024-11-01T14:06:37.745Z" }, + { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", upload-time = "2024-11-01T14:06:39.748Z" }, + { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", upload-time = "2024-11-01T14:06:41.009Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", upload-time = "2024-11-01T14:06:59.472Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", upload-time = "2024-11-01T14:07:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", upload-time = "2024-11-01T14:07:02.568Z" }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", upload-time = "2024-11-01T14:07:03.893Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", upload-time = "2024-11-01T14:07:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", upload-time = "2024-11-01T14:07:06.376Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", upload-time = "2024-11-01T14:07:07.547Z" }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", upload-time = "2024-11-01T14:07:09.525Z" }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", upload-time = "2024-11-01T14:07:10.686Z" }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", upload-time = "2024-11-01T14:07:11.845Z" }, ] [[package]] name = "wrapt" version = "2.1.2" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/2e/64/925f213fdcbb9baeb1530449ac71a4d57fc361c053d06bf78d0c5c7cd80c/wrapt-2.1.2.tar.gz", hash = "sha256:3996a67eecc2c68fd47b4e3c564405a5777367adfd9b8abb58387b63ee83b21e", upload-time = "2026-03-06T02:53:25.134Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/64/925f213fdcbb9baeb1530449ac71a4d57fc361c053d06bf78d0c5c7cd80c/wrapt-2.1.2.tar.gz", hash = "sha256:3996a67eecc2c68fd47b4e3c564405a5777367adfd9b8abb58387b63ee83b21e", upload-time = "2026-03-06T02:53:25.134Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/4c/b6/1db817582c49c7fcbb7df6809d0f515af29d7c2fbf57eb44c36e98fb1492/wrapt-2.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ff2aad9c4cda28a8f0653fc2d487596458c2a3f475e56ba02909e950a9efa6a9", upload-time = "2026-03-06T02:52:45.663Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/a2/16/9b02a6b99c09227c93cd4b73acc3678114154ec38da53043c0ddc1fba0dc/wrapt-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6433ea84e1cfacf32021d2a4ee909554ade7fd392caa6f7c13f1f4bf7b8e8748", upload-time = "2026-03-06T02:53:48.728Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/af/aa/ead46a88f9ec3a432a4832dfedb84092fc35af2d0ba40cd04aea3889f247/wrapt-2.1.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c20b757c268d30d6215916a5fa8461048d023865d888e437fab451139cad6c8e", upload-time = "2026-03-06T02:54:40.328Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/3a/9f/742c7c7cdf58b59085a1ee4b6c37b013f66ac33673a7ef4aaed5e992bc33/wrapt-2.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79847b83eb38e70d93dc392c7c5b587efe65b3e7afcc167aa8abd5d60e8761c8", upload-time = "2026-03-06T02:53:26.58Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/e8/44/2c3dd45d53236b7ed7c646fcf212251dc19e48e599debd3926b52310fafb/wrapt-2.1.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f8fba1bae256186a83d1875b2b1f4e2d1242e8fac0f58ec0d7e41b26967b965c", upload-time = "2026-03-06T02:53:11.547Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/74/e2/b17d66abc26bd96f89dec0ecd0ef03da4a1286e6ff793839ec431b9fae57/wrapt-2.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e3d3b35eedcf5f7d022291ecd7533321c4775f7b9cd0050a31a68499ba45757c", upload-time = "2026-03-06T02:54:09.5Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/3c/62/e2977843fdf9f03daf1586a0ff49060b1b2fc7ff85a7ea82b6217c1ae36e/wrapt-2.1.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:6f2c5390460de57fa9582bc8a1b7a6c86e1a41dfad74c5225fc07044c15cc8d1", upload-time = "2026-03-06T02:54:03.884Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/88/dd/27fc67914e68d740bce512f11734aec08696e6b17641fef8867c00c949fc/wrapt-2.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7dfa9f2cf65d027b951d05c662cc99ee3bd01f6e4691ed39848a7a5fffc902b2", upload-time = "2026-03-06T02:53:20.412Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/ec/9f/b750b3692ed2ef4705cb305bd68858e73010492b80e43d2a4faa5573cbe7/wrapt-2.1.2-cp312-cp312-win32.whl", hash = "sha256:eba8155747eb2cae4a0b913d9ebd12a1db4d860fc4c829d7578c7b989bd3f2f0", upload-time = "2026-03-06T02:53:37.732Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/8e/b2/feecfe29f28483d888d76a48f03c4c4d8afea944dbee2b0cd3380f9df032/wrapt-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:1c51c738d7d9faa0b3601708e7e2eda9bf779e1b601dce6c77411f2a1b324a63", upload-time = "2026-03-06T02:52:47.138Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/44/e1/e328f605d6e208547ea9fd120804fcdec68536ac748987a68c47c606eea8/wrapt-2.1.2-cp312-cp312-win_arm64.whl", hash = "sha256:c8e46ae8e4032792eb2f677dbd0d557170a8e5524d22acc55199f43efedd39bf", upload-time = "2026-03-06T02:53:22.053Z" }, - { url = "https://pypi-proxy.cloud.databricks.com/packages/1a/c7/8528ac2dfa2c1e6708f647df7ae144ead13f0a31146f43c7264b4942bf12/wrapt-2.1.2-py3-none-any.whl", hash = "sha256:b8fd6fa2b2c4e7621808f8c62e8317f4aae56e59721ad933bac5239d913cf0e8", upload-time = "2026-03-06T02:53:12.905Z" }, + { url = "https://files.pythonhosted.org/packages/4c/b6/1db817582c49c7fcbb7df6809d0f515af29d7c2fbf57eb44c36e98fb1492/wrapt-2.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ff2aad9c4cda28a8f0653fc2d487596458c2a3f475e56ba02909e950a9efa6a9", upload-time = "2026-03-06T02:52:45.663Z" }, + { url = "https://files.pythonhosted.org/packages/a2/16/9b02a6b99c09227c93cd4b73acc3678114154ec38da53043c0ddc1fba0dc/wrapt-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6433ea84e1cfacf32021d2a4ee909554ade7fd392caa6f7c13f1f4bf7b8e8748", upload-time = "2026-03-06T02:53:48.728Z" }, + { url = "https://files.pythonhosted.org/packages/af/aa/ead46a88f9ec3a432a4832dfedb84092fc35af2d0ba40cd04aea3889f247/wrapt-2.1.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c20b757c268d30d6215916a5fa8461048d023865d888e437fab451139cad6c8e", upload-time = "2026-03-06T02:54:40.328Z" }, + { url = "https://files.pythonhosted.org/packages/3a/9f/742c7c7cdf58b59085a1ee4b6c37b013f66ac33673a7ef4aaed5e992bc33/wrapt-2.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79847b83eb38e70d93dc392c7c5b587efe65b3e7afcc167aa8abd5d60e8761c8", upload-time = "2026-03-06T02:53:26.58Z" }, + { url = "https://files.pythonhosted.org/packages/e8/44/2c3dd45d53236b7ed7c646fcf212251dc19e48e599debd3926b52310fafb/wrapt-2.1.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f8fba1bae256186a83d1875b2b1f4e2d1242e8fac0f58ec0d7e41b26967b965c", upload-time = "2026-03-06T02:53:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/74/e2/b17d66abc26bd96f89dec0ecd0ef03da4a1286e6ff793839ec431b9fae57/wrapt-2.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e3d3b35eedcf5f7d022291ecd7533321c4775f7b9cd0050a31a68499ba45757c", upload-time = "2026-03-06T02:54:09.5Z" }, + { url = "https://files.pythonhosted.org/packages/3c/62/e2977843fdf9f03daf1586a0ff49060b1b2fc7ff85a7ea82b6217c1ae36e/wrapt-2.1.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:6f2c5390460de57fa9582bc8a1b7a6c86e1a41dfad74c5225fc07044c15cc8d1", upload-time = "2026-03-06T02:54:03.884Z" }, + { url = "https://files.pythonhosted.org/packages/88/dd/27fc67914e68d740bce512f11734aec08696e6b17641fef8867c00c949fc/wrapt-2.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7dfa9f2cf65d027b951d05c662cc99ee3bd01f6e4691ed39848a7a5fffc902b2", upload-time = "2026-03-06T02:53:20.412Z" }, + { url = "https://files.pythonhosted.org/packages/ec/9f/b750b3692ed2ef4705cb305bd68858e73010492b80e43d2a4faa5573cbe7/wrapt-2.1.2-cp312-cp312-win32.whl", hash = "sha256:eba8155747eb2cae4a0b913d9ebd12a1db4d860fc4c829d7578c7b989bd3f2f0", upload-time = "2026-03-06T02:53:37.732Z" }, + { url = "https://files.pythonhosted.org/packages/8e/b2/feecfe29f28483d888d76a48f03c4c4d8afea944dbee2b0cd3380f9df032/wrapt-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:1c51c738d7d9faa0b3601708e7e2eda9bf779e1b601dce6c77411f2a1b324a63", upload-time = "2026-03-06T02:52:47.138Z" }, + { url = "https://files.pythonhosted.org/packages/44/e1/e328f605d6e208547ea9fd120804fcdec68536ac748987a68c47c606eea8/wrapt-2.1.2-cp312-cp312-win_arm64.whl", hash = "sha256:c8e46ae8e4032792eb2f677dbd0d557170a8e5524d22acc55199f43efedd39bf", upload-time = "2026-03-06T02:53:22.053Z" }, + { url = "https://files.pythonhosted.org/packages/1a/c7/8528ac2dfa2c1e6708f647df7ae144ead13f0a31146f43c7264b4942bf12/wrapt-2.1.2-py3-none-any.whl", hash = "sha256:b8fd6fa2b2c4e7621808f8c62e8317f4aae56e59721ad933bac5239d913cf0e8", upload-time = "2026-03-06T02:53:12.905Z" }, ] [[package]] name = "yapf" version = "0.43.0" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "platformdirs" }, ] -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/23/97/b6f296d1e9cc1ec25c7604178b48532fa5901f721bcf1b8d8148b13e5588/yapf-0.43.0.tar.gz", hash = "sha256:00d3aa24bfedff9420b2e0d5d9f5ab6d9d4268e72afbf59bb3fa542781d5218e", upload-time = "2024-11-14T00:11:41.584Z" } +sdist = { url = "https://files.pythonhosted.org/packages/23/97/b6f296d1e9cc1ec25c7604178b48532fa5901f721bcf1b8d8148b13e5588/yapf-0.43.0.tar.gz", hash = "sha256:00d3aa24bfedff9420b2e0d5d9f5ab6d9d4268e72afbf59bb3fa542781d5218e", upload-time = "2024-11-14T00:11:41.584Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/37/81/6acd6601f61e31cfb8729d3da6d5df966f80f374b78eff83760714487338/yapf-0.43.0-py3-none-any.whl", hash = "sha256:224faffbc39c428cb095818cf6ef5511fdab6f7430a10783fdfb292ccf2852ca", upload-time = "2024-11-14T00:11:39.37Z" }, + { url = "https://files.pythonhosted.org/packages/37/81/6acd6601f61e31cfb8729d3da6d5df966f80f374b78eff83760714487338/yapf-0.43.0-py3-none-any.whl", hash = "sha256:224faffbc39c428cb095818cf6ef5511fdab6f7430a10783fdfb292ccf2852ca", upload-time = "2024-11-14T00:11:39.37Z" }, ] [[package]] name = "zipp" version = "3.23.1" -source = { registry = "https://pypi-proxy.cloud.databricks.com/simple/" } -sdist = { url = "https://pypi-proxy.cloud.databricks.com/packages/30/21/093488dfc7cc8964ded15ab726fad40f25fd3d788fd741cc1c5a17d78ee8/zipp-3.23.1.tar.gz", hash = "sha256:32120e378d32cd9714ad503c1d024619063ec28aad2248dc6672ad13edfa5110", upload-time = "2026-04-13T23:21:46.6Z" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/21/093488dfc7cc8964ded15ab726fad40f25fd3d788fd741cc1c5a17d78ee8/zipp-3.23.1.tar.gz", hash = "sha256:32120e378d32cd9714ad503c1d024619063ec28aad2248dc6672ad13edfa5110", upload-time = "2026-04-13T23:21:46.6Z" } wheels = [ - { url = "https://pypi-proxy.cloud.databricks.com/packages/08/8a/0861bec20485572fbddf3dfba2910e38fe249796cb73ecdeb74e07eeb8d3/zipp-3.23.1-py3-none-any.whl", hash = "sha256:0b3596c50a5c700c9cb40ba8d86d9f2cc4807e9bedb06bcdf7fac85633e444dc", upload-time = "2026-04-13T23:21:45.386Z" }, + { url = "https://files.pythonhosted.org/packages/08/8a/0861bec20485572fbddf3dfba2910e38fe249796cb73ecdeb74e07eeb8d3/zipp-3.23.1-py3-none-any.whl", hash = "sha256:0b3596c50a5c700c9cb40ba8d86d9f2cc4807e9bedb06bcdf7fac85633e444dc", upload-time = "2026-04-13T23:21:45.386Z" }, ] From 7177e4c8d5203c4598d30761ec489fc20dc9d819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Br=C3=A4uer?= Date: Tue, 4 Aug 2026 14:22:19 +0200 Subject: [PATCH 7/8] renamed and fixes for data source unit tests --- .isaac/config.json | 3 + pyproject.toml | 2 +- .../mdf/KNOWN_LIMITATIONS.md | 2 +- src/impulse_data_sources/mdf/QUICKSTART.md | 4 +- src/impulse_data_sources/mdf/README.md | 10 +- src/impulse_data_sources/mdf/__init__.py | 4 +- src/impulse_data_sources/mdf/arrow_emit.py | 6 +- src/impulse_data_sources/mdf/converter.py | 20 +- src/impulse_data_sources/mdf/datasources.py | 6 +- .../__init__.py | 0 .../mdf/__init__.py | 0 .../mdf/_block_fixtures.py | 0 .../mdf/_mdf_samples.py | 0 .../mdf/test_arrow_emit.py | 10 +- .../mdf/test_bin_packer.py | 8 +- .../mdf/test_datasources.py | 48 +- .../mdf/test_mdf4_reader.py | 24 +- .../mdf/test_mdf_blocks.py | 6 +- .../mdf/test_mdf_coverage_gaps.py | 114 +-- .../mdf/test_mdf_decode.py | 4 +- .../mdf/test_mdf_package.py | 4 +- .../mdf/test_telemetry.py | 4 +- .../mdf/test_unsorted_dg.py | 10 +- tests/impulse_ds/mdf/conftest.py | 36 - uv.lock | 952 ++++++++---------- 25 files changed, 576 insertions(+), 701 deletions(-) create mode 100644 .isaac/config.json rename tests/{impulse_ds => impulse_data_sources}/__init__.py (100%) rename tests/{impulse_ds => impulse_data_sources}/mdf/__init__.py (100%) rename tests/{impulse_ds => impulse_data_sources}/mdf/_block_fixtures.py (100%) rename tests/{impulse_ds => impulse_data_sources}/mdf/_mdf_samples.py (100%) rename tests/{impulse_ds => impulse_data_sources}/mdf/test_arrow_emit.py (93%) rename tests/{impulse_ds => impulse_data_sources}/mdf/test_bin_packer.py (94%) rename tests/{impulse_ds => impulse_data_sources}/mdf/test_datasources.py (92%) rename tests/{impulse_ds => impulse_data_sources}/mdf/test_mdf4_reader.py (95%) rename tests/{impulse_ds => impulse_data_sources}/mdf/test_mdf_blocks.py (97%) rename tests/{impulse_ds => impulse_data_sources}/mdf/test_mdf_coverage_gaps.py (93%) rename tests/{impulse_ds => impulse_data_sources}/mdf/test_mdf_decode.py (98%) rename tests/{impulse_ds => impulse_data_sources}/mdf/test_mdf_package.py (74%) rename tests/{impulse_ds => impulse_data_sources}/mdf/test_telemetry.py (96%) rename tests/{impulse_ds => impulse_data_sources}/mdf/test_unsorted_dg.py (95%) delete mode 100644 tests/impulse_ds/mdf/conftest.py diff --git a/.isaac/config.json b/.isaac/config.json new file mode 100644 index 00000000..a09c3726 --- /dev/null +++ b/.isaac/config.json @@ -0,0 +1,3 @@ +{ + "sync_reminder_last_shown": "2026-08-04" +} \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 91208c6d..20a1f1b7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -138,7 +138,7 @@ ignore = [ convention = "numpy" [tool.ruff.lint.isort] -known-first-party = ["impulse_query_engine", "impulse_reporting", "impulse_ds", "impulse_data_sources"] +known-first-party = ["impulse_query_engine", "impulse_reporting", "impulse_data_sources"] [tool.black] line-length = 99 diff --git a/src/impulse_data_sources/mdf/KNOWN_LIMITATIONS.md b/src/impulse_data_sources/mdf/KNOWN_LIMITATIONS.md index f8b5df69..d222dd14 100644 --- a/src/impulse_data_sources/mdf/KNOWN_LIMITATIONS.md +++ b/src/impulse_data_sources/mdf/KNOWN_LIMITATIONS.md @@ -1,6 +1,6 @@ # Known limitations -`impulse_ds.mdf` is **experimental** and under active development. It does **not** +`impulse_data_sources.mdf` is **experimental** and under active development. It does **not** yet fully implement the [ASAM MDF4](https://www.asam.net/standards/detail/mdf/) specification. Some block types, encodings, compression modes, and edge cases may be missing or behave differently than reference tools. Validate outputs against diff --git a/src/impulse_data_sources/mdf/QUICKSTART.md b/src/impulse_data_sources/mdf/QUICKSTART.md index 1664e1aa..a6d3e2cb 100644 --- a/src/impulse_data_sources/mdf/QUICKSTART.md +++ b/src/impulse_data_sources/mdf/QUICKSTART.md @@ -1,13 +1,13 @@ # MDF data sources — quickstart -Read ASAM MDF4 files as Spark DataFrames. Install the `impulse_ds` package on the +Read ASAM MDF4 files as Spark DataFrames. Install the `impulse_data_sources` package on the cluster, then register the three data sources once per session. ## Setup ```python from databricks.sdk import WorkspaceClient -from impulse_ds.mdf import register_mdf_datasources +from impulse_data_sources.mdf import register_mdf_datasources register_mdf_datasources(spark, WorkspaceClient()) ``` diff --git a/src/impulse_data_sources/mdf/README.md b/src/impulse_data_sources/mdf/README.md index 33655b25..f37ca96a 100644 --- a/src/impulse_data_sources/mdf/README.md +++ b/src/impulse_data_sources/mdf/README.md @@ -1,4 +1,4 @@ -# impulse_ds.mdf +# impulse_data_sources.mdf > ⚠️ **Experimental** — see [KNOWN_LIMITATIONS.md](KNOWN_LIMITATIONS.md) for spec > coverage gaps and backlog items. @@ -38,7 +38,7 @@ import the package). ```python from databricks.sdk import WorkspaceClient -from impulse_ds.mdf import register_mdf_datasources +from impulse_data_sources.mdf import register_mdf_datasources register_mdf_datasources(spark, WorkspaceClient()) @@ -168,7 +168,7 @@ Also works over Databricks Connect (no cluster install needed — uses the `mapInArrow` path with shipped artifacts). ```python -from impulse_ds.mdf import MDFToDeltaConverter +from impulse_data_sources.mdf import MDFToDeltaConverter conv = MDFToDeltaConverter( spark, signals_table="cat.sch.signals", # CLUSTER BY (file_uri, channel_id) @@ -186,7 +186,7 @@ conv.convert_batch(["/Volumes/.../a.mf4", ...]) # many files, sequential ### Low-level reader ```python -from impulse_ds.mdf import MDF4Reader +from impulse_data_sources.mdf import MDF4Reader r = MDF4Reader("/path/drive.mf4") # or MDF4Reader(file_bytes=blob) org = r.scan_channels_organized() # masters / signals / channel_id_map r.read_header_datetime() # measurement start (UTC) @@ -196,7 +196,7 @@ r.read_header_datetime() # measurement start (UTC) ## Module layout -Package path: `src/impulse_ds/mdf/` +Package path: `src/impulse_data_sources/mdf/` | module | responsibility | diff --git a/src/impulse_data_sources/mdf/__init__.py b/src/impulse_data_sources/mdf/__init__.py index 73df758f..f5049a23 100644 --- a/src/impulse_data_sources/mdf/__init__.py +++ b/src/impulse_data_sources/mdf/__init__.py @@ -7,7 +7,7 @@ Public API (lazy-loaded to avoid importing PySpark unless needed):: - from impulse_ds.mdf import ( + from impulse_data_sources.mdf import ( MDFToDeltaConverter, MDF4Reader, register_mdf_datasources, @@ -52,4 +52,4 @@ def __getattr__(name): "MdfMetadataDataSource": MdfMetadataDataSource, "MdfMastersDataSource": MdfMastersDataSource, }[name] - raise AttributeError(f"module 'impulse_ds.mdf' has no attribute {name!r}") + raise AttributeError(f"module 'impulse_data_sources.mdf' has no attribute {name!r}") diff --git a/src/impulse_data_sources/mdf/arrow_emit.py b/src/impulse_data_sources/mdf/arrow_emit.py index a11a24a5..ea22cc8b 100644 --- a/src/impulse_data_sources/mdf/arrow_emit.py +++ b/src/impulse_data_sources/mdf/arrow_emit.py @@ -383,7 +383,7 @@ def convert_spec_to_arrow_batches( import time import logging - log = logging.getLogger("impulse_ds.mdf.convert") + log = logging.getLogger("impulse_data_sources.mdf.convert") _now = time.perf_counter_ns if prof is None: prof = {"read": 0, "decode": 0, "arrow": 0, "rows": 0} @@ -654,7 +654,7 @@ def convert_master_spec_to_arrow_batches(spec, prof=None, time_dtype="float64"): import logging import pyarrow as pa - log = logging.getLogger("impulse_ds.mdf.convert") + log = logging.getLogger("impulse_data_sources.mdf.convert") _now = time.perf_counter_ns if prof is None: prof = {"read": 0, "decode": 0, "arrow": 0, "rows": 0} @@ -762,7 +762,7 @@ def convert_stripe_spec_to_arrow_batches( import time import logging - log = logging.getLogger("impulse_ds.mdf.convert") + log = logging.getLogger("impulse_data_sources.mdf.convert") _now = time.perf_counter_ns if prof is None: prof = {"read": 0, "decode": 0, "arrow": 0, "rows": 0} diff --git a/src/impulse_data_sources/mdf/converter.py b/src/impulse_data_sources/mdf/converter.py index 23473512..7a02e323 100644 --- a/src/impulse_data_sources/mdf/converter.py +++ b/src/impulse_data_sources/mdf/converter.py @@ -30,13 +30,13 @@ def _ensure_artifacts_shipped(spark: SparkSession): - """Ship the impulse_ds.mdf package to Spark workers once per session. + """Ship the impulse_data_sources.mdf package to Spark workers once per session. NOTE: this `addArtifact(pyfile=True)` reaches mapInArrow UDF workers (which import the package at runtime, by-value serialized) but does NOT reach the server's `create_data_source` worker, which deserializes the registered custom data-source class BY REFERENCE and therefore must - `import impulse_ds.mdf` at that point. So the mapInArrow conversion path + `import impulse_data_sources.mdf` at that point. So the mapInArrow conversion path works with only this shipped artifact, while the `mdf_signals`/`mdf_metadata` data sources additionally require the package to be importable cluster-side (e.g. installed as a cluster library). A warm-up mapInArrow was tried and did @@ -50,13 +50,13 @@ def _ensure_artifacts_shipped(spark: SparkSession): import tempfile package_dir = pathlib.Path(__file__).parent - impulse_ds_dir = package_dir.parent - # Ship as a zip to preserve package structure (import impulse_ds.mdf.*) - zip_path = pathlib.Path(tempfile.gettempdir()) / "impulse_ds_mdf.zip" + impulse_data_sources_dir = package_dir.parent + # Ship as a zip to preserve package structure (import impulse_data_sources.mdf.*) + zip_path = pathlib.Path(tempfile.gettempdir()) / "impulse_data_sources_mdf.zip" with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf: - zf.write(impulse_ds_dir / "__init__.py", "impulse_ds/__init__.py") + zf.write(impulse_data_sources_dir / "__init__.py", "impulse_data_sources/__init__.py") for py_file in package_dir.glob("*.py"): - zf.write(py_file, f"impulse_ds/mdf/{py_file.name}") + zf.write(py_file, f"impulse_data_sources/mdf/{py_file.name}") spark.addArtifact(str(zip_path), pyfile=True) _artifacts_shipped = True @@ -291,7 +291,7 @@ def _run_spark_conversion(self, partition_specs: list[dict], mode: str): # Use mapInArrow for zero-copy vectorized conversion. The output schema # follows the dtype carried in the specs (time/value may be float32). # _make_arrow_udf returns a local function that cloudpickle can serialize - # without requiring the impulse_ds.mdf module on workers + # without requiring the impulse_data_sources.mdf module on workers udf_func = _make_arrow_udf() td = partition_specs[0].get("time_dtype", "float64") if partition_specs else "float64" vd = partition_specs[0].get("value_dtype", "float64") if partition_specs else "float64" @@ -429,7 +429,7 @@ def _scan(idx_path): def _make_arrow_udf(): """Return the Arrow UDF with __module__ set so cloudpickle serializes it inline.""" func = _convert_partition_arrow - # Prevent cloudpickle from trying to import impulse_ds.mdf on workers + # Prevent cloudpickle from trying to import impulse_data_sources.mdf on workers func.__module__ = "__main__" func.__qualname__ = "_convert_partition_arrow" return func @@ -567,7 +567,7 @@ def _convert_partition_arrow(batch_iter): signals_arrow_schema, ) - log = logging.getLogger("impulse_ds.mdf.convert") + log = logging.getLogger("impulse_data_sources.mdf.convert") prof = {"read": 0, "decode": 0, "arrow": 0, "rows": 0} for batch in batch_iter: diff --git a/src/impulse_data_sources/mdf/datasources.py b/src/impulse_data_sources/mdf/datasources.py index 4f7b43f5..dcfb1b5c 100644 --- a/src/impulse_data_sources/mdf/datasources.py +++ b/src/impulse_data_sources/mdf/datasources.py @@ -9,7 +9,7 @@ Usage: from databricks.sdk import WorkspaceClient - from impulse_ds.mdf import register_mdf_datasources + from impulse_data_sources.mdf import register_mdf_datasources register_mdf_datasources(spark, WorkspaceClient()) @@ -332,7 +332,7 @@ def read(self, partition): value_dtype=value_dtype, run_length_encoding=run_length_encoding, ) - logging.getLogger("impulse_ds.mdf.convert").warning( + logging.getLogger("impulse_data_sources.mdf.convert").warning( "MDF_PROFILE rows=%d read_ms=%.0f decode_ms=%.0f arrow_ms=%.0f", prof["rows"], prof["read"] / 1e6, @@ -532,7 +532,7 @@ def read(self, partition): time_dtype = str(spec.get("time_dtype", self.options.get("time_dtype", "float64"))) prof = {"read": 0, "decode": 0, "arrow": 0, "rows": 0} yield from convert_master_spec_to_arrow_batches(spec, prof=prof, time_dtype=time_dtype) - logging.getLogger("impulse_ds.mdf.convert").warning( + logging.getLogger("impulse_data_sources.mdf.convert").warning( "MDF_PROFILE(masters) rows=%d read_ms=%.0f decode_ms=%.0f arrow_ms=%.0f", prof["rows"], prof["read"] / 1e6, diff --git a/tests/impulse_ds/__init__.py b/tests/impulse_data_sources/__init__.py similarity index 100% rename from tests/impulse_ds/__init__.py rename to tests/impulse_data_sources/__init__.py diff --git a/tests/impulse_ds/mdf/__init__.py b/tests/impulse_data_sources/mdf/__init__.py similarity index 100% rename from tests/impulse_ds/mdf/__init__.py rename to tests/impulse_data_sources/mdf/__init__.py diff --git a/tests/impulse_ds/mdf/_block_fixtures.py b/tests/impulse_data_sources/mdf/_block_fixtures.py similarity index 100% rename from tests/impulse_ds/mdf/_block_fixtures.py rename to tests/impulse_data_sources/mdf/_block_fixtures.py diff --git a/tests/impulse_ds/mdf/_mdf_samples.py b/tests/impulse_data_sources/mdf/_mdf_samples.py similarity index 100% rename from tests/impulse_ds/mdf/_mdf_samples.py rename to tests/impulse_data_sources/mdf/_mdf_samples.py diff --git a/tests/impulse_ds/mdf/test_arrow_emit.py b/tests/impulse_data_sources/mdf/test_arrow_emit.py similarity index 93% rename from tests/impulse_ds/mdf/test_arrow_emit.py rename to tests/impulse_data_sources/mdf/test_arrow_emit.py index d6557938..0d22a335 100644 --- a/tests/impulse_ds/mdf/test_arrow_emit.py +++ b/tests/impulse_data_sources/mdf/test_arrow_emit.py @@ -1,4 +1,4 @@ -"""Integration tests for impulse_ds.mdf.arrow_emit decode paths.""" +"""Integration tests for impulse_data_sources.mdf.arrow_emit decode paths.""" import os import struct @@ -7,10 +7,10 @@ import numpy as np import pytest -from impulse_ds.mdf.arrow_emit import _rle_compress_chunk, _rle_flush -from impulse_ds.mdf.bin_packer import plan_stripes_for_file -from impulse_ds.mdf.datasources import MdfSignalsReader -from impulse_ds.mdf.udf_helpers import ( +from impulse_data_sources.mdf.arrow_emit import _rle_compress_chunk, _rle_flush +from impulse_data_sources.mdf.bin_packer import plan_stripes_for_file +from impulse_data_sources.mdf.datasources import MdfSignalsReader +from impulse_data_sources.mdf.udf_helpers import ( convert_spec_to_arrow_batches, convert_stripe_spec_to_arrow_batches, ) diff --git a/tests/impulse_ds/mdf/test_bin_packer.py b/tests/impulse_data_sources/mdf/test_bin_packer.py similarity index 94% rename from tests/impulse_ds/mdf/test_bin_packer.py rename to tests/impulse_data_sources/mdf/test_bin_packer.py index 633c31a2..999320e2 100644 --- a/tests/impulse_ds/mdf/test_bin_packer.py +++ b/tests/impulse_data_sources/mdf/test_bin_packer.py @@ -1,13 +1,13 @@ -"""Tests for impulse_ds.mdf.bin_packer partition planners.""" +"""Tests for impulse_data_sources.mdf.bin_packer partition planners.""" import pytest -from impulse_ds.mdf.bin_packer import ( +from impulse_data_sources.mdf.bin_packer import ( plan_master_partitions, plan_partitions, plan_stripes_for_file, ) -from impulse_ds.mdf.mdf4_reader import ChannelInfo, CN_TYPE_MASTER +from impulse_data_sources.mdf.mdf4_reader import ChannelInfo, CN_TYPE_MASTER from ._mdf_samples import sample_mdf_dir @@ -137,7 +137,7 @@ def test_stripes_skip_zero_sample_group(self, monkeypatch): path = f"{d}/{files[0]}" with open(path, "rb") as fh: fb = fh.read() - from impulse_ds.mdf.mdf4_reader import MDF4Reader + from impulse_data_sources.mdf.mdf4_reader import MDF4Reader organized = MDF4Reader(file_bytes=fb).scan_channels_organized() organized = dict(organized) diff --git a/tests/impulse_ds/mdf/test_datasources.py b/tests/impulse_data_sources/mdf/test_datasources.py similarity index 92% rename from tests/impulse_ds/mdf/test_datasources.py rename to tests/impulse_data_sources/mdf/test_datasources.py index 3e5951ec..b594f86f 100644 --- a/tests/impulse_ds/mdf/test_datasources.py +++ b/tests/impulse_data_sources/mdf/test_datasources.py @@ -9,8 +9,8 @@ import pytest import numpy as np -from impulse_ds.mdf.mdf4_reader import MDF4Reader -from impulse_ds.mdf.datasources import ( +from impulse_data_sources.mdf.mdf4_reader import MDF4Reader +from impulse_data_sources.mdf.datasources import ( _resolve_file_list, MdfMetadataReader, MdfSignalsReader, @@ -119,7 +119,7 @@ def test_read_partition(self): assert len(partitions) == 1 rows = list(reader.read(partitions[0])) assert len(rows) > 0 - from impulse_ds.mdf.schemas import METADATA_SCHEMA + from impulse_data_sources.mdf.schemas import METADATA_SCHEMA assert len(rows[0]) == len(METADATA_SCHEMA.fields) # md_comment included ( @@ -197,7 +197,7 @@ def _read(self, opts): def test_rle_schema(self): if not EXAMPLE_FILES: pytest.skip("No example files") - from impulse_ds.mdf.datasources import MdfSignalsDataSource + from impulse_data_sources.mdf.datasources import MdfSignalsDataSource opts = {"path": EXAMPLE_DIR, "files": EXAMPLE_FILES[0], "run_length_encoding": "true"} sch = MdfSignalsDataSource(dict(opts)).schema() @@ -244,7 +244,7 @@ def test_rle_reconstructs_original_and_compresses(self): if not EXAMPLE_FILES: pytest.skip("No example files") from collections import defaultdict - from impulse_ds.mdf.udf_helpers import _rle_run_starts + from impulse_data_sources.mdf.udf_helpers import _rle_run_starts base = {"path": EXAMPLE_DIR, "files": EXAMPLE_FILES[0], "target_partition_mb": "16"} _, plain = self._read(base) @@ -319,12 +319,12 @@ def _read(self, reader, cols): def test_masters_schema_and_grid(self): if not EXAMPLE_FILES: pytest.skip("No example files") - from impulse_ds.mdf.datasources import ( + from impulse_data_sources.mdf.datasources import ( MdfMastersDataSource, MdfMastersReader, MdfSignalsReader, ) - from impulse_ds.mdf.mdf4_reader import MDF4Reader + from impulse_data_sources.mdf.mdf4_reader import MDF4Reader opts = {"path": EXAMPLE_DIR, "files": EXAMPLE_FILES[0], "target_partition_mb": "16"} sch = MdfMastersDataSource(dict(opts)).schema() @@ -346,8 +346,8 @@ def test_masters_schema_and_grid(self): def test_reverse_rle_recovers_originals(self): if not EXAMPLE_FILES: pytest.skip("No example files") - from impulse_ds.mdf.datasources import MdfMastersReader, MdfSignalsReader - from impulse_ds.mdf.mdf4_reader import MDF4Reader + from impulse_data_sources.mdf.datasources import MdfMastersReader, MdfSignalsReader + from impulse_data_sources.mdf.mdf4_reader import MDF4Reader opts = {"path": EXAMPLE_DIR, "files": EXAMPLE_FILES[0], "target_partition_mb": "16"} _, orig = self._read(MdfSignalsReader(opts), ["channel_id", "time", "value"]) @@ -376,7 +376,7 @@ def test_reverse_rle_recovers_originals(self): class TestAbsoluteTime: def _read(self, opts, cols): from collections import defaultdict - from impulse_ds.mdf.datasources import MdfSignalsReader + from impulse_data_sources.mdf.datasources import MdfSignalsReader rd = MdfSignalsReader(opts) out = defaultdict(lambda: defaultdict(list)) @@ -392,7 +392,7 @@ def _read(self, opts, cols): def test_absolute_time_adds_start_and_forces_float64(self): if not EXAMPLE_FILES: pytest.skip("No example files") - from impulse_ds.mdf.datasources import MdfSignalsDataSource + from impulse_data_sources.mdf.datasources import MdfSignalsDataSource f = EXAMPLE_FILES[0] start = MDF4Reader(os.path.join(EXAMPLE_DIR, f)).read_header_start_epoch_seconds() @@ -420,7 +420,7 @@ def test_absolute_time_rle_and_masters_align(self): if not EXAMPLE_FILES: pytest.skip("No example files") from collections import defaultdict - from impulse_ds.mdf.datasources import MdfMastersReader + from impulse_data_sources.mdf.datasources import MdfMastersReader f = EXAMPLE_FILES[0] start = MDF4Reader(os.path.join(EXAMPLE_DIR, f)).read_header_start_epoch_seconds() @@ -455,7 +455,7 @@ def test_all_option_combos_consistent(self): if not EXAMPLE_FILES: pytest.skip("No example files") from itertools import product - from impulse_ds.mdf.datasources import MdfSignalsDataSource + from impulse_data_sources.mdf.datasources import MdfSignalsDataSource spark2arrow = { "double": "double", @@ -504,7 +504,7 @@ def test_all_option_combos_consistent(self): class TestDatasourcesEdgeCases: def test_metadata_read_empty_file_path(self): - from impulse_ds.mdf.datasources import MdfMetadataReader + from impulse_data_sources.mdf.datasources import MdfMetadataReader from pyspark.sql.datasource import InputPartition reader = MdfMetadataReader({"path": "/unused"}) @@ -514,7 +514,7 @@ def test_metadata_read_empty_file_path(self): def test_masters_schema_float32(self): if not EXAMPLE_FILES: pytest.skip("No example files") - from impulse_ds.mdf.datasources import MdfMastersDataSource, MdfMastersReader + from impulse_data_sources.mdf.datasources import MdfMastersDataSource, MdfMastersReader opts = {"path": EXAMPLE_DIR, "files": EXAMPLE_FILES[0], "time_dtype": "float32"} sch = MdfMastersDataSource(dict(opts)).schema() @@ -537,7 +537,7 @@ def test_absolute_time_raises_without_hd_start(self, tmp_path, monkeypatch): mdf.close() monkeypatch.setattr( - "impulse_ds.mdf.mdf4_reader.MDF4Reader.read_header_start_epoch_seconds", + "impulse_data_sources.mdf.mdf4_reader.MDF4Reader.read_header_start_epoch_seconds", lambda _self: None, ) reader = MdfSignalsReader( @@ -549,7 +549,7 @@ def test_absolute_time_raises_without_hd_start(self, tmp_path, monkeypatch): def test_masters_absolute_time_raises_without_hd_start(self, tmp_path, monkeypatch): from asammdf import MDF, Signal import numpy as np - from impulse_ds.mdf.datasources import MdfMastersReader + from impulse_data_sources.mdf.datasources import MdfMastersReader path = tmp_path / "no_start.mf4" mdf = MDF(version="4.10") @@ -559,7 +559,7 @@ def test_masters_absolute_time_raises_without_hd_start(self, tmp_path, monkeypat mdf.close() monkeypatch.setattr( - "impulse_ds.mdf.mdf4_reader.MDF4Reader.read_header_start_epoch_seconds", + "impulse_data_sources.mdf.mdf4_reader.MDF4Reader.read_header_start_epoch_seconds", lambda _self: None, ) reader = MdfMastersReader( @@ -573,7 +573,7 @@ def test_masters_absolute_time_raises_without_hd_start(self, tmp_path, monkeypat reader.partitions() def test_signals_empty_partitions_when_no_signals(self, monkeypatch): - from impulse_ds.mdf.datasources import MdfSignalsReader + from impulse_data_sources.mdf.datasources import MdfSignalsReader def _empty_scan(self): return { @@ -584,11 +584,11 @@ def _empty_scan(self): } monkeypatch.setattr( - "impulse_ds.mdf.datasources._resolve_file_list", + "impulse_data_sources.mdf.datasources._resolve_file_list", lambda _opts: ["/fake/a.mf4"], ) monkeypatch.setattr( - "impulse_ds.mdf.mdf4_reader.MDF4Reader.scan_channels_organized", + "impulse_data_sources.mdf.mdf4_reader.MDF4Reader.scan_channels_organized", _empty_scan, ) reader = MdfSignalsReader({"path": "/x", "files": "a.mf4"}) @@ -598,7 +598,7 @@ def _empty_scan(self): assert list(reader.read(parts[0])) == [] def test_masters_empty_when_no_masters(self, monkeypatch): - from impulse_ds.mdf.datasources import MdfMastersReader + from impulse_data_sources.mdf.datasources import MdfMastersReader def _no_masters(self): return { @@ -609,11 +609,11 @@ def _no_masters(self): } monkeypatch.setattr( - "impulse_ds.mdf.datasources._resolve_file_list", + "impulse_data_sources.mdf.datasources._resolve_file_list", lambda _opts: ["/fake/a.mf4"], ) monkeypatch.setattr( - "impulse_ds.mdf.mdf4_reader.MDF4Reader.scan_channels_organized", + "impulse_data_sources.mdf.mdf4_reader.MDF4Reader.scan_channels_organized", _no_masters, ) reader = MdfMastersReader({"path": "/x", "files": "a.mf4"}) diff --git a/tests/impulse_ds/mdf/test_mdf4_reader.py b/tests/impulse_data_sources/mdf/test_mdf4_reader.py similarity index 95% rename from tests/impulse_ds/mdf/test_mdf4_reader.py rename to tests/impulse_data_sources/mdf/test_mdf4_reader.py index 9c4c0211..199f7a74 100644 --- a/tests/impulse_ds/mdf/test_mdf4_reader.py +++ b/tests/impulse_data_sources/mdf/test_mdf4_reader.py @@ -11,7 +11,7 @@ import pytest import numpy as np -from impulse_ds.mdf.mdf4_reader import MDF4Reader, CN_TYPE_MASTER, CN_TYPE_VIRTUAL_MASTER +from impulse_data_sources.mdf.mdf4_reader import MDF4Reader, CN_TYPE_MASTER, CN_TYPE_VIRTUAL_MASTER from ._mdf_samples import sample_mdf_dir, START_TIME _DIR, _FILES = sample_mdf_dir() @@ -249,7 +249,7 @@ def test_cc_fields_present_on_channel_info(self, mdf_file): assert isinstance(ch.cc_params, tuple) def test_apply_cc_linear(self): - from impulse_ds.mdf.udf_helpers import apply_cc_conversion + from impulse_data_sources.mdf.udf_helpers import apply_cc_conversion raw = np.array([0.0, 1.0, 2.0, 100.0]) # linear: phys = 2.0 * raw + 10.0, params = (b=10.0, a=2.0) @@ -257,7 +257,7 @@ def test_apply_cc_linear(self): np.testing.assert_allclose(result, [10.0, 12.0, 14.0, 210.0]) def test_apply_cc_rational(self): - from impulse_ds.mdf.udf_helpers import apply_cc_conversion + from impulse_data_sources.mdf.udf_helpers import apply_cc_conversion raw = np.array([1.0, 2.0, 10.0]) # rational: (0*X^2 + 2*X + 1) / (0*X^2 + 0*X + 1) = 2*X + 1 @@ -265,14 +265,14 @@ def test_apply_cc_rational(self): np.testing.assert_allclose(result, [3.0, 5.0, 21.0]) def test_apply_cc_identity(self): - from impulse_ds.mdf.udf_helpers import apply_cc_conversion + from impulse_data_sources.mdf.udf_helpers import apply_cc_conversion raw = np.array([42.0, -1.5, 0.0]) result = apply_cc_conversion(raw, 0, ()) np.testing.assert_array_equal(result, raw) def test_apply_cc_tabular_interp(self): - from impulse_ds.mdf.udf_helpers import apply_cc_conversion + from impulse_data_sources.mdf.udf_helpers import apply_cc_conversion # Interleaved per spec: (key_0, val_0, key_1, val_1, key_2, val_2) raw = np.array([0.0, 50.0, 100.0, 150.0, 200.0]) @@ -280,7 +280,7 @@ def test_apply_cc_tabular_interp(self): np.testing.assert_allclose(result, [0.0, 25.0, 50.0, 75.0, 100.0]) def test_apply_cc_no_conversion(self): - from impulse_ds.mdf.udf_helpers import apply_cc_conversion + from impulse_data_sources.mdf.udf_helpers import apply_cc_conversion raw = np.array([1.0, 2.0, 3.0]) result = apply_cc_conversion(raw, -1, ()) @@ -290,7 +290,7 @@ def test_apply_cc_no_conversion(self): def test_virtual_master_cc_applied(self): """Verify CC conversion is applied to virtual master timestamps.""" - from impulse_ds.mdf.udf_helpers import extract_timestamps + from impulse_data_sources.mdf.udf_helpers import extract_timestamps # Simulate raw_data for 5 samples with 8-byte records (any content) raw_data = b"\x00" * 40 @@ -309,7 +309,7 @@ def test_virtual_master_cc_applied(self): def test_virtual_master_no_cc(self): """Virtual master without CC returns raw indices.""" - from impulse_ds.mdf.udf_helpers import extract_timestamps + from impulse_data_sources.mdf.udf_helpers import extract_timestamps raw_data = b"\x00" * 24 record_size = 8 @@ -333,7 +333,7 @@ class TestPlanPartitionsCoalescing: @staticmethod def _ch(gi, ci, samples, addr, ctype=0): - from impulse_ds.mdf.mdf4_reader import ChannelInfo + from impulse_data_sources.mdf.mdf4_reader import ChannelInfo return ChannelInfo( group_idx=gi, @@ -378,7 +378,7 @@ def _layout(self): return masters, signal, cidmap def test_coalesces_and_respects_bounds(self): - from impulse_ds.mdf.bin_packer import plan_partitions + from impulse_data_sources.mdf.bin_packer import plan_partitions masters, signal, cidmap = self._layout() cap = 64 @@ -406,7 +406,7 @@ def test_coalesces_and_respects_bounds(self): assert any("row_start" in s for s in specs) def test_full_channel_coverage_exactly_once(self): - from impulse_ds.mdf.bin_packer import plan_partitions + from impulse_data_sources.mdf.bin_packer import plan_partitions masters, signal, cidmap = self._layout() specs = plan_partitions( @@ -482,7 +482,7 @@ def test_linear_cc_on_sample_c(self): np.testing.assert_allclose(values, np.arange(10) * 2.0 + 10.0) def test_channel_to_dict_unsorted_fields(self): - from impulse_ds.mdf.mdf4_reader import ChannelInfo + from impulse_data_sources.mdf.mdf4_reader import ChannelInfo ch = ChannelInfo( group_idx=0, diff --git a/tests/impulse_ds/mdf/test_mdf_blocks.py b/tests/impulse_data_sources/mdf/test_mdf_blocks.py similarity index 97% rename from tests/impulse_ds/mdf/test_mdf_blocks.py rename to tests/impulse_data_sources/mdf/test_mdf_blocks.py index d0b670bb..49a9b8b0 100644 --- a/tests/impulse_ds/mdf/test_mdf_blocks.py +++ b/tests/impulse_data_sources/mdf/test_mdf_blocks.py @@ -1,4 +1,4 @@ -"""Unit tests for impulse_ds.mdf.mdf_blocks binary I/O.""" +"""Unit tests for impulse_data_sources.mdf.mdf_blocks binary I/O.""" import io import logging @@ -7,7 +7,7 @@ import numpy as np import pytest -from impulse_ds.mdf.mdf_blocks import ( +from impulse_data_sources.mdf.mdf_blocks import ( _collect_dl_block_addrs, _read_block_chunks, _read_dl_blob, @@ -72,7 +72,7 @@ def test_read_raw_data_dz_from_sample_b(self): if not files: pytest.skip("no samples") path = f"{d}/{files[1]}" # sample_b compressed - from impulse_ds.mdf.mdf4_reader import MDF4Reader + from impulse_data_sources.mdf.mdf4_reader import MDF4Reader ch = MDF4Reader(path).scan_metadata()[0] with open(path, "rb") as f: diff --git a/tests/impulse_ds/mdf/test_mdf_coverage_gaps.py b/tests/impulse_data_sources/mdf/test_mdf_coverage_gaps.py similarity index 93% rename from tests/impulse_ds/mdf/test_mdf_coverage_gaps.py rename to tests/impulse_data_sources/mdf/test_mdf_coverage_gaps.py index 8f4b1649..f150c97f 100644 --- a/tests/impulse_ds/mdf/test_mdf_coverage_gaps.py +++ b/tests/impulse_data_sources/mdf/test_mdf_coverage_gaps.py @@ -8,7 +8,7 @@ import numpy as np import pytest -from impulse_ds.mdf.arrow_emit import ( +from impulse_data_sources.mdf.arrow_emit import ( _eq_nan, _emit_prepared_signal_group, _make_signal_emitters, @@ -20,7 +20,7 @@ convert_stripe_spec_to_arrow_batches, signals_arrow_schema, ) -from impulse_ds.mdf.mdf4_reader import ( +from impulse_data_sources.mdf.mdf4_reader import ( BLOCK_ID_CC, BLOCK_ID_HD, ChannelInfo, @@ -28,7 +28,7 @@ CN_TYPE_VIRTUAL_MASTER, MDF4Reader, ) -from impulse_ds.mdf.mdf_blocks import ( +from impulse_data_sources.mdf.mdf_blocks import ( _decompress_subblock_blob, _read_block_chunks, _read_subblock_file, @@ -36,7 +36,7 @@ read_data_list_range, read_raw_data, ) -from impulse_ds.mdf.mdf_decode import ( +from impulse_data_sources.mdf.mdf_decode import ( CC_IDENTITY, CC_LINEAR, CC_RATIONAL, @@ -59,7 +59,7 @@ storage_record_id, unsorted_fields_from_ctx, ) -from impulse_ds.mdf.datasources import MdfMastersReader, MdfSignalsReader +from impulse_data_sources.mdf.datasources import MdfMastersReader, MdfSignalsReader from ._block_fixtures import build_dl_file, make_dt_block, make_dz_block from ._mdf_samples import sample_mdf_dir @@ -359,7 +359,7 @@ def test_stripe_on_compressed_sample(self): path = f"{d}/{files[1]}" with open(path, "rb") as fh: fb = fh.read() - from impulse_ds.mdf.bin_packer import plan_stripes_for_file + from impulse_data_sources.mdf.bin_packer import plan_stripes_for_file specs = plan_stripes_for_file(path, file_bytes=fb, stripe_target_mb=0.001) total = sum(b.num_rows for s in specs for b in convert_stripe_spec_to_arrow_batches(s)) @@ -396,7 +396,7 @@ def test_signals_float32_and_masters_schema(self): d, files = sample_mdf_dir() if not files: pytest.skip("no samples") - from impulse_ds.mdf.datasources import MdfMastersDataSource, MdfSignalsDataSource + from impulse_data_sources.mdf.datasources import MdfMastersDataSource, MdfSignalsDataSource opts = {"path": d, "files": files[0], "time_dtype": "float32", "value_dtype": "float32"} assert MdfSignalsDataSource(opts).schema()["value"].dataType.simpleString() == "float" @@ -540,7 +540,7 @@ def test_sample_d_integer_channels(self): def test_metadata_reader_empty_path(self): from pyspark.sql.datasource import InputPartition - from impulse_ds.mdf.datasources import MdfMetadataReader + from impulse_data_sources.mdf.datasources import MdfMetadataReader reader = MdfMetadataReader({"path": "/tmp", "files": "x.mf4"}) assert list(reader.read(InputPartition({"file_path": ""}))) == [] @@ -555,11 +555,11 @@ def _no_masters(self): } monkeypatch.setattr( - "impulse_ds.mdf.datasources._resolve_file_list", + "impulse_data_sources.mdf.datasources._resolve_file_list", lambda _o: ["/x.mf4"], ) monkeypatch.setattr( - "impulse_ds.mdf.mdf4_reader.MDF4Reader.scan_channels_organized", + "impulse_data_sources.mdf.mdf4_reader.MDF4Reader.scan_channels_organized", _no_masters, ) reader = MdfMastersReader({"path": "/x", "files": "a.mf4"}) @@ -856,7 +856,7 @@ def test_decompress_subblock_dz_transpose_remainder(self): assert out == payload def test_collect_dl_stops_on_non_dl_block(self): - from impulse_ds.mdf.mdf_blocks import _collect_dl_block_addrs + from impulse_data_sources.mdf.mdf_blocks import _collect_dl_block_addrs from ._block_fixtures import make_dl_block bad = b"##XX" + b"\x00" * 20 @@ -869,7 +869,7 @@ def test_collect_dl_stops_on_non_dl_block(self): assert addrs == [len(bad)] def test_read_dl_blob_short_header(self): - from impulse_ds.mdf.mdf_blocks import _read_dl_blob + from impulse_data_sources.mdf.mdf_blocks import _read_dl_blob blob, dl_addr = build_dl_file([struct.pack(" None: - """Attach *mod* on its parent so monkeypatch can resolve dotted paths.""" - parent_name, _, child_name = full_name.rpartition(".") - parent = sys.modules.get(parent_name) - if parent is not None: - setattr(parent, child_name, mod) - - -def _install_impulse_ds_shim() -> None: - if "impulse_ds.mdf" in sys.modules: - return - - impulse_ds = types.ModuleType("impulse_ds") - impulse_ds.__path__ = [] - sys.modules["impulse_ds"] = impulse_ds - - mdf = importlib.import_module("impulse_data_sources.mdf") - sys.modules["impulse_ds.mdf"] = mdf - impulse_ds.mdf = mdf - - for modinfo in pkgutil.walk_packages(mdf.__path__, prefix="impulse_data_sources.mdf."): - alias = modinfo.name.replace("impulse_data_sources", "impulse_ds", 1) - mod = importlib.import_module(modinfo.name) - sys.modules[alias] = mod - _set_parent_attr(alias, mod) - - -_install_impulse_ds_shim() diff --git a/uv.lock b/uv.lock index 2104348b..bcabff91 100644 --- a/uv.lock +++ b/uv.lock @@ -6,11 +6,10 @@ requires-python = "==3.12.*" name = "annotated-types" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", upload-time = "2024-05-20T21:33:25.928Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", upload-time = "2024-05-20T21:33:24.1Z" }, + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, ] - [[package]] name = "asammdf" version = "8.0.1" @@ -32,7 +31,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/44/8c/5b2385bc3b0511a2a96ed8e1643df64dcf190d60cfb95849625a9ab7c8b4/asammdf-8.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a07ebbbf1f4f6f724a2f992eaff809a4f6000e7e9a1796657e9857e589529e57", upload-time = "2024-10-01T13:28:06.293Z" }, { url = "https://files.pythonhosted.org/packages/f4/a9/6ad9208ed9f5ed077dddca45c12b192e3b1c9641e959742cdede549c0e49/asammdf-8.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:d9685e07503671816680b485c7032716acac72fd31e247a6acb059a775cd2100", upload-time = "2024-10-01T13:28:13.363Z" }, ] - [[package]] name = "attrs" version = "26.1.0" @@ -41,7 +39,6 @@ sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c0314 wheels = [ { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", upload-time = "2026-03-19T14:22:23.645Z" }, ] - [[package]] name = "black" version = "26.3.1" @@ -54,16 +51,15 @@ dependencies = [ { name = "platformdirs" }, { name = "pytokens" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e1/c5/61175d618685d42b005847464b8fb4743a67b1b8fdb75e50e5a96c31a27a/black-26.3.1.tar.gz", hash = "sha256:2c50f5063a9641c7eed7795014ba37b0f5fa227f3d408b968936e24bc0566b07", upload-time = "2026-03-12T03:36:03.593Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/c5/61175d618685d42b005847464b8fb4743a67b1b8fdb75e50e5a96c31a27a/black-26.3.1.tar.gz", hash = "sha256:2c50f5063a9641c7eed7795014ba37b0f5fa227f3d408b968936e24bc0566b07", size = 666155, upload-time = "2026-03-12T03:36:03.593Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/f8/da5eae4fc75e78e6dceb60624e1b9662ab00d6b452996046dfa9b8a6025b/black-26.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e6f89631eb88a7302d416594a32faeee9fb8fb848290da9d0a5f2903519fc1", upload-time = "2026-03-12T03:40:13.921Z" }, - { url = "https://files.pythonhosted.org/packages/2c/9f/04e6f26534da2e1629b2b48255c264cabf5eedc5141d04516d9d68a24111/black-26.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41cd2012d35b47d589cb8a16faf8a32ef7a336f56356babd9fcf70939ad1897f", upload-time = "2026-03-12T03:40:15.239Z" }, - { url = "https://files.pythonhosted.org/packages/04/91/a5935b2a63e31b331060c4a9fdb5a6c725840858c599032a6f3aac94055f/black-26.3.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f76ff19ec5297dd8e66eb64deda23631e642c9393ab592826fd4bdc97a4bce7", upload-time = "2026-03-12T03:40:17.124Z" }, - { url = "https://files.pythonhosted.org/packages/e7/0a/86e462cdd311a3c2a8ece708d22aba17d0b2a0d5348ca34b40cdcbea512e/black-26.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:ddb113db38838eb9f043623ba274cfaf7d51d5b0c22ecb30afe58b1bb8322983", upload-time = "2026-03-12T03:40:18.83Z" }, - { url = "https://files.pythonhosted.org/packages/5b/e5/22515a19cb7eaee3440325a6b0d95d2c0e88dd180cb011b12ae488e031d1/black-26.3.1-cp312-cp312-win_arm64.whl", hash = "sha256:dfdd51fc3e64ea4f35873d1b3fb25326773d55d2329ff8449139ebaad7357efb", upload-time = "2026-03-12T03:40:20.425Z" }, - { url = "https://files.pythonhosted.org/packages/8e/0d/52d98722666d6fc6c3dd4c76df339501d6efd40e0ff95e6186a7b7f0befd/black-26.3.1-py3-none-any.whl", hash = "sha256:2bd5aa94fc267d38bb21a70d7410a89f1a1d318841855f698746f8e7f51acd1b", upload-time = "2026-03-12T03:36:01.668Z" }, + { url = "https://files.pythonhosted.org/packages/dc/f8/da5eae4fc75e78e6dceb60624e1b9662ab00d6b452996046dfa9b8a6025b/black-26.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e6f89631eb88a7302d416594a32faeee9fb8fb848290da9d0a5f2903519fc1", size = 1895920, upload-time = "2026-03-12T03:40:13.921Z" }, + { url = "https://files.pythonhosted.org/packages/2c/9f/04e6f26534da2e1629b2b48255c264cabf5eedc5141d04516d9d68a24111/black-26.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41cd2012d35b47d589cb8a16faf8a32ef7a336f56356babd9fcf70939ad1897f", size = 1718499, upload-time = "2026-03-12T03:40:15.239Z" }, + { url = "https://files.pythonhosted.org/packages/04/91/a5935b2a63e31b331060c4a9fdb5a6c725840858c599032a6f3aac94055f/black-26.3.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f76ff19ec5297dd8e66eb64deda23631e642c9393ab592826fd4bdc97a4bce7", size = 1794994, upload-time = "2026-03-12T03:40:17.124Z" }, + { url = "https://files.pythonhosted.org/packages/e7/0a/86e462cdd311a3c2a8ece708d22aba17d0b2a0d5348ca34b40cdcbea512e/black-26.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:ddb113db38838eb9f043623ba274cfaf7d51d5b0c22ecb30afe58b1bb8322983", size = 1420867, upload-time = "2026-03-12T03:40:18.83Z" }, + { url = "https://files.pythonhosted.org/packages/5b/e5/22515a19cb7eaee3440325a6b0d95d2c0e88dd180cb011b12ae488e031d1/black-26.3.1-cp312-cp312-win_arm64.whl", hash = "sha256:dfdd51fc3e64ea4f35873d1b3fb25326773d55d2329ff8449139ebaad7357efb", size = 1230124, upload-time = "2026-03-12T03:40:20.425Z" }, + { url = "https://files.pythonhosted.org/packages/8e/0d/52d98722666d6fc6c3dd4c76df339501d6efd40e0ff95e6186a7b7f0befd/black-26.3.1-py3-none-any.whl", hash = "sha256:2bd5aa94fc267d38bb21a70d7410a89f1a1d318841855f698746f8e7f51acd1b", size = 207542, upload-time = "2026-03-12T03:36:01.668Z" }, ] - [[package]] name = "canmatrix" version = "1.2" @@ -81,16 +77,14 @@ wheels = [ arxml = [ { name = "lxml" }, ] - [[package]] name = "certifi" version = "2026.4.22" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/25/ee/6caf7a40c36a1220410afe15a1cc64993a1f864871f698c0f93acb72842a/certifi-2026.4.22.tar.gz", hash = "sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580", upload-time = "2026-04-22T11:26:11.191Z" } +sdist = { url = "https://files.pythonhosted.org/packages/25/ee/6caf7a40c36a1220410afe15a1cc64993a1f864871f698c0f93acb72842a/certifi-2026.4.22.tar.gz", hash = "sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580", size = 137077, upload-time = "2026-04-22T11:26:11.191Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/22/30/7cd8fdcdfbc5b869528b079bfb76dcdf6056b1a2097a662e5e8c04f42965/certifi-2026.4.22-py3-none-any.whl", hash = "sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a", upload-time = "2026-04-22T11:26:09.372Z" }, + { url = "https://files.pythonhosted.org/packages/22/30/7cd8fdcdfbc5b869528b079bfb76dcdf6056b1a2097a662e5e8c04f42965/certifi-2026.4.22-py3-none-any.whl", hash = "sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a", size = 135707, upload-time = "2026-04-22T11:26:09.372Z" }, ] - [[package]] name = "cffi" version = "2.0.0" @@ -98,56 +92,53 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycparser", marker = "implementation_name != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", upload-time = "2025-09-08T23:24:04.541Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", upload-time = "2025-09-08T23:22:44.795Z" }, - { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", upload-time = "2025-09-08T23:22:45.938Z" }, - { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", upload-time = "2025-09-08T23:22:47.349Z" }, - { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", upload-time = "2025-09-08T23:22:48.677Z" }, - { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", upload-time = "2025-09-08T23:22:50.06Z" }, - { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", upload-time = "2025-09-08T23:22:51.364Z" }, - { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", upload-time = "2025-09-08T23:22:52.902Z" }, - { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", upload-time = "2025-09-08T23:22:54.518Z" }, - { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", upload-time = "2025-09-08T23:22:55.867Z" }, - { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", upload-time = "2025-09-08T23:22:57.188Z" }, - { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", upload-time = "2025-09-08T23:22:58.351Z" }, - { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", upload-time = "2025-09-08T23:22:59.668Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, ] - [[package]] name = "cfgv" version = "3.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", upload-time = "2025-11-19T20:55:51.612Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", upload-time = "2025-11-19T20:55:50.744Z" }, + { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, ] - [[package]] name = "charset-normalizer" version = "3.4.7" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", upload-time = "2026-04-02T09:28:39.342Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", upload-time = "2026-04-02T09:26:24.331Z" }, - { url = "https://files.pythonhosted.org/packages/f8/e3/0fadc706008ac9d7b9b5be6dc767c05f9d3e5df51744ce4cc9605de7b9f4/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", upload-time = "2026-04-02T09:26:25.568Z" }, - { url = "https://files.pythonhosted.org/packages/42/f0/3dd1045c47f4a4604df85ec18ad093912ae1344ac706993aff91d38773a2/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", upload-time = "2026-04-02T09:26:26.865Z" }, - { url = "https://files.pythonhosted.org/packages/dc/67/675a46eb016118a2fbde5a277a5d15f4f69d5f3f5f338e5ee2f8948fcf43/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a", upload-time = "2026-04-02T09:26:28.044Z" }, - { url = "https://files.pythonhosted.org/packages/4b/f8/d0118a2f5f23b02cd166fa385c60f9b0d4f9194f574e2b31cef350ad7223/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116", upload-time = "2026-04-02T09:26:29.239Z" }, - { url = "https://files.pythonhosted.org/packages/b1/f1/6d2b0b261b6c4ceef0fcb0d17a01cc5bc53586c2d4796fa04b5c540bc13d/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb", upload-time = "2026-04-02T09:26:30.5Z" }, - { url = "https://files.pythonhosted.org/packages/6f/c0/7b1f943f7e87cc3db9626ba17807d042c38645f0a1d4415c7a14afb5591f/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1", upload-time = "2026-04-02T09:26:31.709Z" }, - { url = "https://files.pythonhosted.org/packages/38/dd/5a9ab159fe45c6e72079398f277b7d2b523e7f716acc489726115a910097/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15", upload-time = "2026-04-02T09:26:33.282Z" }, - { url = "https://files.pythonhosted.org/packages/d5/ff/531a1cad5ca855d1c1a8b69cb71abfd6d85c0291580146fda7c82857caa1/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5", upload-time = "2026-04-02T09:26:34.845Z" }, - { url = "https://files.pythonhosted.org/packages/c1/4c/a5fb52d528a8ca41f7598cb619409ece30a169fbdf9cdce592e53b46c3a6/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d", upload-time = "2026-04-02T09:26:36.152Z" }, - { url = "https://files.pythonhosted.org/packages/59/7a/071feed8124111a32b316b33ae4de83d36923039ef8cf48120266844285b/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7", upload-time = "2026-04-02T09:26:37.672Z" }, - { url = "https://files.pythonhosted.org/packages/fd/35/f7dba3994312d7ba508e041eaac39a36b120f32d4c8662b8814dab876431/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464", upload-time = "2026-04-02T09:26:38.93Z" }, - { url = "https://files.pythonhosted.org/packages/8a/2d/a572df5c9204ab7688ec1edc895a73ebded3b023bb07364710b05dd1c9be/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49", upload-time = "2026-04-02T09:26:40.17Z" }, - { url = "https://files.pythonhosted.org/packages/86/eb/890922a8b03a568ca2f336c36585a4713c55d4d67bf0f0c78924be6315ca/charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c", upload-time = "2026-04-02T09:26:41.416Z" }, - { url = "https://files.pythonhosted.org/packages/35/d9/0e7dffa06c5ab081f75b1b786f0aefc88365825dfcd0ac544bdb7b2b6853/charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6", upload-time = "2026-04-02T09:26:42.554Z" }, - { url = "https://files.pythonhosted.org/packages/9e/5d/481bcc2a7c88ea6b0878c299547843b2521ccbc40980cb406267088bc701/charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d", upload-time = "2026-04-02T09:26:44.075Z" }, - { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", upload-time = "2026-04-02T09:28:37.794Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", size = 311328, upload-time = "2026-04-02T09:26:24.331Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e3/0fadc706008ac9d7b9b5be6dc767c05f9d3e5df51744ce4cc9605de7b9f4/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", size = 208061, upload-time = "2026-04-02T09:26:25.568Z" }, + { url = "https://files.pythonhosted.org/packages/42/f0/3dd1045c47f4a4604df85ec18ad093912ae1344ac706993aff91d38773a2/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", size = 229031, upload-time = "2026-04-02T09:26:26.865Z" }, + { url = "https://files.pythonhosted.org/packages/dc/67/675a46eb016118a2fbde5a277a5d15f4f69d5f3f5f338e5ee2f8948fcf43/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a", size = 225239, upload-time = "2026-04-02T09:26:28.044Z" }, + { url = "https://files.pythonhosted.org/packages/4b/f8/d0118a2f5f23b02cd166fa385c60f9b0d4f9194f574e2b31cef350ad7223/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116", size = 216589, upload-time = "2026-04-02T09:26:29.239Z" }, + { url = "https://files.pythonhosted.org/packages/b1/f1/6d2b0b261b6c4ceef0fcb0d17a01cc5bc53586c2d4796fa04b5c540bc13d/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb", size = 202733, upload-time = "2026-04-02T09:26:30.5Z" }, + { url = "https://files.pythonhosted.org/packages/6f/c0/7b1f943f7e87cc3db9626ba17807d042c38645f0a1d4415c7a14afb5591f/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1", size = 212652, upload-time = "2026-04-02T09:26:31.709Z" }, + { url = "https://files.pythonhosted.org/packages/38/dd/5a9ab159fe45c6e72079398f277b7d2b523e7f716acc489726115a910097/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15", size = 211229, upload-time = "2026-04-02T09:26:33.282Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ff/531a1cad5ca855d1c1a8b69cb71abfd6d85c0291580146fda7c82857caa1/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5", size = 203552, upload-time = "2026-04-02T09:26:34.845Z" }, + { url = "https://files.pythonhosted.org/packages/c1/4c/a5fb52d528a8ca41f7598cb619409ece30a169fbdf9cdce592e53b46c3a6/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d", size = 230806, upload-time = "2026-04-02T09:26:36.152Z" }, + { url = "https://files.pythonhosted.org/packages/59/7a/071feed8124111a32b316b33ae4de83d36923039ef8cf48120266844285b/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7", size = 212316, upload-time = "2026-04-02T09:26:37.672Z" }, + { url = "https://files.pythonhosted.org/packages/fd/35/f7dba3994312d7ba508e041eaac39a36b120f32d4c8662b8814dab876431/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464", size = 227274, upload-time = "2026-04-02T09:26:38.93Z" }, + { url = "https://files.pythonhosted.org/packages/8a/2d/a572df5c9204ab7688ec1edc895a73ebded3b023bb07364710b05dd1c9be/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49", size = 218468, upload-time = "2026-04-02T09:26:40.17Z" }, + { url = "https://files.pythonhosted.org/packages/86/eb/890922a8b03a568ca2f336c36585a4713c55d4d67bf0f0c78924be6315ca/charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c", size = 148460, upload-time = "2026-04-02T09:26:41.416Z" }, + { url = "https://files.pythonhosted.org/packages/35/d9/0e7dffa06c5ab081f75b1b786f0aefc88365825dfcd0ac544bdb7b2b6853/charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6", size = 159330, upload-time = "2026-04-02T09:26:42.554Z" }, + { url = "https://files.pythonhosted.org/packages/9e/5d/481bcc2a7c88ea6b0878c299547843b2521ccbc40980cb406267088bc701/charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d", size = 147828, upload-time = "2026-04-02T09:26:44.075Z" }, + { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" }, ] - [[package]] name = "click" version = "8.3.3" @@ -155,20 +146,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bb/63/f9e1ea081ce35720d8b92acde70daaedace594dc93b693c869e0d5910718/click-8.3.3.tar.gz", hash = "sha256:398329ad4837b2ff7cbe1dd166a4c0f8900c3ca3a218de04466f38f6497f18a2", upload-time = "2026-04-22T15:11:27.506Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/63/f9e1ea081ce35720d8b92acde70daaedace594dc93b693c869e0d5910718/click-8.3.3.tar.gz", hash = "sha256:398329ad4837b2ff7cbe1dd166a4c0f8900c3ca3a218de04466f38f6497f18a2", size = 328061, upload-time = "2026-04-22T15:11:27.506Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ae/44/c1221527f6a71a01ec6fbad7fa78f1d50dfa02217385cf0fa3eec7087d59/click-8.3.3-py3-none-any.whl", hash = "sha256:a2bf429bb3033c89fa4936ffb35d5cb471e3719e1f3c8a7c3fff0b8314305613", upload-time = "2026-04-22T15:11:25.044Z" }, + { url = "https://files.pythonhosted.org/packages/ae/44/c1221527f6a71a01ec6fbad7fa78f1d50dfa02217385cf0fa3eec7087d59/click-8.3.3-py3-none-any.whl", hash = "sha256:a2bf429bb3033c89fa4936ffb35d5cb471e3719e1f3c8a7c3fff0b8314305613", size = 110502, upload-time = "2026-04-22T15:11:25.044Z" }, ] - [[package]] name = "colorama" version = "0.4.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", upload-time = "2022-10-25T02:36:22.414Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", upload-time = "2022-10-25T02:36:20.889Z" }, + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] - [[package]] name = "contourpy" version = "1.3.3" @@ -176,45 +165,43 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", upload-time = "2025-07-26T12:03:12.549Z" } +sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/be/45/adfee365d9ea3d853550b2e735f9d66366701c65db7855cd07621732ccfc/contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb", upload-time = "2025-07-26T12:01:21.16Z" }, - { url = "https://files.pythonhosted.org/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6", upload-time = "2025-07-26T12:01:22.448Z" }, - { url = "https://files.pythonhosted.org/packages/d4/1c/a12359b9b2ca3a845e8f7f9ac08bdf776114eb931392fcad91743e2ea17b/contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7", upload-time = "2025-07-26T12:01:24.155Z" }, - { url = "https://files.pythonhosted.org/packages/63/12/897aeebfb475b7748ea67b61e045accdfcf0d971f8a588b67108ed7f5512/contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8", upload-time = "2025-07-26T12:01:25.91Z" }, - { url = "https://files.pythonhosted.org/packages/43/8a/a8c584b82deb248930ce069e71576fc09bd7174bbd35183b7943fb1064fd/contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea", upload-time = "2025-07-26T12:01:27.152Z" }, - { url = "https://files.pythonhosted.org/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1", upload-time = "2025-07-26T12:01:28.808Z" }, - { url = "https://files.pythonhosted.org/packages/05/0a/a3fe3be3ee2dceb3e615ebb4df97ae6f3828aa915d3e10549ce016302bd1/contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7", upload-time = "2025-07-26T12:01:31.198Z" }, - { url = "https://files.pythonhosted.org/packages/33/1d/acad9bd4e97f13f3e2b18a3977fe1b4a37ecf3d38d815333980c6c72e963/contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411", upload-time = "2025-07-26T12:01:33.947Z" }, - { url = "https://files.pythonhosted.org/packages/cf/8f/5847f44a7fddf859704217a99a23a4f6417b10e5ab1256a179264561540e/contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69", upload-time = "2025-07-26T12:01:35.64Z" }, - { url = "https://files.pythonhosted.org/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b", upload-time = "2025-07-26T12:01:36.804Z" }, - { url = "https://files.pythonhosted.org/packages/d1/e2/f05240d2c39a1ed228d8328a78b6f44cd695f7ef47beb3e684cf93604f86/contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc", upload-time = "2025-07-26T12:01:37.999Z" }, + { url = "https://files.pythonhosted.org/packages/be/45/adfee365d9ea3d853550b2e735f9d66366701c65db7855cd07621732ccfc/contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb", size = 293419, upload-time = "2025-07-26T12:01:21.16Z" }, + { url = "https://files.pythonhosted.org/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6", size = 273979, upload-time = "2025-07-26T12:01:22.448Z" }, + { url = "https://files.pythonhosted.org/packages/d4/1c/a12359b9b2ca3a845e8f7f9ac08bdf776114eb931392fcad91743e2ea17b/contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7", size = 332653, upload-time = "2025-07-26T12:01:24.155Z" }, + { url = "https://files.pythonhosted.org/packages/63/12/897aeebfb475b7748ea67b61e045accdfcf0d971f8a588b67108ed7f5512/contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8", size = 379536, upload-time = "2025-07-26T12:01:25.91Z" }, + { url = "https://files.pythonhosted.org/packages/43/8a/a8c584b82deb248930ce069e71576fc09bd7174bbd35183b7943fb1064fd/contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea", size = 384397, upload-time = "2025-07-26T12:01:27.152Z" }, + { url = "https://files.pythonhosted.org/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1", size = 362601, upload-time = "2025-07-26T12:01:28.808Z" }, + { url = "https://files.pythonhosted.org/packages/05/0a/a3fe3be3ee2dceb3e615ebb4df97ae6f3828aa915d3e10549ce016302bd1/contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7", size = 1331288, upload-time = "2025-07-26T12:01:31.198Z" }, + { url = "https://files.pythonhosted.org/packages/33/1d/acad9bd4e97f13f3e2b18a3977fe1b4a37ecf3d38d815333980c6c72e963/contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411", size = 1403386, upload-time = "2025-07-26T12:01:33.947Z" }, + { url = "https://files.pythonhosted.org/packages/cf/8f/5847f44a7fddf859704217a99a23a4f6417b10e5ab1256a179264561540e/contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69", size = 185018, upload-time = "2025-07-26T12:01:35.64Z" }, + { url = "https://files.pythonhosted.org/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b", size = 226567, upload-time = "2025-07-26T12:01:36.804Z" }, + { url = "https://files.pythonhosted.org/packages/d1/e2/f05240d2c39a1ed228d8328a78b6f44cd695f7ef47beb3e684cf93604f86/contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc", size = 193655, upload-time = "2025-07-26T12:01:37.999Z" }, ] - [[package]] name = "coverage" version = "7.13.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9d/e0/70553e3000e345daff267cec284ce4cbf3fc141b6da229ac52775b5428f1/coverage-7.13.5.tar.gz", hash = "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179", upload-time = "2026-03-17T10:33:18.341Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/c3/a396306ba7db865bf96fc1fb3b7fd29bcbf3d829df642e77b13555163cd6/coverage-7.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:460cf0114c5016fa841214ff5564aa4864f11948da9440bc97e21ad1f4ba1e01", upload-time = "2026-03-17T10:30:42.208Z" }, - { url = "https://files.pythonhosted.org/packages/a6/16/a68a19e5384e93f811dccc51034b1fd0b865841c390e3c931dcc4699e035/coverage-7.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e223ce4b4ed47f065bfb123687686512e37629be25cc63728557ae7db261422", upload-time = "2026-03-17T10:30:43.906Z" }, - { url = "https://files.pythonhosted.org/packages/29/72/20b917c6793af3a5ceb7fb9c50033f3ec7865f2911a1416b34a7cfa0813b/coverage-7.13.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6e3370441f4513c6252bf042b9c36d22491142385049243253c7e48398a15a9f", upload-time = "2026-03-17T10:30:45.545Z" }, - { url = "https://files.pythonhosted.org/packages/8c/49/cd14b789536ac6a4778c453c6a2338bc0a2fb60c5a5a41b4008328b9acc1/coverage-7.13.5-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:03ccc709a17a1de074fb1d11f217342fb0d2b1582ed544f554fc9fc3f07e95f5", upload-time = "2026-03-17T10:30:47.204Z" }, - { url = "https://files.pythonhosted.org/packages/9d/00/7b0edcfe64e2ed4c0340dac14a52ad0f4c9bd0b8b5e531af7d55b703db7c/coverage-7.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3f4818d065964db3c1c66dc0fbdac5ac692ecbc875555e13374fdbe7eedb4376", upload-time = "2026-03-17T10:30:48.812Z" }, - { url = "https://files.pythonhosted.org/packages/93/89/7ffc4ba0f5d0a55c1e84ea7cee39c9fc06af7b170513d83fbf3bbefce280/coverage-7.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:012d5319e66e9d5a218834642d6c35d265515a62f01157a45bcc036ecf947256", upload-time = "2026-03-17T10:30:50.77Z" }, - { url = "https://files.pythonhosted.org/packages/81/bd/73ddf85f93f7e6fa83e77ccecb6162d9415c79007b4bc124008a4995e4a7/coverage-7.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8dd02af98971bdb956363e4827d34425cb3df19ee550ef92855b0acb9c7ce51c", upload-time = "2026-03-17T10:30:52.5Z" }, - { url = "https://files.pythonhosted.org/packages/a0/81/278aff4e8dec4926a0bcb9486320752811f543a3ce5b602cc7a29978d073/coverage-7.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f08fd75c50a760c7eb068ae823777268daaf16a80b918fa58eea888f8e3919f5", upload-time = "2026-03-17T10:30:54.543Z" }, - { url = "https://files.pythonhosted.org/packages/70/ee/fe1621488e2e0a58d7e94c4800f0d96f79671553488d401a612bebae324b/coverage-7.13.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:843ea8643cf967d1ac7e8ecd4bb00c99135adf4816c0c0593fdcc47b597fcf09", upload-time = "2026-03-17T10:30:56.663Z" }, - { url = "https://files.pythonhosted.org/packages/37/a6/f79fb37aa104b562207cc23cb5711ab6793608e246cae1e93f26b2236ed9/coverage-7.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:9d44d7aa963820b1b971dbecd90bfe5fe8f81cff79787eb6cca15750bd2f79b9", upload-time = "2026-03-17T10:30:58.427Z" }, - { url = "https://files.pythonhosted.org/packages/75/f0/ed15262a58ec81ce457ceb717b7f78752a1713556b19081b76e90896e8d4/coverage-7.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7132bed4bd7b836200c591410ae7d97bf7ae8be6fc87d160b2bd881df929e7bf", upload-time = "2026-03-17T10:31:00.093Z" }, - { url = "https://files.pythonhosted.org/packages/0f/e9/9129958f20e7e9d4d56d51d42ccf708d15cac355ff4ac6e736e97a9393d2/coverage-7.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a698e363641b98843c517817db75373c83254781426e94ada3197cabbc2c919c", upload-time = "2026-03-17T10:31:01.916Z" }, - { url = "https://files.pythonhosted.org/packages/a4/d7/0ad9b15812d81272db94379fe4c6df8fd17781cc7671fdfa30c76ba5ff7b/coverage-7.13.5-cp312-cp312-win32.whl", hash = "sha256:bdba0a6b8812e8c7df002d908a9a2ea3c36e92611b5708633c50869e6d922fdf", upload-time = "2026-03-17T10:31:03.642Z" }, - { url = "https://files.pythonhosted.org/packages/29/3d/821a9a5799fac2556bcf0bd37a70d1d11fa9e49784b6d22e92e8b2f85f18/coverage-7.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:d2c87e0c473a10bffe991502eac389220533024c8082ec1ce849f4218dded810", upload-time = "2026-03-17T10:31:05.651Z" }, - { url = "https://files.pythonhosted.org/packages/d4/fa/2238c2ad08e35cf4f020ea721f717e09ec3152aea75d191a7faf3ef009a8/coverage-7.13.5-cp312-cp312-win_arm64.whl", hash = "sha256:bf69236a9a81bdca3bff53796237aab096cdbf8d78a66ad61e992d9dac7eb2de", upload-time = "2026-03-17T10:31:07.293Z" }, - { url = "https://files.pythonhosted.org/packages/9e/ee/a4cf96b8ce1e566ed238f0659ac2d3f007ed1d14b181bcb684e19561a69a/coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61", upload-time = "2026-03-17T10:33:15.691Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/9d/e0/70553e3000e345daff267cec284ce4cbf3fc141b6da229ac52775b5428f1/coverage-7.13.5.tar.gz", hash = "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179", size = 915967, upload-time = "2026-03-17T10:33:18.341Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/c3/a396306ba7db865bf96fc1fb3b7fd29bcbf3d829df642e77b13555163cd6/coverage-7.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:460cf0114c5016fa841214ff5564aa4864f11948da9440bc97e21ad1f4ba1e01", size = 219554, upload-time = "2026-03-17T10:30:42.208Z" }, + { url = "https://files.pythonhosted.org/packages/a6/16/a68a19e5384e93f811dccc51034b1fd0b865841c390e3c931dcc4699e035/coverage-7.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e223ce4b4ed47f065bfb123687686512e37629be25cc63728557ae7db261422", size = 219908, upload-time = "2026-03-17T10:30:43.906Z" }, + { url = "https://files.pythonhosted.org/packages/29/72/20b917c6793af3a5ceb7fb9c50033f3ec7865f2911a1416b34a7cfa0813b/coverage-7.13.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6e3370441f4513c6252bf042b9c36d22491142385049243253c7e48398a15a9f", size = 251419, upload-time = "2026-03-17T10:30:45.545Z" }, + { url = "https://files.pythonhosted.org/packages/8c/49/cd14b789536ac6a4778c453c6a2338bc0a2fb60c5a5a41b4008328b9acc1/coverage-7.13.5-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:03ccc709a17a1de074fb1d11f217342fb0d2b1582ed544f554fc9fc3f07e95f5", size = 254159, upload-time = "2026-03-17T10:30:47.204Z" }, + { url = "https://files.pythonhosted.org/packages/9d/00/7b0edcfe64e2ed4c0340dac14a52ad0f4c9bd0b8b5e531af7d55b703db7c/coverage-7.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3f4818d065964db3c1c66dc0fbdac5ac692ecbc875555e13374fdbe7eedb4376", size = 255270, upload-time = "2026-03-17T10:30:48.812Z" }, + { url = "https://files.pythonhosted.org/packages/93/89/7ffc4ba0f5d0a55c1e84ea7cee39c9fc06af7b170513d83fbf3bbefce280/coverage-7.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:012d5319e66e9d5a218834642d6c35d265515a62f01157a45bcc036ecf947256", size = 257538, upload-time = "2026-03-17T10:30:50.77Z" }, + { url = "https://files.pythonhosted.org/packages/81/bd/73ddf85f93f7e6fa83e77ccecb6162d9415c79007b4bc124008a4995e4a7/coverage-7.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8dd02af98971bdb956363e4827d34425cb3df19ee550ef92855b0acb9c7ce51c", size = 251821, upload-time = "2026-03-17T10:30:52.5Z" }, + { url = "https://files.pythonhosted.org/packages/a0/81/278aff4e8dec4926a0bcb9486320752811f543a3ce5b602cc7a29978d073/coverage-7.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f08fd75c50a760c7eb068ae823777268daaf16a80b918fa58eea888f8e3919f5", size = 253191, upload-time = "2026-03-17T10:30:54.543Z" }, + { url = "https://files.pythonhosted.org/packages/70/ee/fe1621488e2e0a58d7e94c4800f0d96f79671553488d401a612bebae324b/coverage-7.13.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:843ea8643cf967d1ac7e8ecd4bb00c99135adf4816c0c0593fdcc47b597fcf09", size = 251337, upload-time = "2026-03-17T10:30:56.663Z" }, + { url = "https://files.pythonhosted.org/packages/37/a6/f79fb37aa104b562207cc23cb5711ab6793608e246cae1e93f26b2236ed9/coverage-7.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:9d44d7aa963820b1b971dbecd90bfe5fe8f81cff79787eb6cca15750bd2f79b9", size = 255404, upload-time = "2026-03-17T10:30:58.427Z" }, + { url = "https://files.pythonhosted.org/packages/75/f0/ed15262a58ec81ce457ceb717b7f78752a1713556b19081b76e90896e8d4/coverage-7.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7132bed4bd7b836200c591410ae7d97bf7ae8be6fc87d160b2bd881df929e7bf", size = 250903, upload-time = "2026-03-17T10:31:00.093Z" }, + { url = "https://files.pythonhosted.org/packages/0f/e9/9129958f20e7e9d4d56d51d42ccf708d15cac355ff4ac6e736e97a9393d2/coverage-7.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a698e363641b98843c517817db75373c83254781426e94ada3197cabbc2c919c", size = 252780, upload-time = "2026-03-17T10:31:01.916Z" }, + { url = "https://files.pythonhosted.org/packages/a4/d7/0ad9b15812d81272db94379fe4c6df8fd17781cc7671fdfa30c76ba5ff7b/coverage-7.13.5-cp312-cp312-win32.whl", hash = "sha256:bdba0a6b8812e8c7df002d908a9a2ea3c36e92611b5708633c50869e6d922fdf", size = 222093, upload-time = "2026-03-17T10:31:03.642Z" }, + { url = "https://files.pythonhosted.org/packages/29/3d/821a9a5799fac2556bcf0bd37a70d1d11fa9e49784b6d22e92e8b2f85f18/coverage-7.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:d2c87e0c473a10bffe991502eac389220533024c8082ec1ce849f4218dded810", size = 222900, upload-time = "2026-03-17T10:31:05.651Z" }, + { url = "https://files.pythonhosted.org/packages/d4/fa/2238c2ad08e35cf4f020ea721f717e09ec3152aea75d191a7faf3ef009a8/coverage-7.13.5-cp312-cp312-win_arm64.whl", hash = "sha256:bf69236a9a81bdca3bff53796237aab096cdbf8d78a66ad61e992d9dac7eb2de", size = 221515, upload-time = "2026-03-17T10:31:07.293Z" }, + { url = "https://files.pythonhosted.org/packages/9e/ee/a4cf96b8ce1e566ed238f0659ac2d3f007ed1d14b181bcb684e19561a69a/coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61", size = 211346, upload-time = "2026-03-17T10:33:15.691Z" }, ] - [[package]] name = "cryptography" version = "47.0.0" @@ -222,47 +209,45 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ef/b2/7ffa7fe8207a8c42147ffe70c3e360b228160c1d85dc3faff16aaa3244c0/cryptography-47.0.0.tar.gz", hash = "sha256:9f8e55fe4e63613a5e1cc5819030f27b97742d720203a087802ce4ce9ceb52bb", upload-time = "2026-04-24T19:54:57.056Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/98/40dfe932134bdcae4f6ab5927c87488754bf9eb79297d7e0070b78dd58e9/cryptography-47.0.0-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:160ad728f128972d362e714054f6ba0067cab7fb350c5202a9ae8ae4ce3ef1a0", upload-time = "2026-04-24T19:53:03.864Z" }, - { url = "https://files.pythonhosted.org/packages/34/c6/2733531243fba725f58611b918056b277692f1033373dcc8bd01af1c05d4/cryptography-47.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b9a8943e359b7615db1a3ba587994618e094ff3d6fa5a390c73d079ce18b3973", upload-time = "2026-04-24T19:53:06.909Z" }, - { url = "https://files.pythonhosted.org/packages/00/e3/b27be1a670a9b87f855d211cf0e1174a5d721216b7616bd52d8581d912ed/cryptography-47.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f5c15764f261394b22aef6b00252f5195f46f2ca300bec57149474e2538b31f8", upload-time = "2026-04-24T19:53:09.053Z" }, - { url = "https://files.pythonhosted.org/packages/81/b9/8443cfe5d17d482d348cee7048acf502bb89a51b6382f06240fd290d4ca3/cryptography-47.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9c59ab0e0fa3a180a5a9c59f3a5abe3ef90d474bc56d7fadfbe80359491b615b", upload-time = "2026-04-24T19:53:11.217Z" }, - { url = "https://files.pythonhosted.org/packages/5d/5e/13ed0cdd0eb88ba159d6dd5ebfece8cb901dbcf1ae5ac4072e28b55d3153/cryptography-47.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:34b4358b925a5ea3e14384ca781a2c0ef7ac219b57bb9eacc4457078e2b19f92", upload-time = "2026-04-24T19:53:13.532Z" }, - { url = "https://files.pythonhosted.org/packages/64/16/ed058e1df0f33d440217cd120d41d5dda9dd215a80b8187f68483185af82/cryptography-47.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0024b87d47ae2399165a6bfb20d24888881eeab83ae2566d62467c5ff0030ce7", upload-time = "2026-04-24T19:53:15.618Z" }, - { url = "https://files.pythonhosted.org/packages/02/e0/3d30986b30fdbd9e969abbdf8ba00ed0618615144341faeb57f395a084fe/cryptography-47.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:1e47422b5557bb82d3fff997e8d92cff4e28b9789576984f08c248d2b3535d93", upload-time = "2026-04-24T19:53:17.755Z" }, - { url = "https://files.pythonhosted.org/packages/df/fd/32db38e3ad0cb331f0691cb4c7a8a6f176f679124dee746b3af6633db4d9/cryptography-47.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:6f29f36582e6151d9686235e586dd35bb67491f024767d10b842e520dc6a07ac", upload-time = "2026-04-24T19:53:20.062Z" }, - { url = "https://files.pythonhosted.org/packages/86/53/5395d944dfd48cb1f67917f533c609c34347185ef15eb4308024c876f274/cryptography-47.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:a9b761f012a943b7de0e828843c5688d0de94a0578d44d6c85a1bae32f87791f", upload-time = "2026-04-24T19:53:22.498Z" }, - { url = "https://files.pythonhosted.org/packages/34/4f/e5711b28e1901f7d480a2b1b688b645aa4c77c73f10731ed17e7f7db3f0d/cryptography-47.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4e1de79e047e25d6e9f8cea71c86b4a53aced64134f0f003bbcbf3655fd172c8", upload-time = "2026-04-24T19:53:24.356Z" }, - { url = "https://files.pythonhosted.org/packages/22/22/c8ddc25de3010fc8da447648f5a092c40e7a8fadf01dd6d255d9c0b9373d/cryptography-47.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef6b3634087f18d2155b1e8ce264e5345a753da2c5fa9815e7d41315c90f8318", upload-time = "2026-04-24T19:53:26.665Z" }, - { url = "https://files.pythonhosted.org/packages/66/b6/d4a68f4ea999c6d89e8498579cba1c5fcba4276284de7773b17e4fa69293/cryptography-47.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:11dbb9f50a0f1bb9757b3d8c27c1101780efb8f0bdecfb12439c22a74d64c001", upload-time = "2026-04-24T19:53:28.686Z" }, - { url = "https://files.pythonhosted.org/packages/54/ed/5f524db1fade9c013aa618e1c99c6ed05e8ffc9ceee6cda22fed22dda3f4/cryptography-47.0.0-cp311-abi3-win32.whl", hash = "sha256:7fda2f02c9015db3f42bb8a22324a454516ed10a8c29ca6ece6cdbb5efe2a203", upload-time = "2026-04-24T19:53:31.058Z" }, - { url = "https://files.pythonhosted.org/packages/b2/dc/1b901990b174786569029f67542b3edf72ac068b6c3c8683c17e6a2f5363/cryptography-47.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:f5c3296dab66202f1b18a91fa266be93d6aa0c2806ea3d67762c69f60adc71aa", upload-time = "2026-04-24T19:53:33.054Z" }, - { url = "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:14432c8a9bcb37009784f9594a62fae211a2ae9543e96c92b2a8e4c3cd5cd0c4", upload-time = "2026-04-24T19:54:06.411Z" }, - { url = "https://files.pythonhosted.org/packages/01/64/d7b1e54fdb69f22d24a64bb3e88dc718b31c7fb10ef0b9691a3cf7eeea6e/cryptography-47.0.0-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:07efe86201817e7d3c18781ca9770bc0db04e1e48c994be384e4602bc38f8f27", upload-time = "2026-04-24T19:54:08.519Z" }, - { url = "https://files.pythonhosted.org/packages/8b/7b/cca826391fb2a94efdcdfe4631eb69306ee1cff0b22f664a412c90713877/cryptography-47.0.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2b45761c6ec22b7c726d6a829558777e32d0f1c8be7c3f3480f9c912d5ee8a10", upload-time = "2026-04-24T19:54:10.795Z" }, - { url = "https://files.pythonhosted.org/packages/4c/65/4b57bcc823f42a991627c51c2f68c9fd6eb1393c1756aac876cba2accae2/cryptography-47.0.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:edd4da498015da5b9f26d38d3bfc2e90257bfa9cbed1f6767c282a0025ae649b", upload-time = "2026-04-24T19:54:13.275Z" }, - { url = "https://files.pythonhosted.org/packages/f4/c4/2c5fbeea70adbbca2bbae865e1d605d6a4a7f8dbd9d33eaf69645087f06c/cryptography-47.0.0-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:9af828c0d5a65c70ec729cd7495a4bf1a67ecb66417b8f02ff125ab8a6326a74", upload-time = "2026-04-24T19:54:15.18Z" }, - { url = "https://files.pythonhosted.org/packages/7e/b8/ac57107ef32749d2b244e36069bb688792a363aaaa3acc9e3cf84c130315/cryptography-47.0.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:256d07c78a04d6b276f5df935a9923275f53bd1522f214447fdf365494e2d515", upload-time = "2026-04-24T19:54:17.835Z" }, - { url = "https://files.pythonhosted.org/packages/56/fc/9f1de22ff8be99d991f240a46863c52d475404c408886c5a38d2b5c3bb26/cryptography-47.0.0-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:5d0e362ff51041b0c0d219cc7d6924d7b8996f57ce5712bdcef71eb3c65a59cc", upload-time = "2026-04-24T19:54:19.963Z" }, - { url = "https://files.pythonhosted.org/packages/00/68/d70c852797aa68e8e48d12e5a87170c43f67bb4a59403627259dd57d15de/cryptography-47.0.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:1581aef4219f7ca2849d0250edaa3866212fb74bf5667284f46aa92f9e65c1ca", upload-time = "2026-04-24T19:54:21.818Z" }, - { url = "https://files.pythonhosted.org/packages/a5/51/661cbee74f594c5d97ff82d34f10d5551c085ca4668645f4606ebd22bd5d/cryptography-47.0.0-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:a49a3eb5341b9503fa3000a9a0db033161db90d47285291f53c2a9d2cd1b7f76", upload-time = "2026-04-24T19:54:24.376Z" }, - { url = "https://files.pythonhosted.org/packages/94/87/f2b6c374a82cf076cfa1416992ac8e8ec94d79facc37aec87c1a5cb72352/cryptography-47.0.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:2207a498b03275d0051589e326b79d4cf59985c99031b05bb292ac52631c37fe", upload-time = "2026-04-24T19:54:26.946Z" }, - { url = "https://files.pythonhosted.org/packages/14/e2/8b7462f4acf21ec509616f0245018bb197194ab0b65c2ea21a0bdd53c0eb/cryptography-47.0.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7a02675e2fabd0c0fc04c868b8781863cbf1967691543c22f5470500ff840b31", upload-time = "2026-04-24T19:54:28.926Z" }, - { url = "https://files.pythonhosted.org/packages/70/75/158e494e4c08dc05e039da5bb48553826bd26c23930cf8d3cd5f21fa8921/cryptography-47.0.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80887c5cbd1774683cb126f0ab4184567f080071d5acf62205acb354b4b753b7", upload-time = "2026-04-24T19:54:30.869Z" }, - { url = "https://files.pythonhosted.org/packages/06/bd/0a9d3edbf5eadbac926d7b9b3cd0c4be584eeeae4a003d24d9eda4affbbd/cryptography-47.0.0-cp38-abi3-win32.whl", hash = "sha256:ed67ea4e0cfb5faa5bc7ecb6e2b8838f3807a03758eec239d6c21c8769355310", upload-time = "2026-04-24T19:54:33.494Z" }, - { url = "https://files.pythonhosted.org/packages/60/80/5681af756d0da3a599b7bdb586fac5a1540f1bcefd2717a20e611ddade45/cryptography-47.0.0-cp38-abi3-win_amd64.whl", hash = "sha256:835d2d7f47cdc53b3224e90810fb1d36ca94ea29cc1801fb4c1bc43876735769", upload-time = "2026-04-24T19:54:35.408Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/ef/b2/7ffa7fe8207a8c42147ffe70c3e360b228160c1d85dc3faff16aaa3244c0/cryptography-47.0.0.tar.gz", hash = "sha256:9f8e55fe4e63613a5e1cc5819030f27b97742d720203a087802ce4ce9ceb52bb", size = 830863, upload-time = "2026-04-24T19:54:57.056Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/98/40dfe932134bdcae4f6ab5927c87488754bf9eb79297d7e0070b78dd58e9/cryptography-47.0.0-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:160ad728f128972d362e714054f6ba0067cab7fb350c5202a9ae8ae4ce3ef1a0", size = 7912214, upload-time = "2026-04-24T19:53:03.864Z" }, + { url = "https://files.pythonhosted.org/packages/34/c6/2733531243fba725f58611b918056b277692f1033373dcc8bd01af1c05d4/cryptography-47.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b9a8943e359b7615db1a3ba587994618e094ff3d6fa5a390c73d079ce18b3973", size = 4644617, upload-time = "2026-04-24T19:53:06.909Z" }, + { url = "https://files.pythonhosted.org/packages/00/e3/b27be1a670a9b87f855d211cf0e1174a5d721216b7616bd52d8581d912ed/cryptography-47.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f5c15764f261394b22aef6b00252f5195f46f2ca300bec57149474e2538b31f8", size = 4668186, upload-time = "2026-04-24T19:53:09.053Z" }, + { url = "https://files.pythonhosted.org/packages/81/b9/8443cfe5d17d482d348cee7048acf502bb89a51b6382f06240fd290d4ca3/cryptography-47.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9c59ab0e0fa3a180a5a9c59f3a5abe3ef90d474bc56d7fadfbe80359491b615b", size = 4651244, upload-time = "2026-04-24T19:53:11.217Z" }, + { url = "https://files.pythonhosted.org/packages/5d/5e/13ed0cdd0eb88ba159d6dd5ebfece8cb901dbcf1ae5ac4072e28b55d3153/cryptography-47.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:34b4358b925a5ea3e14384ca781a2c0ef7ac219b57bb9eacc4457078e2b19f92", size = 5252906, upload-time = "2026-04-24T19:53:13.532Z" }, + { url = "https://files.pythonhosted.org/packages/64/16/ed058e1df0f33d440217cd120d41d5dda9dd215a80b8187f68483185af82/cryptography-47.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0024b87d47ae2399165a6bfb20d24888881eeab83ae2566d62467c5ff0030ce7", size = 4701842, upload-time = "2026-04-24T19:53:15.618Z" }, + { url = "https://files.pythonhosted.org/packages/02/e0/3d30986b30fdbd9e969abbdf8ba00ed0618615144341faeb57f395a084fe/cryptography-47.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:1e47422b5557bb82d3fff997e8d92cff4e28b9789576984f08c248d2b3535d93", size = 4289313, upload-time = "2026-04-24T19:53:17.755Z" }, + { url = "https://files.pythonhosted.org/packages/df/fd/32db38e3ad0cb331f0691cb4c7a8a6f176f679124dee746b3af6633db4d9/cryptography-47.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:6f29f36582e6151d9686235e586dd35bb67491f024767d10b842e520dc6a07ac", size = 4650964, upload-time = "2026-04-24T19:53:20.062Z" }, + { url = "https://files.pythonhosted.org/packages/86/53/5395d944dfd48cb1f67917f533c609c34347185ef15eb4308024c876f274/cryptography-47.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:a9b761f012a943b7de0e828843c5688d0de94a0578d44d6c85a1bae32f87791f", size = 5207817, upload-time = "2026-04-24T19:53:22.498Z" }, + { url = "https://files.pythonhosted.org/packages/34/4f/e5711b28e1901f7d480a2b1b688b645aa4c77c73f10731ed17e7f7db3f0d/cryptography-47.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4e1de79e047e25d6e9f8cea71c86b4a53aced64134f0f003bbcbf3655fd172c8", size = 4701544, upload-time = "2026-04-24T19:53:24.356Z" }, + { url = "https://files.pythonhosted.org/packages/22/22/c8ddc25de3010fc8da447648f5a092c40e7a8fadf01dd6d255d9c0b9373d/cryptography-47.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef6b3634087f18d2155b1e8ce264e5345a753da2c5fa9815e7d41315c90f8318", size = 4783536, upload-time = "2026-04-24T19:53:26.665Z" }, + { url = "https://files.pythonhosted.org/packages/66/b6/d4a68f4ea999c6d89e8498579cba1c5fcba4276284de7773b17e4fa69293/cryptography-47.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:11dbb9f50a0f1bb9757b3d8c27c1101780efb8f0bdecfb12439c22a74d64c001", size = 4926106, upload-time = "2026-04-24T19:53:28.686Z" }, + { url = "https://files.pythonhosted.org/packages/54/ed/5f524db1fade9c013aa618e1c99c6ed05e8ffc9ceee6cda22fed22dda3f4/cryptography-47.0.0-cp311-abi3-win32.whl", hash = "sha256:7fda2f02c9015db3f42bb8a22324a454516ed10a8c29ca6ece6cdbb5efe2a203", size = 3258581, upload-time = "2026-04-24T19:53:31.058Z" }, + { url = "https://files.pythonhosted.org/packages/b2/dc/1b901990b174786569029f67542b3edf72ac068b6c3c8683c17e6a2f5363/cryptography-47.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:f5c3296dab66202f1b18a91fa266be93d6aa0c2806ea3d67762c69f60adc71aa", size = 3775309, upload-time = "2026-04-24T19:53:33.054Z" }, + { url = "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:14432c8a9bcb37009784f9594a62fae211a2ae9543e96c92b2a8e4c3cd5cd0c4", size = 7904072, upload-time = "2026-04-24T19:54:06.411Z" }, + { url = "https://files.pythonhosted.org/packages/01/64/d7b1e54fdb69f22d24a64bb3e88dc718b31c7fb10ef0b9691a3cf7eeea6e/cryptography-47.0.0-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:07efe86201817e7d3c18781ca9770bc0db04e1e48c994be384e4602bc38f8f27", size = 4635767, upload-time = "2026-04-24T19:54:08.519Z" }, + { url = "https://files.pythonhosted.org/packages/8b/7b/cca826391fb2a94efdcdfe4631eb69306ee1cff0b22f664a412c90713877/cryptography-47.0.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2b45761c6ec22b7c726d6a829558777e32d0f1c8be7c3f3480f9c912d5ee8a10", size = 4654350, upload-time = "2026-04-24T19:54:10.795Z" }, + { url = "https://files.pythonhosted.org/packages/4c/65/4b57bcc823f42a991627c51c2f68c9fd6eb1393c1756aac876cba2accae2/cryptography-47.0.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:edd4da498015da5b9f26d38d3bfc2e90257bfa9cbed1f6767c282a0025ae649b", size = 4643394, upload-time = "2026-04-24T19:54:13.275Z" }, + { url = "https://files.pythonhosted.org/packages/f4/c4/2c5fbeea70adbbca2bbae865e1d605d6a4a7f8dbd9d33eaf69645087f06c/cryptography-47.0.0-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:9af828c0d5a65c70ec729cd7495a4bf1a67ecb66417b8f02ff125ab8a6326a74", size = 5225777, upload-time = "2026-04-24T19:54:15.18Z" }, + { url = "https://files.pythonhosted.org/packages/7e/b8/ac57107ef32749d2b244e36069bb688792a363aaaa3acc9e3cf84c130315/cryptography-47.0.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:256d07c78a04d6b276f5df935a9923275f53bd1522f214447fdf365494e2d515", size = 4688771, upload-time = "2026-04-24T19:54:17.835Z" }, + { url = "https://files.pythonhosted.org/packages/56/fc/9f1de22ff8be99d991f240a46863c52d475404c408886c5a38d2b5c3bb26/cryptography-47.0.0-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:5d0e362ff51041b0c0d219cc7d6924d7b8996f57ce5712bdcef71eb3c65a59cc", size = 4270753, upload-time = "2026-04-24T19:54:19.963Z" }, + { url = "https://files.pythonhosted.org/packages/00/68/d70c852797aa68e8e48d12e5a87170c43f67bb4a59403627259dd57d15de/cryptography-47.0.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:1581aef4219f7ca2849d0250edaa3866212fb74bf5667284f46aa92f9e65c1ca", size = 4642911, upload-time = "2026-04-24T19:54:21.818Z" }, + { url = "https://files.pythonhosted.org/packages/a5/51/661cbee74f594c5d97ff82d34f10d5551c085ca4668645f4606ebd22bd5d/cryptography-47.0.0-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:a49a3eb5341b9503fa3000a9a0db033161db90d47285291f53c2a9d2cd1b7f76", size = 5181411, upload-time = "2026-04-24T19:54:24.376Z" }, + { url = "https://files.pythonhosted.org/packages/94/87/f2b6c374a82cf076cfa1416992ac8e8ec94d79facc37aec87c1a5cb72352/cryptography-47.0.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:2207a498b03275d0051589e326b79d4cf59985c99031b05bb292ac52631c37fe", size = 4688262, upload-time = "2026-04-24T19:54:26.946Z" }, + { url = "https://files.pythonhosted.org/packages/14/e2/8b7462f4acf21ec509616f0245018bb197194ab0b65c2ea21a0bdd53c0eb/cryptography-47.0.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7a02675e2fabd0c0fc04c868b8781863cbf1967691543c22f5470500ff840b31", size = 4775506, upload-time = "2026-04-24T19:54:28.926Z" }, + { url = "https://files.pythonhosted.org/packages/70/75/158e494e4c08dc05e039da5bb48553826bd26c23930cf8d3cd5f21fa8921/cryptography-47.0.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80887c5cbd1774683cb126f0ab4184567f080071d5acf62205acb354b4b753b7", size = 4912060, upload-time = "2026-04-24T19:54:30.869Z" }, + { url = "https://files.pythonhosted.org/packages/06/bd/0a9d3edbf5eadbac926d7b9b3cd0c4be584eeeae4a003d24d9eda4affbbd/cryptography-47.0.0-cp38-abi3-win32.whl", hash = "sha256:ed67ea4e0cfb5faa5bc7ecb6e2b8838f3807a03758eec239d6c21c8769355310", size = 3248487, upload-time = "2026-04-24T19:54:33.494Z" }, + { url = "https://files.pythonhosted.org/packages/60/80/5681af756d0da3a599b7bdb586fac5a1540f1bcefd2717a20e611ddade45/cryptography-47.0.0-cp38-abi3-win_amd64.whl", hash = "sha256:835d2d7f47cdc53b3224e90810fb1d36ca94ea29cc1801fb4c1bc43876735769", size = 3755737, upload-time = "2026-04-24T19:54:35.408Z" }, ] - [[package]] name = "cycler" version = "0.12.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", upload-time = "2023-10-07T05:32:18.335Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", upload-time = "2023-10-07T05:32:16.783Z" }, + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, ] - [[package]] name = "databind" version = "4.5.4" @@ -274,11 +259,10 @@ dependencies = [ { name = "typeapi" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/71/9e/835a5211eeb7228a0e3870d54def48dd7951dbd951f51b30900020a5f9fc/databind-4.5.4.tar.gz", hash = "sha256:342e170a219b1661e5c1b20778b532aecfa67e46560ba75beb7e2c6faa2150b5", upload-time = "2026-04-02T22:21:47.318Z" } +sdist = { url = "https://files.pythonhosted.org/packages/71/9e/835a5211eeb7228a0e3870d54def48dd7951dbd951f51b30900020a5f9fc/databind-4.5.4.tar.gz", hash = "sha256:342e170a219b1661e5c1b20778b532aecfa67e46560ba75beb7e2c6faa2150b5", size = 43193, upload-time = "2026-04-02T22:21:47.318Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/db/3b8eb860b5baef89b72c7aadcc5072e1648ca0c98d6ba4b9e4eabbdc2cf5/databind-4.5.4-py3-none-any.whl", hash = "sha256:78467f874a3e80bcd1d3de349167587a0d369831bc64c03798520be86074f96e", upload-time = "2026-04-02T22:21:45.389Z" }, + { url = "https://files.pythonhosted.org/packages/e2/db/3b8eb860b5baef89b72c7aadcc5072e1648ca0c98d6ba4b9e4eabbdc2cf5/databind-4.5.4-py3-none-any.whl", hash = "sha256:78467f874a3e80bcd1d3de349167587a0d369831bc64c03798520be86074f96e", size = 52381, upload-time = "2026-04-02T22:21:45.389Z" }, ] - [[package]] name = "databind-core" version = "4.5.4" @@ -286,11 +270,10 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "databind" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9e/dc/b63a6f6a404146e8e3f1226c9243a5cb30784a1f75218d014cafce9a411f/databind_core-4.5.4.tar.gz", hash = "sha256:a7a47af183d4a8046c893fc19fa9c085f287a15e57a05e58345016086ce0f807", upload-time = "2026-04-02T22:21:56.588Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9e/dc/b63a6f6a404146e8e3f1226c9243a5cb30784a1f75218d014cafce9a411f/databind_core-4.5.4.tar.gz", hash = "sha256:a7a47af183d4a8046c893fc19fa9c085f287a15e57a05e58345016086ce0f807", size = 974, upload-time = "2026-04-02T22:21:56.588Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/cf/1d1f4d37b4112f26ea5086d54200837d1dcbddaa536f3a70bb1d8b48ed9a/databind_core-4.5.4-py3-none-any.whl", hash = "sha256:25482c352f4f6fcade7c106c665553a18febeccda2972c00cf5af19f473960ab", upload-time = "2026-04-02T22:21:55.504Z" }, + { url = "https://files.pythonhosted.org/packages/fa/cf/1d1f4d37b4112f26ea5086d54200837d1dcbddaa536f3a70bb1d8b48ed9a/databind_core-4.5.4-py3-none-any.whl", hash = "sha256:25482c352f4f6fcade7c106c665553a18febeccda2972c00cf5af19f473960ab", size = 1666, upload-time = "2026-04-02T22:21:55.504Z" }, ] - [[package]] name = "databind-json" version = "4.5.4" @@ -298,15 +281,15 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "databind" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ab/72/9af59950a23ff6a03062acd85879de289595168ec43d6cec57253d00497c/databind_json-4.5.4.tar.gz", hash = "sha256:2c714f9c3039a81e42fc3826e47d7826ef020d93131c34daf4c9ae0483108e4d", upload-time = "2026-04-02T22:22:05.538Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ab/72/9af59950a23ff6a03062acd85879de289595168ec43d6cec57253d00497c/databind_json-4.5.4.tar.gz", hash = "sha256:2c714f9c3039a81e42fc3826e47d7826ef020d93131c34daf4c9ae0483108e4d", size = 966, upload-time = "2026-04-02T22:22:05.538Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/d4/e00d531202314e29d90c9496f6b4730e3647128b9866180b8ce8ebb79394/databind_json-4.5.4-py3-none-any.whl", hash = "sha256:22e6faaeb6f2ec5cf815fd597a539dfe1f4846b80b618760112f4fe59a0898cc", upload-time = "2026-04-02T22:22:04.204Z" }, + { url = "https://files.pythonhosted.org/packages/b3/d4/e00d531202314e29d90c9496f6b4730e3647128b9866180b8ce8ebb79394/databind_json-4.5.4-py3-none-any.whl", hash = "sha256:22e6faaeb6f2ec5cf815fd597a539dfe1f4846b80b618760112f4fe59a0898cc", size = 1664, upload-time = "2026-04-02T22:22:04.204Z" }, ] - [[package]] name = "databricks-impulse" source = { editable = "." } dependencies = [ + { name = "delta-spark" }, { name = "lz4" }, { name = "nptyping" }, ] @@ -314,7 +297,6 @@ dependencies = [ [package.optional-dependencies] local-dev = [ { name = "databricks-sdk" }, - { name = "delta-spark" }, { name = "matplotlib" }, { name = "pandas" }, { name = "pyarrow" }, @@ -342,7 +324,7 @@ test = [ [package.metadata] requires-dist = [ { name = "databricks-sdk", marker = "extra == 'local-dev'", specifier = "==0.106.0" }, - { name = "delta-spark", marker = "extra == 'local-dev'", specifier = "==4.0.1" }, + { name = "delta-spark", specifier = "==4.0.1" }, { name = "lz4", specifier = "==4.4.5" }, { name = "matplotlib", marker = "extra == 'local-dev'", specifier = "==3.10.0" }, { name = "nptyping", specifier = "==2.5.0" }, @@ -367,7 +349,6 @@ dev = [ { name = "setuptools", specifier = "==75.8.2" }, ] test = [{ name = "asammdf", specifier = "==8.0.1" }] - [[package]] name = "databricks-sdk" version = "0.106.0" @@ -377,11 +358,10 @@ dependencies = [ { name = "protobuf" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b5/b7/ef86e7b8c3d135c844f972e06efb628e147eed0a7b9a0ecbf9511437a3c2/databricks_sdk-0.106.0.tar.gz", hash = "sha256:6bbd492cb8593747aced037b9186f8632e9d553fc358e6f3d83b7e959851d9d3", upload-time = "2026-04-30T12:33:19.601Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/b7/ef86e7b8c3d135c844f972e06efb628e147eed0a7b9a0ecbf9511437a3c2/databricks_sdk-0.106.0.tar.gz", hash = "sha256:6bbd492cb8593747aced037b9186f8632e9d553fc358e6f3d83b7e959851d9d3", size = 930953, upload-time = "2026-04-30T12:33:19.601Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/a9/63b4f6ef3078e4d060faaad85c4e43667189c3429edd68d5cbddc45187ca/databricks_sdk-0.106.0-py3-none-any.whl", hash = "sha256:db9de5566279ae80dfea0ecd37231e8968523ef984e83cbe4bd77e50c59aa6a5", upload-time = "2026-04-30T12:33:18.116Z" }, + { url = "https://files.pythonhosted.org/packages/07/a9/63b4f6ef3078e4d060faaad85c4e43667189c3429edd68d5cbddc45187ca/databricks_sdk-0.106.0-py3-none-any.whl", hash = "sha256:db9de5566279ae80dfea0ecd37231e8968523ef984e83cbe4bd77e50c59aa6a5", size = 879452, upload-time = "2026-04-30T12:33:18.116Z" }, ] - [[package]] name = "delta-spark" version = "4.0.1" @@ -390,11 +370,10 @@ dependencies = [ { name = "importlib-metadata" }, { name = "pyspark" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8f/4d/9670c5b109fb1c7a84814525cb116203cc36a6112eca546785d617f41a08/delta_spark-4.0.1.tar.gz", hash = "sha256:066512d723f615c9a900e1aa4d83bbc7d0f27a1703e1d5dc52606ea51b8733cc", upload-time = "2026-01-10T02:40:50.315Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8f/4d/9670c5b109fb1c7a84814525cb116203cc36a6112eca546785d617f41a08/delta_spark-4.0.1.tar.gz", hash = "sha256:066512d723f615c9a900e1aa4d83bbc7d0f27a1703e1d5dc52606ea51b8733cc", size = 35521, upload-time = "2026-01-10T02:40:50.315Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/13/22/a3716bc5ea86786be5f0afd09f62b20e6a111fa2d78868e930b19367a88c/delta_spark-4.0.1-py3-none-any.whl", hash = "sha256:ae0707eda68f05c6ec20b841c8966bb1201d1a5f124d9e94e8c2232162139be8", upload-time = "2026-01-10T02:40:49.047Z" }, + { url = "https://files.pythonhosted.org/packages/13/22/a3716bc5ea86786be5f0afd09f62b20e6a111fa2d78868e930b19367a88c/delta_spark-4.0.1-py3-none-any.whl", hash = "sha256:ae0707eda68f05c6ec20b841c8966bb1201d1a5f124d9e94e8c2232162139be8", size = 43002, upload-time = "2026-01-10T02:40:49.047Z" }, ] - [[package]] name = "deprecated" version = "1.3.1" @@ -402,20 +381,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", upload-time = "2025-10-30T08:19:02.757Z" } +sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", size = 2932523, upload-time = "2025-10-30T08:19:02.757Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", upload-time = "2025-10-30T08:19:00.758Z" }, + { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298, upload-time = "2025-10-30T08:19:00.758Z" }, ] - [[package]] name = "distlib" version = "0.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", upload-time = "2025-07-17T16:52:00.465Z" } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", upload-time = "2025-07-17T16:51:58.613Z" }, + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, ] - [[package]] name = "docspec" version = "2.2.1" @@ -425,11 +402,10 @@ dependencies = [ { name = "databind-json" }, { name = "deprecated" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3c/39/7a71382107445b2cd50c67c6194e3e584f19748a817c3b29e8be8a14f00f/docspec-2.2.1.tar.gz", hash = "sha256:4854e77edc0e2de40e785e57e95880f7095a05fe978f8b54cef7a269586e15ff", upload-time = "2023-05-28T11:24:18.68Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3c/39/7a71382107445b2cd50c67c6194e3e584f19748a817c3b29e8be8a14f00f/docspec-2.2.1.tar.gz", hash = "sha256:4854e77edc0e2de40e785e57e95880f7095a05fe978f8b54cef7a269586e15ff", size = 8646, upload-time = "2023-05-28T11:24:18.68Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/33/aa/0c9d71cc9d450afd3993d09835e2910810a45b0703f585e1aee1d9b78969/docspec-2.2.1-py3-none-any.whl", hash = "sha256:7538f750095a9688c6980ff9a4e029a823a500f64bd00b6b4bdb27951feb31cb", upload-time = "2023-05-28T11:24:15.419Z" }, + { url = "https://files.pythonhosted.org/packages/33/aa/0c9d71cc9d450afd3993d09835e2910810a45b0703f585e1aee1d9b78969/docspec-2.2.1-py3-none-any.whl", hash = "sha256:7538f750095a9688c6980ff9a4e029a823a500f64bd00b6b4bdb27951feb31cb", size = 9844, upload-time = "2023-05-28T11:24:15.419Z" }, ] - [[package]] name = "docspec-python" version = "2.2.2" @@ -439,43 +415,39 @@ dependencies = [ { name = "docspec" }, { name = "nr-util" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ea/ea/e6d9d9c2f805c6ac8072d0e3ee5b1da2dd61886c662327df937dec9f282c/docspec_python-2.2.2.tar.gz", hash = "sha256:429be834d09549461b95bf45eb53c16859f3dfb3e9220408b3bfb12812ccb3fb", upload-time = "2025-05-06T12:40:33.286Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ea/ea/e6d9d9c2f805c6ac8072d0e3ee5b1da2dd61886c662327df937dec9f282c/docspec_python-2.2.2.tar.gz", hash = "sha256:429be834d09549461b95bf45eb53c16859f3dfb3e9220408b3bfb12812ccb3fb", size = 22154, upload-time = "2025-05-06T12:40:33.286Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/03/c2/b3226746fb6b91893da270a60e77bb420d59cf33a7b9a4e719a236955971/docspec_python-2.2.2-py3-none-any.whl", hash = "sha256:caa32dc1e8c470af8a5ecad67cca614e68c1563ac01dab0c0486c4d7f709d6b1", upload-time = "2025-05-06T12:40:31.554Z" }, + { url = "https://files.pythonhosted.org/packages/03/c2/b3226746fb6b91893da270a60e77bb420d59cf33a7b9a4e719a236955971/docspec_python-2.2.2-py3-none-any.whl", hash = "sha256:caa32dc1e8c470af8a5ecad67cca614e68c1563ac01dab0c0486c4d7f709d6b1", size = 15988, upload-time = "2025-05-06T12:40:31.554Z" }, ] - [[package]] name = "docstring-parser" version = "0.11" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/ce/5d6a3782b9f88097ce3e579265015db3372ae78d12f67629b863a9208c96/docstring_parser-0.11.tar.gz", hash = "sha256:93b3f8f481c7d24e37c5d9f30293c89e2933fa209421c8abd731dd3ef0715ecb", upload-time = "2021-09-30T07:44:10.288Z" } - +sdist = { url = "https://files.pythonhosted.org/packages/a2/ce/5d6a3782b9f88097ce3e579265015db3372ae78d12f67629b863a9208c96/docstring_parser-0.11.tar.gz", hash = "sha256:93b3f8f481c7d24e37c5d9f30293c89e2933fa209421c8abd731dd3ef0715ecb", size = 22775, upload-time = "2021-09-30T07:44:10.288Z" } [[package]] name = "filelock" version = "3.29.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/fe/997687a931ab51049acce6fa1f23e8f01216374ea81374ddee763c493db5/filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90", upload-time = "2026-04-19T15:39:10.068Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/fe/997687a931ab51049acce6fa1f23e8f01216374ea81374ddee763c493db5/filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90", size = 57571, upload-time = "2026-04-19T15:39:10.068Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258", upload-time = "2026-04-19T15:39:08.752Z" }, + { url = "https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258", size = 39812, upload-time = "2026-04-19T15:39:08.752Z" }, ] - [[package]] name = "fonttools" version = "4.62.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9a/08/7012b00a9a5874311b639c3920270c36ee0c445b69d9989a85e5c92ebcb0/fonttools-4.62.1.tar.gz", hash = "sha256:e54c75fd6041f1122476776880f7c3c3295ffa31962dc6ebe2543c00dca58b5d", upload-time = "2026-03-13T13:54:25.52Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/08/7012b00a9a5874311b639c3920270c36ee0c445b69d9989a85e5c92ebcb0/fonttools-4.62.1.tar.gz", hash = "sha256:e54c75fd6041f1122476776880f7c3c3295ffa31962dc6ebe2543c00dca58b5d", size = 3580737, upload-time = "2026-03-13T13:54:25.52Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/47/d4/dbacced3953544b9a93088cc10ef2b596d348c983d5c67a404fa41ec51ba/fonttools-4.62.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:90365821debbd7db678809c7491ca4acd1e0779b9624cdc6ddaf1f31992bf974", upload-time = "2026-03-13T13:52:53.664Z" }, - { url = "https://files.pythonhosted.org/packages/66/9e/a769c8e99b81e5a87ab7e5e7236684de4e96246aae17274e5347d11ebd78/fonttools-4.62.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12859ff0b47dd20f110804c3e0d0970f7b832f561630cd879969011541a464a9", upload-time = "2026-03-13T13:52:56.493Z" }, - { url = "https://files.pythonhosted.org/packages/69/64/f19a9e3911968c37e1e620e14dfc5778299e1474f72f4e57c5ec771d9489/fonttools-4.62.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c125ffa00c3d9003cdaaf7f2c79e6e535628093e14b5de1dccb08859b680936", upload-time = "2026-03-13T13:52:59.179Z" }, - { url = "https://files.pythonhosted.org/packages/9b/8a/99c8b3c3888c5c474c08dbfd7c8899786de9604b727fcefb055b42c84bba/fonttools-4.62.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:149f7d84afca659d1a97e39a4778794a2f83bf344c5ee5134e09995086cc2392", upload-time = "2026-03-13T13:53:02.761Z" }, - { url = "https://files.pythonhosted.org/packages/d1/c6/0f904540d3e6ab463c1243a0d803504826a11604c72dd58c2949796a1762/fonttools-4.62.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0aa72c43a601cfa9273bb1ae0518f1acadc01ee181a6fc60cd758d7fdadffc04", upload-time = "2026-03-13T13:53:05.678Z" }, - { url = "https://files.pythonhosted.org/packages/29/0b/5cbef6588dc9bd6b5c9ad6a4d5a8ca384d0cea089da31711bbeb4f9654a6/fonttools-4.62.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:19177c8d96c7c36359266e571c5173bcee9157b59cfc8cb0153c5673dc5a3a7d", upload-time = "2026-03-13T13:53:08.662Z" }, - { url = "https://files.pythonhosted.org/packages/4a/47/b3a5342d381595ef439adec67848bed561ab7fdb1019fa522e82101b7d9c/fonttools-4.62.1-cp312-cp312-win32.whl", hash = "sha256:a24decd24d60744ee8b4679d38e88b8303d86772053afc29b19d23bb8207803c", upload-time = "2026-03-13T13:53:10.998Z" }, - { url = "https://files.pythonhosted.org/packages/28/b1/0c2ab56a16f409c6c8a68816e6af707827ad5d629634691ff60a52879792/fonttools-4.62.1-cp312-cp312-win_amd64.whl", hash = "sha256:9e7863e10b3de72376280b515d35b14f5eeed639d1aa7824f4cf06779ec65e42", upload-time = "2026-03-13T13:53:13.992Z" }, - { url = "https://files.pythonhosted.org/packages/fd/ba/56147c165442cc5ba7e82ecf301c9a68353cede498185869e6e02b4c264f/fonttools-4.62.1-py3-none-any.whl", hash = "sha256:7487782e2113861f4ddcc07c3436450659e3caa5e470b27dc2177cade2d8e7fd", upload-time = "2026-03-13T13:54:22.735Z" }, + { url = "https://files.pythonhosted.org/packages/47/d4/dbacced3953544b9a93088cc10ef2b596d348c983d5c67a404fa41ec51ba/fonttools-4.62.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:90365821debbd7db678809c7491ca4acd1e0779b9624cdc6ddaf1f31992bf974", size = 2870219, upload-time = "2026-03-13T13:52:53.664Z" }, + { url = "https://files.pythonhosted.org/packages/66/9e/a769c8e99b81e5a87ab7e5e7236684de4e96246aae17274e5347d11ebd78/fonttools-4.62.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12859ff0b47dd20f110804c3e0d0970f7b832f561630cd879969011541a464a9", size = 2414891, upload-time = "2026-03-13T13:52:56.493Z" }, + { url = "https://files.pythonhosted.org/packages/69/64/f19a9e3911968c37e1e620e14dfc5778299e1474f72f4e57c5ec771d9489/fonttools-4.62.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c125ffa00c3d9003cdaaf7f2c79e6e535628093e14b5de1dccb08859b680936", size = 5033197, upload-time = "2026-03-13T13:52:59.179Z" }, + { url = "https://files.pythonhosted.org/packages/9b/8a/99c8b3c3888c5c474c08dbfd7c8899786de9604b727fcefb055b42c84bba/fonttools-4.62.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:149f7d84afca659d1a97e39a4778794a2f83bf344c5ee5134e09995086cc2392", size = 4988768, upload-time = "2026-03-13T13:53:02.761Z" }, + { url = "https://files.pythonhosted.org/packages/d1/c6/0f904540d3e6ab463c1243a0d803504826a11604c72dd58c2949796a1762/fonttools-4.62.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0aa72c43a601cfa9273bb1ae0518f1acadc01ee181a6fc60cd758d7fdadffc04", size = 4971512, upload-time = "2026-03-13T13:53:05.678Z" }, + { url = "https://files.pythonhosted.org/packages/29/0b/5cbef6588dc9bd6b5c9ad6a4d5a8ca384d0cea089da31711bbeb4f9654a6/fonttools-4.62.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:19177c8d96c7c36359266e571c5173bcee9157b59cfc8cb0153c5673dc5a3a7d", size = 5122723, upload-time = "2026-03-13T13:53:08.662Z" }, + { url = "https://files.pythonhosted.org/packages/4a/47/b3a5342d381595ef439adec67848bed561ab7fdb1019fa522e82101b7d9c/fonttools-4.62.1-cp312-cp312-win32.whl", hash = "sha256:a24decd24d60744ee8b4679d38e88b8303d86772053afc29b19d23bb8207803c", size = 2281278, upload-time = "2026-03-13T13:53:10.998Z" }, + { url = "https://files.pythonhosted.org/packages/28/b1/0c2ab56a16f409c6c8a68816e6af707827ad5d629634691ff60a52879792/fonttools-4.62.1-cp312-cp312-win_amd64.whl", hash = "sha256:9e7863e10b3de72376280b515d35b14f5eeed639d1aa7824f4cf06779ec65e42", size = 2331414, upload-time = "2026-03-13T13:53:13.992Z" }, + { url = "https://files.pythonhosted.org/packages/fd/ba/56147c165442cc5ba7e82ecf301c9a68353cede498185869e6e02b4c264f/fonttools-4.62.1-py3-none-any.whl", hash = "sha256:7487782e2113861f4ddcc07c3436450659e3caa5e470b27dc2177cade2d8e7fd", size = 1152647, upload-time = "2026-03-13T13:54:22.735Z" }, ] - [[package]] name = "google-auth" version = "2.49.2" @@ -484,29 +456,26 @@ dependencies = [ { name = "cryptography" }, { name = "pyasn1-modules" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c6/fc/e925290a1ad95c975c459e2df070fac2b90954e13a0370ac505dff78cb99/google_auth-2.49.2.tar.gz", hash = "sha256:c1ae38500e73065dcae57355adb6278cf8b5c8e391994ae9cbadbcb9631ab409", upload-time = "2026-04-10T00:41:21.888Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c6/fc/e925290a1ad95c975c459e2df070fac2b90954e13a0370ac505dff78cb99/google_auth-2.49.2.tar.gz", hash = "sha256:c1ae38500e73065dcae57355adb6278cf8b5c8e391994ae9cbadbcb9631ab409", size = 333958, upload-time = "2026-04-10T00:41:21.888Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/76/d241a5c927433420507215df6cac1b1fa4ac0ba7a794df42a84326c68da8/google_auth-2.49.2-py3-none-any.whl", hash = "sha256:c2720924dfc82dedb962c9f52cabb2ab16714fd0a6a707e40561d217574ed6d5", upload-time = "2026-04-10T00:41:14.501Z" }, + { url = "https://files.pythonhosted.org/packages/73/76/d241a5c927433420507215df6cac1b1fa4ac0ba7a794df42a84326c68da8/google_auth-2.49.2-py3-none-any.whl", hash = "sha256:c2720924dfc82dedb962c9f52cabb2ab16714fd0a6a707e40561d217574ed6d5", size = 240638, upload-time = "2026-04-10T00:41:14.501Z" }, ] - [[package]] name = "identify" version = "2.6.19" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/52/63/51723b5f116cc04b061cb6f5a561790abf249d25931d515cd375e063e0f4/identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842", upload-time = "2026-04-17T18:39:50.265Z" } +sdist = { url = "https://files.pythonhosted.org/packages/52/63/51723b5f116cc04b061cb6f5a561790abf249d25931d515cd375e063e0f4/identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842", size = 99567, upload-time = "2026-04-17T18:39:50.265Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a", upload-time = "2026-04-17T18:39:49.221Z" }, + { url = "https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a", size = 99397, upload-time = "2026-04-17T18:39:49.221Z" }, ] - [[package]] name = "idna" version = "3.13" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ce/cc/762dfb036166873f0059f3b7de4565e1b5bc3d6f28a414c13da27e442f99/idna-3.13.tar.gz", hash = "sha256:585ea8fe5d69b9181ec1afba340451fba6ba764af97026f92a91d4eef164a242", upload-time = "2026-04-22T16:42:42.314Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ce/cc/762dfb036166873f0059f3b7de4565e1b5bc3d6f28a414c13da27e442f99/idna-3.13.tar.gz", hash = "sha256:585ea8fe5d69b9181ec1afba340451fba6ba764af97026f92a91d4eef164a242", size = 194210, upload-time = "2026-04-22T16:42:42.314Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/13/ad7d7ca3808a898b4612b6fe93cde56b53f3034dcde235acb1f0e1df24c6/idna-3.13-py3-none-any.whl", hash = "sha256:892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3", upload-time = "2026-04-22T16:42:40.909Z" }, + { url = "https://files.pythonhosted.org/packages/5d/13/ad7d7ca3808a898b4612b6fe93cde56b53f3034dcde235acb1f0e1df24c6/idna-3.13-py3-none-any.whl", hash = "sha256:892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3", size = 68629, upload-time = "2026-04-22T16:42:40.909Z" }, ] - [[package]] name = "importlib-metadata" version = "9.0.0" @@ -514,20 +483,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "zipp" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a9/01/15bb152d77b21318514a96f43af312635eb2500c96b55398d020c93d86ea/importlib_metadata-9.0.0.tar.gz", hash = "sha256:a4f57ab599e6a2e3016d7595cfd72eb4661a5106e787a95bcc90c7105b831efc", upload-time = "2026-03-20T06:42:56.999Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/01/15bb152d77b21318514a96f43af312635eb2500c96b55398d020c93d86ea/importlib_metadata-9.0.0.tar.gz", hash = "sha256:a4f57ab599e6a2e3016d7595cfd72eb4661a5106e787a95bcc90c7105b831efc", size = 56405, upload-time = "2026-03-20T06:42:56.999Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl", hash = "sha256:2d21d1cc5a017bd0559e36150c21c830ab1dc304dedd1b7ea85d20f45ef3edd7", upload-time = "2026-03-20T06:42:55.665Z" }, + { url = "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl", hash = "sha256:2d21d1cc5a017bd0559e36150c21c830ab1dc304dedd1b7ea85d20f45ef3edd7", size = 27789, upload-time = "2026-03-20T06:42:55.665Z" }, ] - [[package]] name = "iniconfig" version = "2.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", upload-time = "2025-10-18T21:55:43.219Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", upload-time = "2025-10-18T21:55:41.639Z" }, + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, ] - [[package]] name = "isal" version = "1.8.0" @@ -539,7 +506,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9f/72/5cbc30d59821bcf93be44eab758ca999794fbd6e47b67954193d11e92000/isal-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ce55960f53603145d35188ca6363848b79675d81c95a3ff2cfb4b2cb806873e", upload-time = "2025-09-10T08:47:02.178Z" }, { url = "https://files.pythonhosted.org/packages/63/a0/3cdaac7caab7e5e2660afbf03d16616f8c3fb91ec3b75596e2388d42b90b/isal-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d376b7644434d50fedfb670483150ece64082212b6e1f23976f92a91fa1b99b", upload-time = "2025-09-10T08:49:15.206Z" }, ] - [[package]] name = "jinja2" version = "3.1.6" @@ -547,38 +513,36 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", upload-time = "2025-03-05T20:05:02.478Z" } +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", upload-time = "2025-03-05T20:05:00.369Z" }, + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, ] - [[package]] name = "kiwisolver" version = "1.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d0/67/9c61eccb13f0bdca9307614e782fec49ffdde0f7a2314935d489fa93cd9c/kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a", upload-time = "2026-03-09T13:15:53.382Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/b2/818b74ebea34dabe6d0c51cb1c572e046730e64844da6ed646d5298c40ce/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4e9750bc21b886308024f8a54ccb9a2cc38ac9fa813bf4348434e3d54f337ff9", upload-time = "2026-03-09T13:13:23.127Z" }, - { url = "https://files.pythonhosted.org/packages/bf/d9/405320f8077e8e1c5c4bd6adc45e1e6edf6d727b6da7f2e2533cf58bff71/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72ec46b7eba5b395e0a7b63025490d3214c11013f4aacb4f5e8d6c3041829588", upload-time = "2026-03-09T13:13:24.765Z" }, - { url = "https://files.pythonhosted.org/packages/99/9f/795fedf35634f746151ca8839d05681ceb6287fbed6cc1c9bf235f7887c2/kiwisolver-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ed3a984b31da7481b103f68776f7128a89ef26ed40f4dc41a2223cda7fb24819", upload-time = "2026-03-09T13:13:25.878Z" }, - { url = "https://files.pythonhosted.org/packages/c4/13/680c54afe3e65767bed7ec1a15571e1a2f1257128733851ade24abcefbcc/kiwisolver-1.5.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb5136fb5352d3f422df33f0c879a1b0c204004324150cc3b5e3c4f310c9049f", upload-time = "2026-03-09T13:13:27.166Z" }, - { url = "https://files.pythonhosted.org/packages/c8/2f/cebfcdb60fd6a9b0f6b47a9337198bcbad6fbe15e68189b7011fd914911f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2af221f268f5af85e776a73d62b0845fc8baf8ef0abfae79d29c77d0e776aaf", upload-time = "2026-03-09T13:13:28.707Z" }, - { url = "https://files.pythonhosted.org/packages/f2/0d/9b782923aada3fafb1d6b84e13121954515c669b18af0c26e7d21f579855/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b0f172dc8ffaccb8522d7c5d899de00133f2f1ca7b0a49b7da98e901de87bf2d", upload-time = "2026-03-09T13:13:30.528Z" }, - { url = "https://files.pythonhosted.org/packages/27/70/83241b6634b04fe44e892688d5208332bde130f38e610c0418f9ede47ded/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6ab8ba9152203feec73758dad83af9a0bbe05001eb4639e547207c40cfb52083", upload-time = "2026-03-09T13:13:32.818Z" }, - { url = "https://files.pythonhosted.org/packages/e4/db/30ed226fb271ae1a6431fc0fe0edffb2efe23cadb01e798caeb9f2ceae8f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:cdee07c4d7f6d72008d3f73b9bf027f4e11550224c7c50d8df1ae4a37c1402a6", upload-time = "2026-03-09T13:13:34.435Z" }, - { url = "https://files.pythonhosted.org/packages/ec/bd/c314595208e4c9587652d50959ead9e461995389664e490f4dce7ff0f782/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7c60d3c9b06fb23bd9c6139281ccbdc384297579ae037f08ae90c69f6845c0b1", upload-time = "2026-03-09T13:13:36.4Z" }, - { url = "https://files.pythonhosted.org/packages/c1/43/0499cec932d935229b5543d073c2b87c9c22846aab48881e9d8d6e742a2d/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e315e5ec90d88e140f57696ff85b484ff68bb311e36f2c414aa4286293e6dee0", upload-time = "2026-03-09T13:13:38.204Z" }, - { url = "https://files.pythonhosted.org/packages/3d/6f/79b0d760907965acfd9d61826a3d41f8f093c538f55cd2633d3f0db269f6/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:1465387ac63576c3e125e5337a6892b9e99e0627d52317f3ca79e6930d889d15", upload-time = "2026-03-09T13:13:39.966Z" }, - { url = "https://files.pythonhosted.org/packages/ab/31/01d0537c41cb75a551a438c3c7a80d0c60d60b81f694dac83dd436aec0d0/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:530a3fd64c87cffa844d4b6b9768774763d9caa299e9b75d8eca6a4423b31314", upload-time = "2026-03-09T13:13:41.698Z" }, - { url = "https://files.pythonhosted.org/packages/e4/34/8aefdd0be9cfd00a44509251ba864f5caf2991e36772e61c408007e7f417/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1d9daea4ea6b9be74fe2f01f7fbade8d6ffab263e781274cffca0dba9be9eec9", upload-time = "2026-03-09T13:13:43.343Z" }, - { url = "https://files.pythonhosted.org/packages/ad/cf/0348374369ca588f8fe9c338fae49fa4e16eeb10ffb3d012f23a54578a9e/kiwisolver-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:f18c2d9782259a6dc132fdc7a63c168cbc74b35284b6d75c673958982a378384", upload-time = "2026-03-09T13:13:45.792Z" }, - { url = "https://files.pythonhosted.org/packages/28/26/192b26196e2316e2bd29deef67e37cdf9870d9af8e085e521afff0fed526/kiwisolver-1.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:f7c7553b13f69c1b29a5bde08ddc6d9d0c8bfb84f9ed01c30db25944aeb852a7", upload-time = "2026-03-09T13:13:46.878Z" }, - { url = "https://files.pythonhosted.org/packages/1c/fa/2910df836372d8761bb6eff7d8bdcb1613b5c2e03f260efe7abe34d388a7/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_10_13_x86_64.whl", hash = "sha256:5ae8e62c147495b01a0f4765c878e9bfdf843412446a247e28df59936e99e797", upload-time = "2026-03-09T13:15:35.629Z" }, - { url = "https://files.pythonhosted.org/packages/0f/41/c5f71f9f00aabcc71fee8b7475e3f64747282580c2fe748961ba29b18385/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f6764a4ccab3078db14a632420930f6186058750df066b8ea2a7106df91d3203", upload-time = "2026-03-09T13:15:36.894Z" }, - { url = "https://files.pythonhosted.org/packages/fa/06/7399a607f434119c6e1fdc8ec89a8d51ccccadf3341dee4ead6bd14caaf5/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c31c13da98624f957b0fb1b5bae5383b2333c2c3f6793d9825dd5ce79b525cb7", upload-time = "2026-03-09T13:15:38.22Z" }, - { url = "https://files.pythonhosted.org/packages/b5/91/53255615acd2a1eaca307ede3c90eb550bae9c94581f8c00081b6b1c8f44/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-win_amd64.whl", hash = "sha256:1f1489f769582498610e015a8ef2d36f28f505ab3096d0e16b4858a9ec214f57", upload-time = "2026-03-09T13:15:39.65Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/d0/67/9c61eccb13f0bdca9307614e782fec49ffdde0f7a2314935d489fa93cd9c/kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a", size = 103482, upload-time = "2026-03-09T13:15:53.382Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/b2/818b74ebea34dabe6d0c51cb1c572e046730e64844da6ed646d5298c40ce/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4e9750bc21b886308024f8a54ccb9a2cc38ac9fa813bf4348434e3d54f337ff9", size = 123158, upload-time = "2026-03-09T13:13:23.127Z" }, + { url = "https://files.pythonhosted.org/packages/bf/d9/405320f8077e8e1c5c4bd6adc45e1e6edf6d727b6da7f2e2533cf58bff71/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72ec46b7eba5b395e0a7b63025490d3214c11013f4aacb4f5e8d6c3041829588", size = 66388, upload-time = "2026-03-09T13:13:24.765Z" }, + { url = "https://files.pythonhosted.org/packages/99/9f/795fedf35634f746151ca8839d05681ceb6287fbed6cc1c9bf235f7887c2/kiwisolver-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ed3a984b31da7481b103f68776f7128a89ef26ed40f4dc41a2223cda7fb24819", size = 64068, upload-time = "2026-03-09T13:13:25.878Z" }, + { url = "https://files.pythonhosted.org/packages/c4/13/680c54afe3e65767bed7ec1a15571e1a2f1257128733851ade24abcefbcc/kiwisolver-1.5.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb5136fb5352d3f422df33f0c879a1b0c204004324150cc3b5e3c4f310c9049f", size = 1477934, upload-time = "2026-03-09T13:13:27.166Z" }, + { url = "https://files.pythonhosted.org/packages/c8/2f/cebfcdb60fd6a9b0f6b47a9337198bcbad6fbe15e68189b7011fd914911f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2af221f268f5af85e776a73d62b0845fc8baf8ef0abfae79d29c77d0e776aaf", size = 1278537, upload-time = "2026-03-09T13:13:28.707Z" }, + { url = "https://files.pythonhosted.org/packages/f2/0d/9b782923aada3fafb1d6b84e13121954515c669b18af0c26e7d21f579855/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b0f172dc8ffaccb8522d7c5d899de00133f2f1ca7b0a49b7da98e901de87bf2d", size = 1296685, upload-time = "2026-03-09T13:13:30.528Z" }, + { url = "https://files.pythonhosted.org/packages/27/70/83241b6634b04fe44e892688d5208332bde130f38e610c0418f9ede47ded/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6ab8ba9152203feec73758dad83af9a0bbe05001eb4639e547207c40cfb52083", size = 1346024, upload-time = "2026-03-09T13:13:32.818Z" }, + { url = "https://files.pythonhosted.org/packages/e4/db/30ed226fb271ae1a6431fc0fe0edffb2efe23cadb01e798caeb9f2ceae8f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:cdee07c4d7f6d72008d3f73b9bf027f4e11550224c7c50d8df1ae4a37c1402a6", size = 987241, upload-time = "2026-03-09T13:13:34.435Z" }, + { url = "https://files.pythonhosted.org/packages/ec/bd/c314595208e4c9587652d50959ead9e461995389664e490f4dce7ff0f782/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7c60d3c9b06fb23bd9c6139281ccbdc384297579ae037f08ae90c69f6845c0b1", size = 2227742, upload-time = "2026-03-09T13:13:36.4Z" }, + { url = "https://files.pythonhosted.org/packages/c1/43/0499cec932d935229b5543d073c2b87c9c22846aab48881e9d8d6e742a2d/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e315e5ec90d88e140f57696ff85b484ff68bb311e36f2c414aa4286293e6dee0", size = 2323966, upload-time = "2026-03-09T13:13:38.204Z" }, + { url = "https://files.pythonhosted.org/packages/3d/6f/79b0d760907965acfd9d61826a3d41f8f093c538f55cd2633d3f0db269f6/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:1465387ac63576c3e125e5337a6892b9e99e0627d52317f3ca79e6930d889d15", size = 1977417, upload-time = "2026-03-09T13:13:39.966Z" }, + { url = "https://files.pythonhosted.org/packages/ab/31/01d0537c41cb75a551a438c3c7a80d0c60d60b81f694dac83dd436aec0d0/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:530a3fd64c87cffa844d4b6b9768774763d9caa299e9b75d8eca6a4423b31314", size = 2491238, upload-time = "2026-03-09T13:13:41.698Z" }, + { url = "https://files.pythonhosted.org/packages/e4/34/8aefdd0be9cfd00a44509251ba864f5caf2991e36772e61c408007e7f417/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1d9daea4ea6b9be74fe2f01f7fbade8d6ffab263e781274cffca0dba9be9eec9", size = 2294947, upload-time = "2026-03-09T13:13:43.343Z" }, + { url = "https://files.pythonhosted.org/packages/ad/cf/0348374369ca588f8fe9c338fae49fa4e16eeb10ffb3d012f23a54578a9e/kiwisolver-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:f18c2d9782259a6dc132fdc7a63c168cbc74b35284b6d75c673958982a378384", size = 73569, upload-time = "2026-03-09T13:13:45.792Z" }, + { url = "https://files.pythonhosted.org/packages/28/26/192b26196e2316e2bd29deef67e37cdf9870d9af8e085e521afff0fed526/kiwisolver-1.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:f7c7553b13f69c1b29a5bde08ddc6d9d0c8bfb84f9ed01c30db25944aeb852a7", size = 64997, upload-time = "2026-03-09T13:13:46.878Z" }, + { url = "https://files.pythonhosted.org/packages/1c/fa/2910df836372d8761bb6eff7d8bdcb1613b5c2e03f260efe7abe34d388a7/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_10_13_x86_64.whl", hash = "sha256:5ae8e62c147495b01a0f4765c878e9bfdf843412446a247e28df59936e99e797", size = 130262, upload-time = "2026-03-09T13:15:35.629Z" }, + { url = "https://files.pythonhosted.org/packages/0f/41/c5f71f9f00aabcc71fee8b7475e3f64747282580c2fe748961ba29b18385/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f6764a4ccab3078db14a632420930f6186058750df066b8ea2a7106df91d3203", size = 138036, upload-time = "2026-03-09T13:15:36.894Z" }, + { url = "https://files.pythonhosted.org/packages/fa/06/7399a607f434119c6e1fdc8ec89a8d51ccccadf3341dee4ead6bd14caaf5/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c31c13da98624f957b0fb1b5bae5383b2333c2c3f6793d9825dd5ce79b525cb7", size = 194295, upload-time = "2026-03-09T13:15:38.22Z" }, + { url = "https://files.pythonhosted.org/packages/b5/91/53255615acd2a1eaca307ede3c90eb550bae9c94581f8c00081b6b1c8f44/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-win_amd64.whl", hash = "sha256:1f1489f769582498610e015a8ef2d36f28f505ab3096d0e16b4858a9ec214f57", size = 75987, upload-time = "2026-03-09T13:15:39.65Z" }, ] - [[package]] name = "lxml" version = "6.1.1" @@ -604,42 +568,39 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1b/89/45198e9624762af2dfd2cb8782598477ceb29f6e59caab560388ae1f4ec1/lxml-6.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:26e6eda8d38c1fcab1090dd196ee87cbd13788e531937610e2589085de074e77", upload-time = "2026-05-18T19:17:56.781Z" }, { url = "https://files.pythonhosted.org/packages/90/a9/7a54b6834088d9ae528a7b780584ba6a39a9457b0ac330479f20ffbc9449/lxml-6.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:6540377fbd53fe1b629172288c464fb18db11ce1fa7dc15891da10aa9dcc3e7f", upload-time = "2026-05-19T19:22:50.843Z" }, ] - [[package]] name = "lz4" version = "4.4.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/57/51/f1b86d93029f418033dddf9b9f79c8d2641e7454080478ee2aab5123173e/lz4-4.4.5.tar.gz", hash = "sha256:5f0b9e53c1e82e88c10d7c180069363980136b9d7a8306c4dca4f760d60c39f0", upload-time = "2025-11-03T13:02:36.061Z" } +sdist = { url = "https://files.pythonhosted.org/packages/57/51/f1b86d93029f418033dddf9b9f79c8d2641e7454080478ee2aab5123173e/lz4-4.4.5.tar.gz", hash = "sha256:5f0b9e53c1e82e88c10d7c180069363980136b9d7a8306c4dca4f760d60c39f0", size = 172886, upload-time = "2025-11-03T13:02:36.061Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1b/ac/016e4f6de37d806f7cc8f13add0a46c9a7cfc41a5ddc2bc831d7954cf1ce/lz4-4.4.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:df5aa4cead2044bab83e0ebae56e0944cc7fcc1505c7787e9e1057d6d549897e", upload-time = "2025-11-03T13:01:45.895Z" }, - { url = "https://files.pythonhosted.org/packages/8d/df/0fadac6e5bd31b6f34a1a8dbd4db6a7606e70715387c27368586455b7fc9/lz4-4.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d0bf51e7745484d2092b3a51ae6eb58c3bd3ce0300cf2b2c14f76c536d5697a", upload-time = "2025-11-03T13:01:47.205Z" }, - { url = "https://files.pythonhosted.org/packages/b7/17/34e36cc49bb16ca73fb57fbd4c5eaa61760c6b64bce91fcb4e0f4a97f852/lz4-4.4.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7b62f94b523c251cf32aa4ab555f14d39bd1a9df385b72443fd76d7c7fb051f5", upload-time = "2025-11-03T13:01:48.667Z" }, - { url = "https://files.pythonhosted.org/packages/90/1c/b1d8e3741e9fc89ed3b5f7ef5f22586c07ed6bb04e8343c2e98f0fa7ff04/lz4-4.4.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c3ea562c3af274264444819ae9b14dbbf1ab070aff214a05e97db6896c7597e", upload-time = "2025-11-03T13:01:50.159Z" }, - { url = "https://files.pythonhosted.org/packages/55/d9/e3867222474f6c1b76e89f3bd914595af69f55bf2c1866e984c548afdc15/lz4-4.4.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24092635f47538b392c4eaeff14c7270d2c8e806bf4be2a6446a378591c5e69e", upload-time = "2025-11-03T13:01:51.273Z" }, - { url = "https://files.pythonhosted.org/packages/b2/e7/d667d337367686311c38b580d1ca3d5a23a6617e129f26becd4f5dc458df/lz4-4.4.5-cp312-cp312-win32.whl", hash = "sha256:214e37cfe270948ea7eb777229e211c601a3e0875541c1035ab408fbceaddf50", upload-time = "2025-11-03T13:01:52.605Z" }, - { url = "https://files.pythonhosted.org/packages/a5/0b/a54cd7406995ab097fceb907c7eb13a6ddd49e0b231e448f1a81a50af65c/lz4-4.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:713a777de88a73425cf08eb11f742cd2c98628e79a8673d6a52e3c5f0c116f33", upload-time = "2025-11-03T13:01:53.477Z" }, - { url = "https://files.pythonhosted.org/packages/6a/7e/dc28a952e4bfa32ca16fa2eb026e7a6ce5d1411fcd5986cd08c74ec187b9/lz4-4.4.5-cp312-cp312-win_arm64.whl", hash = "sha256:a88cbb729cc333334ccfb52f070463c21560fca63afcf636a9f160a55fac3301", upload-time = "2025-11-03T13:01:54.419Z" }, + { url = "https://files.pythonhosted.org/packages/1b/ac/016e4f6de37d806f7cc8f13add0a46c9a7cfc41a5ddc2bc831d7954cf1ce/lz4-4.4.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:df5aa4cead2044bab83e0ebae56e0944cc7fcc1505c7787e9e1057d6d549897e", size = 207163, upload-time = "2025-11-03T13:01:45.895Z" }, + { url = "https://files.pythonhosted.org/packages/8d/df/0fadac6e5bd31b6f34a1a8dbd4db6a7606e70715387c27368586455b7fc9/lz4-4.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d0bf51e7745484d2092b3a51ae6eb58c3bd3ce0300cf2b2c14f76c536d5697a", size = 207150, upload-time = "2025-11-03T13:01:47.205Z" }, + { url = "https://files.pythonhosted.org/packages/b7/17/34e36cc49bb16ca73fb57fbd4c5eaa61760c6b64bce91fcb4e0f4a97f852/lz4-4.4.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7b62f94b523c251cf32aa4ab555f14d39bd1a9df385b72443fd76d7c7fb051f5", size = 1292045, upload-time = "2025-11-03T13:01:48.667Z" }, + { url = "https://files.pythonhosted.org/packages/90/1c/b1d8e3741e9fc89ed3b5f7ef5f22586c07ed6bb04e8343c2e98f0fa7ff04/lz4-4.4.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c3ea562c3af274264444819ae9b14dbbf1ab070aff214a05e97db6896c7597e", size = 1279546, upload-time = "2025-11-03T13:01:50.159Z" }, + { url = "https://files.pythonhosted.org/packages/55/d9/e3867222474f6c1b76e89f3bd914595af69f55bf2c1866e984c548afdc15/lz4-4.4.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24092635f47538b392c4eaeff14c7270d2c8e806bf4be2a6446a378591c5e69e", size = 1368249, upload-time = "2025-11-03T13:01:51.273Z" }, + { url = "https://files.pythonhosted.org/packages/b2/e7/d667d337367686311c38b580d1ca3d5a23a6617e129f26becd4f5dc458df/lz4-4.4.5-cp312-cp312-win32.whl", hash = "sha256:214e37cfe270948ea7eb777229e211c601a3e0875541c1035ab408fbceaddf50", size = 88189, upload-time = "2025-11-03T13:01:52.605Z" }, + { url = "https://files.pythonhosted.org/packages/a5/0b/a54cd7406995ab097fceb907c7eb13a6ddd49e0b231e448f1a81a50af65c/lz4-4.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:713a777de88a73425cf08eb11f742cd2c98628e79a8673d6a52e3c5f0c116f33", size = 99497, upload-time = "2025-11-03T13:01:53.477Z" }, + { url = "https://files.pythonhosted.org/packages/6a/7e/dc28a952e4bfa32ca16fa2eb026e7a6ce5d1411fcd5986cd08c74ec187b9/lz4-4.4.5-cp312-cp312-win_arm64.whl", hash = "sha256:a88cbb729cc333334ccfb52f070463c21560fca63afcf636a9f160a55fac3301", size = 91279, upload-time = "2025-11-03T13:01:54.419Z" }, ] - [[package]] name = "markupsafe" version = "3.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", upload-time = "2025-09-27T18:37:40.426Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", upload-time = "2025-09-27T18:36:30.854Z" }, - { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", upload-time = "2025-09-27T18:36:31.971Z" }, - { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", upload-time = "2025-09-27T18:36:32.813Z" }, - { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", upload-time = "2025-09-27T18:36:33.86Z" }, - { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", upload-time = "2025-09-27T18:36:35.099Z" }, - { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", upload-time = "2025-09-27T18:36:36.001Z" }, - { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", upload-time = "2025-09-27T18:36:36.906Z" }, - { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", upload-time = "2025-09-27T18:36:37.868Z" }, - { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", upload-time = "2025-09-27T18:36:38.761Z" }, - { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", upload-time = "2025-09-27T18:36:39.701Z" }, - { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", upload-time = "2025-09-27T18:36:40.689Z" }, + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, ] - [[package]] name = "matplotlib" version = "3.10.0" @@ -655,34 +616,31 @@ dependencies = [ { name = "pyparsing" }, { name = "python-dateutil" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/68/dd/fa2e1a45fce2d09f4aea3cee169760e672c8262325aa5796c49d543dc7e6/matplotlib-3.10.0.tar.gz", hash = "sha256:b886d02a581b96704c9d1ffe55709e49b4d2d52709ccebc4be42db856e511278", upload-time = "2024-12-14T06:32:51.547Z" } +sdist = { url = "https://files.pythonhosted.org/packages/68/dd/fa2e1a45fce2d09f4aea3cee169760e672c8262325aa5796c49d543dc7e6/matplotlib-3.10.0.tar.gz", hash = "sha256:b886d02a581b96704c9d1ffe55709e49b4d2d52709ccebc4be42db856e511278", size = 36686418, upload-time = "2024-12-14T06:32:51.547Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/44/c7/6b2d8cb7cc251d53c976799cacd3200add56351c175ba89ab9cbd7c1e68a/matplotlib-3.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4659665bc7c9b58f8c00317c3c2a299f7f258eeae5a5d56b4c64226fca2f7c59", upload-time = "2024-12-14T06:31:24.727Z" }, - { url = "https://files.pythonhosted.org/packages/42/2a/6d66d0fba41e13e9ca6512a0a51170f43e7e7ed3a8dfa036324100775612/matplotlib-3.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d44cb942af1693cced2604c33a9abcef6205601c445f6d0dc531d813af8a2f5a", upload-time = "2024-12-14T06:31:28.55Z" }, - { url = "https://files.pythonhosted.org/packages/90/60/2a60342b27b90a16bada939a85e29589902b41073f59668b904b15ea666c/matplotlib-3.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a994f29e968ca002b50982b27168addfd65f0105610b6be7fa515ca4b5307c95", upload-time = "2024-12-14T06:31:32.223Z" }, - { url = "https://files.pythonhosted.org/packages/a7/b2/d872fc3d753516870d520595ddd8ce4dd44fa797a240999f125f58521ad7/matplotlib-3.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b0558bae37f154fffda54d779a592bc97ca8b4701f1c710055b609a3bac44c8", upload-time = "2024-12-14T06:31:34.894Z" }, - { url = "https://files.pythonhosted.org/packages/f4/bd/b2f60cf7f57d014ab33e4f74602a2b5bdc657976db8196bbc022185f6f9c/matplotlib-3.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:503feb23bd8c8acc75541548a1d709c059b7184cde26314896e10a9f14df5f12", upload-time = "2024-12-14T06:31:39.552Z" }, - { url = "https://files.pythonhosted.org/packages/9f/6e/264673e64001b99d747aff5a288eca82826c024437a3694e19aed1decf46/matplotlib-3.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:c40ba2eb08b3f5de88152c2333c58cee7edcead0a2a0d60fcafa116b17117adc", upload-time = "2024-12-14T06:31:44.128Z" }, + { url = "https://files.pythonhosted.org/packages/44/c7/6b2d8cb7cc251d53c976799cacd3200add56351c175ba89ab9cbd7c1e68a/matplotlib-3.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4659665bc7c9b58f8c00317c3c2a299f7f258eeae5a5d56b4c64226fca2f7c59", size = 8172465, upload-time = "2024-12-14T06:31:24.727Z" }, + { url = "https://files.pythonhosted.org/packages/42/2a/6d66d0fba41e13e9ca6512a0a51170f43e7e7ed3a8dfa036324100775612/matplotlib-3.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d44cb942af1693cced2604c33a9abcef6205601c445f6d0dc531d813af8a2f5a", size = 8043300, upload-time = "2024-12-14T06:31:28.55Z" }, + { url = "https://files.pythonhosted.org/packages/90/60/2a60342b27b90a16bada939a85e29589902b41073f59668b904b15ea666c/matplotlib-3.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a994f29e968ca002b50982b27168addfd65f0105610b6be7fa515ca4b5307c95", size = 8448936, upload-time = "2024-12-14T06:31:32.223Z" }, + { url = "https://files.pythonhosted.org/packages/a7/b2/d872fc3d753516870d520595ddd8ce4dd44fa797a240999f125f58521ad7/matplotlib-3.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b0558bae37f154fffda54d779a592bc97ca8b4701f1c710055b609a3bac44c8", size = 8594151, upload-time = "2024-12-14T06:31:34.894Z" }, + { url = "https://files.pythonhosted.org/packages/f4/bd/b2f60cf7f57d014ab33e4f74602a2b5bdc657976db8196bbc022185f6f9c/matplotlib-3.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:503feb23bd8c8acc75541548a1d709c059b7184cde26314896e10a9f14df5f12", size = 9400347, upload-time = "2024-12-14T06:31:39.552Z" }, + { url = "https://files.pythonhosted.org/packages/9f/6e/264673e64001b99d747aff5a288eca82826c024437a3694e19aed1decf46/matplotlib-3.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:c40ba2eb08b3f5de88152c2333c58cee7edcead0a2a0d60fcafa116b17117adc", size = 8039144, upload-time = "2024-12-14T06:31:44.128Z" }, ] - [[package]] name = "mypy-extensions" version = "1.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", upload-time = "2025-04-22T14:54:24.164Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", upload-time = "2025-04-22T14:54:22.983Z" }, + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, ] - [[package]] name = "nodeenv" version = "1.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", upload-time = "2025-12-20T14:08:54.006Z" } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", upload-time = "2025-12-20T14:08:52.782Z" }, + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, ] - [[package]] name = "nptyping" version = "2.5.0" @@ -690,29 +648,26 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e1/b7/ffe533358c32506b1708feec0fb04ba0a35a959a94163fff5333671909da/nptyping-2.5.0.tar.gz", hash = "sha256:e3d35b53af967e6fb407c3016ff9abae954d3a0568f7cc13a461084224e8e20a", upload-time = "2023-02-20T21:57:11.814Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/b7/ffe533358c32506b1708feec0fb04ba0a35a959a94163fff5333671909da/nptyping-2.5.0.tar.gz", hash = "sha256:e3d35b53af967e6fb407c3016ff9abae954d3a0568f7cc13a461084224e8e20a", size = 71623, upload-time = "2023-02-20T21:57:11.814Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/28/92edc05378175de13a3d4986cee7531853634a22b7e5e21a988fa84fde3f/nptyping-2.5.0-py3-none-any.whl", hash = "sha256:764e51836faae33a7ae2e928af574cfb701355647accadcc89f2ad793630b7c8", upload-time = "2023-02-20T21:57:09.61Z" }, + { url = "https://files.pythonhosted.org/packages/b1/28/92edc05378175de13a3d4986cee7531853634a22b7e5e21a988fa84fde3f/nptyping-2.5.0-py3-none-any.whl", hash = "sha256:764e51836faae33a7ae2e928af574cfb701355647accadcc89f2ad793630b7c8", size = 37602, upload-time = "2023-02-20T21:57:09.61Z" }, ] - [[package]] name = "nr-date" version = "2.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a0/92/08110dd3d7ff5e2b852a220752eb6c40183839f5b7cc91f9f38dd2298e7d/nr_date-2.1.0.tar.gz", hash = "sha256:0643aea13bcdc2a8bc56af9d5e6a89ef244c9744a1ef00cdc735902ba7f7d2e6", upload-time = "2023-08-16T13:46:04.114Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a0/92/08110dd3d7ff5e2b852a220752eb6c40183839f5b7cc91f9f38dd2298e7d/nr_date-2.1.0.tar.gz", hash = "sha256:0643aea13bcdc2a8bc56af9d5e6a89ef244c9744a1ef00cdc735902ba7f7d2e6", size = 8789, upload-time = "2023-08-16T13:46:04.114Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/10/1d2b00172537c1522fe64bbc6fb16b015632a02f7b3864e788ccbcb4dd85/nr_date-2.1.0-py3-none-any.whl", hash = "sha256:bd672a9dfbdcf7c4b9289fea6750c42490eaee08036a72059dcc78cb236ed568", upload-time = "2023-08-16T13:46:02.627Z" }, + { url = "https://files.pythonhosted.org/packages/f9/10/1d2b00172537c1522fe64bbc6fb16b015632a02f7b3864e788ccbcb4dd85/nr_date-2.1.0-py3-none-any.whl", hash = "sha256:bd672a9dfbdcf7c4b9289fea6750c42490eaee08036a72059dcc78cb236ed568", size = 10496, upload-time = "2023-08-16T13:46:02.627Z" }, ] - [[package]] name = "nr-stream" version = "1.1.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b7/37/e4d36d852c441233c306c5fbd98147685dce3ac9b0a8bbf4a587d0ea29ea/nr_stream-1.1.5.tar.gz", hash = "sha256:eb0216c6bfc61a46d4568dba3b588502c610ec8ddef4ac98f3932a2bd7264f65", upload-time = "2023-02-14T22:44:09.074Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b7/37/e4d36d852c441233c306c5fbd98147685dce3ac9b0a8bbf4a587d0ea29ea/nr_stream-1.1.5.tar.gz", hash = "sha256:eb0216c6bfc61a46d4568dba3b588502c610ec8ddef4ac98f3932a2bd7264f65", size = 10053, upload-time = "2023-02-14T22:44:09.074Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/e1/f93485fe09aa36c0e1a3b76363efa1791241f7f863a010f725c95e8a74fe/nr_stream-1.1.5-py3-none-any.whl", hash = "sha256:47e12150b331ad2cb729cfd9d2abd281c9949809729ba461c6aa87dd9927b2d4", upload-time = "2023-02-14T22:44:07.72Z" }, + { url = "https://files.pythonhosted.org/packages/1d/e1/f93485fe09aa36c0e1a3b76363efa1791241f7f863a010f725c95e8a74fe/nr_stream-1.1.5-py3-none-any.whl", hash = "sha256:47e12150b331ad2cb729cfd9d2abd281c9949809729ba461c6aa87dd9927b2d4", size = 10448, upload-time = "2023-02-14T22:44:07.72Z" }, ] - [[package]] name = "nr-util" version = "0.8.12" @@ -721,11 +676,10 @@ dependencies = [ { name = "deprecated" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/20/0c/078c567d95e25564bc1ede3c2cf6ce1c91f50648c83786354b47224326da/nr.util-0.8.12.tar.gz", hash = "sha256:a4549c2033d99d2f0379b3f3d233fd2a8ade286bbf0b3ad0cc7cea16022214f4", upload-time = "2022-06-20T13:29:29.192Z" } +sdist = { url = "https://files.pythonhosted.org/packages/20/0c/078c567d95e25564bc1ede3c2cf6ce1c91f50648c83786354b47224326da/nr.util-0.8.12.tar.gz", hash = "sha256:a4549c2033d99d2f0379b3f3d233fd2a8ade286bbf0b3ad0cc7cea16022214f4", size = 63707, upload-time = "2022-06-20T13:29:29.192Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/58/eab08df9dbd69d9e21fc5e7be6f67454f386336ec71e6b64e378a2dddea4/nr.util-0.8.12-py3-none-any.whl", hash = "sha256:91da02ac9795eb8e015372275c1efe54bac9051231ee9b0e7e6f96b0b4e7d2bb", upload-time = "2022-06-20T13:29:27.312Z" }, + { url = "https://files.pythonhosted.org/packages/ba/58/eab08df9dbd69d9e21fc5e7be6f67454f386336ec71e6b64e378a2dddea4/nr.util-0.8.12-py3-none-any.whl", hash = "sha256:91da02ac9795eb8e015372275c1efe54bac9051231ee9b0e7e6f96b0b4e7d2bb", size = 90319, upload-time = "2022-06-20T13:29:27.312Z" }, ] - [[package]] name = "numexpr" version = "2.14.1" @@ -744,32 +698,29 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/31/9f/203d82b9e39dadd91d64bca55b3c8ca432e981b822468dcef41a4418626b/numexpr-2.14.1-cp312-cp312-win32.whl", hash = "sha256:36f8d5c1bd1355df93b43d766790f9046cccfc1e32b7c6163f75bcde682cda07", upload-time = "2025-10-13T16:17:10.369Z" }, { url = "https://files.pythonhosted.org/packages/1f/67/ffe750b5452eb66de788c34e7d21ec6d886abb4d7c43ad1dc88ceb3d998f/numexpr-2.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:fdd886f4b7dbaf167633ee396478f0d0aa58ea2f9e7ccc3c6431019623e8d68f", upload-time = "2025-10-13T16:17:11.974Z" }, ] - [[package]] name = "numpy" version = "1.26.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", upload-time = "2024-02-06T00:26:44.495Z" } +sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/95/12/8f2020a8e8b8383ac0177dc9570aad031a3beb12e38847f7129bacd96228/numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218", upload-time = "2024-02-05T23:55:32.801Z" }, - { url = "https://files.pythonhosted.org/packages/75/5b/ca6c8bd14007e5ca171c7c03102d17b4f4e0ceb53957e8c44343a9546dcc/numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b", upload-time = "2024-02-05T23:55:56.28Z" }, - { url = "https://files.pythonhosted.org/packages/79/f8/97f10e6755e2a7d027ca783f63044d5b1bc1ae7acb12afe6a9b4286eac17/numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b", upload-time = "2024-02-05T23:56:20.368Z" }, - { url = "https://files.pythonhosted.org/packages/0f/50/de23fde84e45f5c4fda2488c759b69990fd4512387a8632860f3ac9cd225/numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed", upload-time = "2024-02-05T23:56:56.054Z" }, - { url = "https://files.pythonhosted.org/packages/4c/0c/9c603826b6465e82591e05ca230dfc13376da512b25ccd0894709b054ed0/numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a", upload-time = "2024-02-05T23:57:21.56Z" }, - { url = "https://files.pythonhosted.org/packages/76/8c/2ba3902e1a0fc1c74962ea9bb33a534bb05984ad7ff9515bf8d07527cadd/numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0", upload-time = "2024-02-05T23:57:56.585Z" }, - { url = "https://files.pythonhosted.org/packages/28/4a/46d9e65106879492374999e76eb85f87b15328e06bd1550668f79f7b18c6/numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110", upload-time = "2024-02-05T23:58:08.963Z" }, - { url = "https://files.pythonhosted.org/packages/16/2e/86f24451c2d530c88daf997cb8d6ac622c1d40d19f5a031ed68a4b73a374/numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818", upload-time = "2024-02-05T23:58:36.364Z" }, + { url = "https://files.pythonhosted.org/packages/95/12/8f2020a8e8b8383ac0177dc9570aad031a3beb12e38847f7129bacd96228/numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218", size = 20335901, upload-time = "2024-02-05T23:55:32.801Z" }, + { url = "https://files.pythonhosted.org/packages/75/5b/ca6c8bd14007e5ca171c7c03102d17b4f4e0ceb53957e8c44343a9546dcc/numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b", size = 13685868, upload-time = "2024-02-05T23:55:56.28Z" }, + { url = "https://files.pythonhosted.org/packages/79/f8/97f10e6755e2a7d027ca783f63044d5b1bc1ae7acb12afe6a9b4286eac17/numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b", size = 13925109, upload-time = "2024-02-05T23:56:20.368Z" }, + { url = "https://files.pythonhosted.org/packages/0f/50/de23fde84e45f5c4fda2488c759b69990fd4512387a8632860f3ac9cd225/numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed", size = 17950613, upload-time = "2024-02-05T23:56:56.054Z" }, + { url = "https://files.pythonhosted.org/packages/4c/0c/9c603826b6465e82591e05ca230dfc13376da512b25ccd0894709b054ed0/numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a", size = 13572172, upload-time = "2024-02-05T23:57:21.56Z" }, + { url = "https://files.pythonhosted.org/packages/76/8c/2ba3902e1a0fc1c74962ea9bb33a534bb05984ad7ff9515bf8d07527cadd/numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0", size = 17786643, upload-time = "2024-02-05T23:57:56.585Z" }, + { url = "https://files.pythonhosted.org/packages/28/4a/46d9e65106879492374999e76eb85f87b15328e06bd1550668f79f7b18c6/numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110", size = 5677803, upload-time = "2024-02-05T23:58:08.963Z" }, + { url = "https://files.pythonhosted.org/packages/16/2e/86f24451c2d530c88daf997cb8d6ac622c1d40d19f5a031ed68a4b73a374/numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818", size = 15517754, upload-time = "2024-02-05T23:58:36.364Z" }, ] - [[package]] name = "packaging" version = "26.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", upload-time = "2026-04-24T20:15:23.917Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", upload-time = "2026-04-24T20:15:22.081Z" }, + { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, ] - [[package]] name = "pandas" version = "2.2.3" @@ -780,63 +731,58 @@ dependencies = [ { name = "pytz" }, { name = "tzdata" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9c/d6/9f8431bacc2e19dca897724cd097b1bb224a6ad5433784a44b587c7c13af/pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667", upload-time = "2024-09-20T13:10:04.827Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9c/d6/9f8431bacc2e19dca897724cd097b1bb224a6ad5433784a44b587c7c13af/pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667", size = 4399213, upload-time = "2024-09-20T13:10:04.827Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/17/a3/fb2734118db0af37ea7433f57f722c0a56687e14b14690edff0cdb4b7e58/pandas-2.2.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9", upload-time = "2024-09-20T13:09:09.655Z" }, - { url = "https://files.pythonhosted.org/packages/e1/0c/ad295fd74bfac85358fd579e271cded3ac969de81f62dd0142c426b9da91/pandas-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4", upload-time = "2024-09-20T13:09:14.718Z" }, - { url = "https://files.pythonhosted.org/packages/c6/2a/4bba3f03f7d07207481fed47f5b35f556c7441acddc368ec43d6643c5777/pandas-2.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3", upload-time = "2024-09-20T19:02:03.88Z" }, - { url = "https://files.pythonhosted.org/packages/38/f8/d8fddee9ed0d0c0f4a2132c1dfcf0e3e53265055da8df952a53e7eaf178c/pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319", upload-time = "2024-09-20T13:09:17.621Z" }, - { url = "https://files.pythonhosted.org/packages/20/e8/45a05d9c39d2cea61ab175dbe6a2de1d05b679e8de2011da4ee190d7e748/pandas-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8", upload-time = "2024-09-20T19:02:07.094Z" }, - { url = "https://files.pythonhosted.org/packages/1d/99/617d07a6a5e429ff90c90da64d428516605a1ec7d7bea494235e1c3882de/pandas-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a", upload-time = "2024-09-20T13:09:20.474Z" }, - { url = "https://files.pythonhosted.org/packages/29/d4/1244ab8edf173a10fd601f7e13b9566c1b525c4f365d6bee918e68381889/pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", upload-time = "2024-09-20T13:09:23.137Z" }, + { url = "https://files.pythonhosted.org/packages/17/a3/fb2734118db0af37ea7433f57f722c0a56687e14b14690edff0cdb4b7e58/pandas-2.2.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9", size = 12529893, upload-time = "2024-09-20T13:09:09.655Z" }, + { url = "https://files.pythonhosted.org/packages/e1/0c/ad295fd74bfac85358fd579e271cded3ac969de81f62dd0142c426b9da91/pandas-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4", size = 11363475, upload-time = "2024-09-20T13:09:14.718Z" }, + { url = "https://files.pythonhosted.org/packages/c6/2a/4bba3f03f7d07207481fed47f5b35f556c7441acddc368ec43d6643c5777/pandas-2.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3", size = 15188645, upload-time = "2024-09-20T19:02:03.88Z" }, + { url = "https://files.pythonhosted.org/packages/38/f8/d8fddee9ed0d0c0f4a2132c1dfcf0e3e53265055da8df952a53e7eaf178c/pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319", size = 12739445, upload-time = "2024-09-20T13:09:17.621Z" }, + { url = "https://files.pythonhosted.org/packages/20/e8/45a05d9c39d2cea61ab175dbe6a2de1d05b679e8de2011da4ee190d7e748/pandas-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8", size = 16359235, upload-time = "2024-09-20T19:02:07.094Z" }, + { url = "https://files.pythonhosted.org/packages/1d/99/617d07a6a5e429ff90c90da64d428516605a1ec7d7bea494235e1c3882de/pandas-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a", size = 14056756, upload-time = "2024-09-20T13:09:20.474Z" }, + { url = "https://files.pythonhosted.org/packages/29/d4/1244ab8edf173a10fd601f7e13b9566c1b525c4f365d6bee918e68381889/pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", size = 11504248, upload-time = "2024-09-20T13:09:23.137Z" }, ] - [[package]] name = "pathspec" version = "1.1.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", upload-time = "2026-04-27T01:46:08.907Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", upload-time = "2026-04-27T01:46:07.06Z" }, + { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" }, ] - [[package]] name = "pillow" version = "12.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/21/c2bcdd5906101a30244eaffc1b6e6ce71a31bd0742a01eb89e660ebfac2d/pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5", upload-time = "2026-04-01T14:46:17.687Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/21/c2bcdd5906101a30244eaffc1b6e6ce71a31bd0742a01eb89e660ebfac2d/pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5", size = 46987819, upload-time = "2026-04-01T14:46:17.687Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/58/be/7482c8a5ebebbc6470b3eb791812fff7d5e0216c2be3827b30b8bb6603ed/pillow-12.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2d192a155bbcec180f8564f693e6fd9bccff5a7af9b32e2e4bf8c9c69dbad6b5", upload-time = "2026-04-01T14:43:13.246Z" }, - { url = "https://files.pythonhosted.org/packages/d8/95/0a351b9289c2b5cbde0bacd4a83ebc44023e835490a727b2a3bd60ddc0f4/pillow-12.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3f40b3c5a968281fd507d519e444c35f0ff171237f4fdde090dd60699458421", upload-time = "2026-04-01T14:43:15.584Z" }, - { url = "https://files.pythonhosted.org/packages/de/af/4e8e6869cbed569d43c416fad3dc4ecb944cb5d9492defaed89ddd6fe871/pillow-12.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:03e7e372d5240cc23e9f07deca4d775c0817bffc641b01e9c3af208dbd300987", upload-time = "2026-04-01T14:43:18.268Z" }, - { url = "https://files.pythonhosted.org/packages/e9/9e/c05e19657fd57841e476be1ab46c4d501bffbadbafdc31a6d665f8b737b6/pillow-12.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b86024e52a1b269467a802258c25521e6d742349d760728092e1bc2d135b4d76", upload-time = "2026-04-01T14:43:20.716Z" }, - { url = "https://files.pythonhosted.org/packages/2b/54/1789c455ed10176066b6e7e6da1b01e50e36f94ba584dc68d9eebfe9156d/pillow-12.2.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7371b48c4fa448d20d2714c9a1f775a81155050d383333e0a6c15b1123dda005", upload-time = "2026-04-01T14:43:23.443Z" }, - { url = "https://files.pythonhosted.org/packages/43/e3/fdc657359e919462369869f1c9f0e973f353f9a9ee295a39b1fea8ee1a77/pillow-12.2.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62f5409336adb0663b7caa0da5c7d9e7bdbaae9ce761d34669420c2a801b2780", upload-time = "2026-04-01T14:43:26.758Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f8/2f6825e441d5b1959d2ca5adec984210f1ec086435b0ed5f52c19b3b8a6e/pillow-12.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:01afa7cf67f74f09523699b4e88c73fb55c13346d212a59a2db1f86b0a63e8c5", upload-time = "2026-04-01T14:43:29.56Z" }, - { url = "https://files.pythonhosted.org/packages/67/f9/029a27095ad20f854f9dba026b3ea6428548316e057e6fc3545409e86651/pillow-12.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc3d34d4a8fbec3e88a79b92e5465e0f9b842b628675850d860b8bd300b159f5", upload-time = "2026-04-01T14:43:32.091Z" }, - { url = "https://files.pythonhosted.org/packages/be/42/025cfe05d1be22dbfdb4f264fe9de1ccda83f66e4fc3aac94748e784af04/pillow-12.2.0-cp312-cp312-win32.whl", hash = "sha256:58f62cc0f00fd29e64b29f4fd923ffdb3859c9f9e6105bfc37ba1d08994e8940", upload-time = "2026-04-01T14:43:34.601Z" }, - { url = "https://files.pythonhosted.org/packages/5d/7b/25a221d2c761c6a8ae21bfa3874988ff2583e19cf8a27bf2fee358df7942/pillow-12.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:7f84204dee22a783350679a0333981df803dac21a0190d706a50475e361c93f5", upload-time = "2026-04-01T14:43:37.213Z" }, - { url = "https://files.pythonhosted.org/packages/10/e1/542a474affab20fd4a0f1836cb234e8493519da6b76899e30bcc5d990b8b/pillow-12.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:af73337013e0b3b46f175e79492d96845b16126ddf79c438d7ea7ff27783a414", upload-time = "2026-04-01T14:43:39.421Z" }, + { url = "https://files.pythonhosted.org/packages/58/be/7482c8a5ebebbc6470b3eb791812fff7d5e0216c2be3827b30b8bb6603ed/pillow-12.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2d192a155bbcec180f8564f693e6fd9bccff5a7af9b32e2e4bf8c9c69dbad6b5", size = 5308279, upload-time = "2026-04-01T14:43:13.246Z" }, + { url = "https://files.pythonhosted.org/packages/d8/95/0a351b9289c2b5cbde0bacd4a83ebc44023e835490a727b2a3bd60ddc0f4/pillow-12.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3f40b3c5a968281fd507d519e444c35f0ff171237f4fdde090dd60699458421", size = 4695490, upload-time = "2026-04-01T14:43:15.584Z" }, + { url = "https://files.pythonhosted.org/packages/de/af/4e8e6869cbed569d43c416fad3dc4ecb944cb5d9492defaed89ddd6fe871/pillow-12.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:03e7e372d5240cc23e9f07deca4d775c0817bffc641b01e9c3af208dbd300987", size = 6284462, upload-time = "2026-04-01T14:43:18.268Z" }, + { url = "https://files.pythonhosted.org/packages/e9/9e/c05e19657fd57841e476be1ab46c4d501bffbadbafdc31a6d665f8b737b6/pillow-12.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b86024e52a1b269467a802258c25521e6d742349d760728092e1bc2d135b4d76", size = 8094744, upload-time = "2026-04-01T14:43:20.716Z" }, + { url = "https://files.pythonhosted.org/packages/2b/54/1789c455ed10176066b6e7e6da1b01e50e36f94ba584dc68d9eebfe9156d/pillow-12.2.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7371b48c4fa448d20d2714c9a1f775a81155050d383333e0a6c15b1123dda005", size = 6398371, upload-time = "2026-04-01T14:43:23.443Z" }, + { url = "https://files.pythonhosted.org/packages/43/e3/fdc657359e919462369869f1c9f0e973f353f9a9ee295a39b1fea8ee1a77/pillow-12.2.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62f5409336adb0663b7caa0da5c7d9e7bdbaae9ce761d34669420c2a801b2780", size = 7087215, upload-time = "2026-04-01T14:43:26.758Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f8/2f6825e441d5b1959d2ca5adec984210f1ec086435b0ed5f52c19b3b8a6e/pillow-12.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:01afa7cf67f74f09523699b4e88c73fb55c13346d212a59a2db1f86b0a63e8c5", size = 6509783, upload-time = "2026-04-01T14:43:29.56Z" }, + { url = "https://files.pythonhosted.org/packages/67/f9/029a27095ad20f854f9dba026b3ea6428548316e057e6fc3545409e86651/pillow-12.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc3d34d4a8fbec3e88a79b92e5465e0f9b842b628675850d860b8bd300b159f5", size = 7212112, upload-time = "2026-04-01T14:43:32.091Z" }, + { url = "https://files.pythonhosted.org/packages/be/42/025cfe05d1be22dbfdb4f264fe9de1ccda83f66e4fc3aac94748e784af04/pillow-12.2.0-cp312-cp312-win32.whl", hash = "sha256:58f62cc0f00fd29e64b29f4fd923ffdb3859c9f9e6105bfc37ba1d08994e8940", size = 6378489, upload-time = "2026-04-01T14:43:34.601Z" }, + { url = "https://files.pythonhosted.org/packages/5d/7b/25a221d2c761c6a8ae21bfa3874988ff2583e19cf8a27bf2fee358df7942/pillow-12.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:7f84204dee22a783350679a0333981df803dac21a0190d706a50475e361c93f5", size = 7084129, upload-time = "2026-04-01T14:43:37.213Z" }, + { url = "https://files.pythonhosted.org/packages/10/e1/542a474affab20fd4a0f1836cb234e8493519da6b76899e30bcc5d990b8b/pillow-12.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:af73337013e0b3b46f175e79492d96845b16126ddf79c438d7ea7ff27783a414", size = 2463612, upload-time = "2026-04-01T14:43:39.421Z" }, ] - [[package]] name = "platformdirs" version = "4.9.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9f/4a/0883b8e3802965322523f0b200ecf33d31f10991d0401162f4b23c698b42/platformdirs-4.9.6.tar.gz", hash = "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a", upload-time = "2026-04-09T00:04:10.812Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9f/4a/0883b8e3802965322523f0b200ecf33d31f10991d0401162f4b23c698b42/platformdirs-4.9.6.tar.gz", hash = "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a", size = 29400, upload-time = "2026-04-09T00:04:10.812Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/75/a6/a0a304dc33b49145b21f4808d763822111e67d1c3a32b524a1baf947b6e1/platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917", upload-time = "2026-04-09T00:04:09.463Z" }, + { url = "https://files.pythonhosted.org/packages/75/a6/a0a304dc33b49145b21f4808d763822111e67d1c3a32b524a1baf947b6e1/platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917", size = 21348, upload-time = "2026-04-09T00:04:09.463Z" }, ] - [[package]] name = "pluggy" version = "1.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", upload-time = "2025-05-15T12:30:07.975Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", upload-time = "2025-05-15T12:30:06.134Z" }, + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, ] - [[package]] name = "pre-commit" version = "4.1.0" @@ -848,68 +794,62 @@ dependencies = [ { name = "pyyaml" }, { name = "virtualenv" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2a/13/b62d075317d8686071eb843f0bb1f195eb332f48869d3c31a4c6f1e063ac/pre_commit-4.1.0.tar.gz", hash = "sha256:ae3f018575a588e30dfddfab9a05448bfbd6b73d78709617b5a2b853549716d4", upload-time = "2025-01-20T18:31:48.681Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2a/13/b62d075317d8686071eb843f0bb1f195eb332f48869d3c31a4c6f1e063ac/pre_commit-4.1.0.tar.gz", hash = "sha256:ae3f018575a588e30dfddfab9a05448bfbd6b73d78709617b5a2b853549716d4", size = 193330, upload-time = "2025-01-20T18:31:48.681Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/43/b3/df14c580d82b9627d173ceea305ba898dca135feb360b6d84019d0803d3b/pre_commit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d29e7cb346295bcc1cc75fc3e92e343495e3ea0196c9ec6ba53f49f10ab6ae7b", upload-time = "2025-01-20T18:31:47.319Z" }, + { url = "https://files.pythonhosted.org/packages/43/b3/df14c580d82b9627d173ceea305ba898dca135feb360b6d84019d0803d3b/pre_commit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d29e7cb346295bcc1cc75fc3e92e343495e3ea0196c9ec6ba53f49f10ab6ae7b", size = 220560, upload-time = "2025-01-20T18:31:47.319Z" }, ] - [[package]] name = "protobuf" version = "6.33.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/66/70/e908e9c5e52ef7c3a6c7902c9dfbb34c7e29c25d2f81ade3856445fd5c94/protobuf-6.33.6.tar.gz", hash = "sha256:a6768d25248312c297558af96a9f9c929e8c4cee0659cb07e780731095f38135", upload-time = "2026-03-18T19:05:00.988Z" } +sdist = { url = "https://files.pythonhosted.org/packages/66/70/e908e9c5e52ef7c3a6c7902c9dfbb34c7e29c25d2f81ade3856445fd5c94/protobuf-6.33.6.tar.gz", hash = "sha256:a6768d25248312c297558af96a9f9c929e8c4cee0659cb07e780731095f38135", size = 444531, upload-time = "2026-03-18T19:05:00.988Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/9f/2f509339e89cfa6f6a4c4ff50438db9ca488dec341f7e454adad60150b00/protobuf-6.33.6-cp310-abi3-win32.whl", hash = "sha256:7d29d9b65f8afef196f8334e80d6bc1d5d4adedb449971fefd3723824e6e77d3", upload-time = "2026-03-18T19:04:48.373Z" }, - { url = "https://files.pythonhosted.org/packages/76/5d/683efcd4798e0030c1bab27374fd13a89f7c2515fb1f3123efdfaa5eab57/protobuf-6.33.6-cp310-abi3-win_amd64.whl", hash = "sha256:0cd27b587afca21b7cfa59a74dcbd48a50f0a6400cfb59391340ad729d91d326", upload-time = "2026-03-18T19:04:50.381Z" }, - { url = "https://files.pythonhosted.org/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:9720e6961b251bde64edfdab7d500725a2af5280f3f4c87e57c0208376aa8c3a", upload-time = "2026-03-18T19:04:51.866Z" }, - { url = "https://files.pythonhosted.org/packages/ee/90/b3c01fdec7d2f627b3a6884243ba328c1217ed2d978def5c12dc50d328a3/protobuf-6.33.6-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:e2afbae9b8e1825e3529f88d514754e094278bb95eadc0e199751cdd9a2e82a2", upload-time = "2026-03-18T19:04:53.096Z" }, - { url = "https://files.pythonhosted.org/packages/9b/ca/25afc144934014700c52e05103c2421997482d561f3101ff352e1292fb81/protobuf-6.33.6-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:c96c37eec15086b79762ed265d59ab204dabc53056e3443e702d2681f4b39ce3", upload-time = "2026-03-18T19:04:54.616Z" }, - { url = "https://files.pythonhosted.org/packages/16/92/d1e32e3e0d894fe00b15ce28ad4944ab692713f2e7f0a99787405e43533a/protobuf-6.33.6-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:e9db7e292e0ab79dd108d7f1a94fe31601ce1ee3f7b79e0692043423020b0593", upload-time = "2026-03-18T19:04:55.768Z" }, - { url = "https://files.pythonhosted.org/packages/c4/72/02445137af02769918a93807b2b7890047c32bfb9f90371cbc12688819eb/protobuf-6.33.6-py3-none-any.whl", hash = "sha256:77179e006c476e69bf8e8ce866640091ec42e1beb80b213c3900006ecfba6901", upload-time = "2026-03-18T19:04:59.826Z" }, + { url = "https://files.pythonhosted.org/packages/fc/9f/2f509339e89cfa6f6a4c4ff50438db9ca488dec341f7e454adad60150b00/protobuf-6.33.6-cp310-abi3-win32.whl", hash = "sha256:7d29d9b65f8afef196f8334e80d6bc1d5d4adedb449971fefd3723824e6e77d3", size = 425739, upload-time = "2026-03-18T19:04:48.373Z" }, + { url = "https://files.pythonhosted.org/packages/76/5d/683efcd4798e0030c1bab27374fd13a89f7c2515fb1f3123efdfaa5eab57/protobuf-6.33.6-cp310-abi3-win_amd64.whl", hash = "sha256:0cd27b587afca21b7cfa59a74dcbd48a50f0a6400cfb59391340ad729d91d326", size = 437089, upload-time = "2026-03-18T19:04:50.381Z" }, + { url = "https://files.pythonhosted.org/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:9720e6961b251bde64edfdab7d500725a2af5280f3f4c87e57c0208376aa8c3a", size = 427737, upload-time = "2026-03-18T19:04:51.866Z" }, + { url = "https://files.pythonhosted.org/packages/ee/90/b3c01fdec7d2f627b3a6884243ba328c1217ed2d978def5c12dc50d328a3/protobuf-6.33.6-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:e2afbae9b8e1825e3529f88d514754e094278bb95eadc0e199751cdd9a2e82a2", size = 324610, upload-time = "2026-03-18T19:04:53.096Z" }, + { url = "https://files.pythonhosted.org/packages/9b/ca/25afc144934014700c52e05103c2421997482d561f3101ff352e1292fb81/protobuf-6.33.6-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:c96c37eec15086b79762ed265d59ab204dabc53056e3443e702d2681f4b39ce3", size = 339381, upload-time = "2026-03-18T19:04:54.616Z" }, + { url = "https://files.pythonhosted.org/packages/16/92/d1e32e3e0d894fe00b15ce28ad4944ab692713f2e7f0a99787405e43533a/protobuf-6.33.6-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:e9db7e292e0ab79dd108d7f1a94fe31601ce1ee3f7b79e0692043423020b0593", size = 323436, upload-time = "2026-03-18T19:04:55.768Z" }, + { url = "https://files.pythonhosted.org/packages/c4/72/02445137af02769918a93807b2b7890047c32bfb9f90371cbc12688819eb/protobuf-6.33.6-py3-none-any.whl", hash = "sha256:77179e006c476e69bf8e8ce866640091ec42e1beb80b213c3900006ecfba6901", size = 170656, upload-time = "2026-03-18T19:04:59.826Z" }, ] - [[package]] name = "py-cpuinfo" version = "9.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/37/a8/d832f7293ebb21690860d2e01d8115e5ff6f2ae8bbdc953f0eb0fa4bd2c7/py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690", upload-time = "2022-10-25T20:38:06.303Z" } +sdist = { url = "https://files.pythonhosted.org/packages/37/a8/d832f7293ebb21690860d2e01d8115e5ff6f2ae8bbdc953f0eb0fa4bd2c7/py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690", size = 104716, upload-time = "2022-10-25T20:38:06.303Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/a9/023730ba63db1e494a271cb018dcd361bd2c917ba7004c3e49d5daf795a2/py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5", upload-time = "2022-10-25T20:38:27.636Z" }, + { url = "https://files.pythonhosted.org/packages/e0/a9/023730ba63db1e494a271cb018dcd361bd2c917ba7004c3e49d5daf795a2/py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5", size = 22335, upload-time = "2022-10-25T20:38:27.636Z" }, ] - [[package]] name = "py4j" version = "0.10.9.9" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/38/31/0b210511177070c8d5d3059556194352e5753602fa64b85b7ab81ec1a009/py4j-0.10.9.9.tar.gz", hash = "sha256:f694cad19efa5bd1dee4f3e5270eb406613c974394035e5bfc4ec1aba870b879", upload-time = "2025-01-15T03:53:18.624Z" } +sdist = { url = "https://files.pythonhosted.org/packages/38/31/0b210511177070c8d5d3059556194352e5753602fa64b85b7ab81ec1a009/py4j-0.10.9.9.tar.gz", hash = "sha256:f694cad19efa5bd1dee4f3e5270eb406613c974394035e5bfc4ec1aba870b879", size = 761089, upload-time = "2025-01-15T03:53:18.624Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl", hash = "sha256:c7c26e4158defb37b0bb124933163641a2ff6e3a3913f7811b0ddbe07ed61533", upload-time = "2025-01-15T03:53:15.648Z" }, + { url = "https://files.pythonhosted.org/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl", hash = "sha256:c7c26e4158defb37b0bb124933163641a2ff6e3a3913f7811b0ddbe07ed61533", size = 203008, upload-time = "2025-01-15T03:53:15.648Z" }, ] - [[package]] name = "pyarrow" version = "19.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7f/09/a9046344212690f0632b9c709f9bf18506522feb333c894d0de81d62341a/pyarrow-19.0.1.tar.gz", hash = "sha256:3bf266b485df66a400f282ac0b6d1b500b9d2ae73314a153dbe97d6d5cc8a99e", upload-time = "2025-02-18T18:55:57.027Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7f/09/a9046344212690f0632b9c709f9bf18506522feb333c894d0de81d62341a/pyarrow-19.0.1.tar.gz", hash = "sha256:3bf266b485df66a400f282ac0b6d1b500b9d2ae73314a153dbe97d6d5cc8a99e", size = 1129437, upload-time = "2025-02-18T18:55:57.027Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b4/94e828704b050e723f67d67c3535cf7076c7432cd4cf046e4bb3b96a9c9d/pyarrow-19.0.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:80b2ad2b193e7d19e81008a96e313fbd53157945c7be9ac65f44f8937a55427b", upload-time = "2025-02-18T18:53:00.062Z" }, - { url = "https://files.pythonhosted.org/packages/7e/3b/4692965e04bb1df55e2c314c4296f1eb12b4f3052d4cf43d29e076aedf66/pyarrow-19.0.1-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:ee8dec072569f43835932a3b10c55973593abc00936c202707a4ad06af7cb294", upload-time = "2025-02-18T18:53:06.581Z" }, - { url = "https://files.pythonhosted.org/packages/22/f7/2239af706252c6582a5635c35caa17cb4d401cd74a87821ef702e3888957/pyarrow-19.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d5d1ec7ec5324b98887bdc006f4d2ce534e10e60f7ad995e7875ffa0ff9cb14", upload-time = "2025-02-18T18:53:11.958Z" }, - { url = "https://files.pythonhosted.org/packages/fb/e3/c9661b2b2849cfefddd9fd65b64e093594b231b472de08ff658f76c732b2/pyarrow-19.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3ad4c0eb4e2a9aeb990af6c09e6fa0b195c8c0e7b272ecc8d4d2b6574809d34", upload-time = "2025-02-18T18:53:17.678Z" }, - { url = "https://files.pythonhosted.org/packages/fe/4f/a2c0ed309167ef436674782dfee4a124570ba64299c551e38d3fdaf0a17b/pyarrow-19.0.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:d383591f3dcbe545f6cc62daaef9c7cdfe0dff0fb9e1c8121101cabe9098cfa6", upload-time = "2025-02-18T18:53:26.263Z" }, - { url = "https://files.pythonhosted.org/packages/27/2e/29bb28a7102a6f71026a9d70d1d61df926887e36ec797f2e6acfd2dd3867/pyarrow-19.0.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b4c4156a625f1e35d6c0b2132635a237708944eb41df5fbe7d50f20d20c17832", upload-time = "2025-02-18T18:53:33.063Z" }, - { url = "https://files.pythonhosted.org/packages/16/33/2a67c0f783251106aeeee516f4806161e7b481f7d744d0d643d2f30230a5/pyarrow-19.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:5bd1618ae5e5476b7654c7b55a6364ae87686d4724538c24185bbb2952679960", upload-time = "2025-02-18T18:53:38.462Z" }, + { url = "https://files.pythonhosted.org/packages/78/b4/94e828704b050e723f67d67c3535cf7076c7432cd4cf046e4bb3b96a9c9d/pyarrow-19.0.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:80b2ad2b193e7d19e81008a96e313fbd53157945c7be9ac65f44f8937a55427b", size = 30670749, upload-time = "2025-02-18T18:53:00.062Z" }, + { url = "https://files.pythonhosted.org/packages/7e/3b/4692965e04bb1df55e2c314c4296f1eb12b4f3052d4cf43d29e076aedf66/pyarrow-19.0.1-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:ee8dec072569f43835932a3b10c55973593abc00936c202707a4ad06af7cb294", size = 32128007, upload-time = "2025-02-18T18:53:06.581Z" }, + { url = "https://files.pythonhosted.org/packages/22/f7/2239af706252c6582a5635c35caa17cb4d401cd74a87821ef702e3888957/pyarrow-19.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d5d1ec7ec5324b98887bdc006f4d2ce534e10e60f7ad995e7875ffa0ff9cb14", size = 41144566, upload-time = "2025-02-18T18:53:11.958Z" }, + { url = "https://files.pythonhosted.org/packages/fb/e3/c9661b2b2849cfefddd9fd65b64e093594b231b472de08ff658f76c732b2/pyarrow-19.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3ad4c0eb4e2a9aeb990af6c09e6fa0b195c8c0e7b272ecc8d4d2b6574809d34", size = 42202991, upload-time = "2025-02-18T18:53:17.678Z" }, + { url = "https://files.pythonhosted.org/packages/fe/4f/a2c0ed309167ef436674782dfee4a124570ba64299c551e38d3fdaf0a17b/pyarrow-19.0.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:d383591f3dcbe545f6cc62daaef9c7cdfe0dff0fb9e1c8121101cabe9098cfa6", size = 40507986, upload-time = "2025-02-18T18:53:26.263Z" }, + { url = "https://files.pythonhosted.org/packages/27/2e/29bb28a7102a6f71026a9d70d1d61df926887e36ec797f2e6acfd2dd3867/pyarrow-19.0.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b4c4156a625f1e35d6c0b2132635a237708944eb41df5fbe7d50f20d20c17832", size = 42087026, upload-time = "2025-02-18T18:53:33.063Z" }, + { url = "https://files.pythonhosted.org/packages/16/33/2a67c0f783251106aeeee516f4806161e7b481f7d744d0d643d2f30230a5/pyarrow-19.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:5bd1618ae5e5476b7654c7b55a6364ae87686d4724538c24185bbb2952679960", size = 25250108, upload-time = "2025-02-18T18:53:38.462Z" }, ] - [[package]] name = "pyasn1" version = "0.6.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5c/5f/6583902b6f79b399c9c40674ac384fd9cd77805f9e6205075f828ef11fb2/pyasn1-0.6.3.tar.gz", hash = "sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf", upload-time = "2026-03-17T01:06:53.382Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/5f/6583902b6f79b399c9c40674ac384fd9cd77805f9e6205075f828ef11fb2/pyasn1-0.6.3.tar.gz", hash = "sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf", size = 148685, upload-time = "2026-03-17T01:06:53.382Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl", hash = "sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde", upload-time = "2026-03-17T01:06:52.036Z" }, + { url = "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl", hash = "sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde", size = 83997, upload-time = "2026-03-17T01:06:52.036Z" }, ] - [[package]] name = "pyasn1-modules" version = "0.4.2" @@ -917,20 +857,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyasn1" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", upload-time = "2025-03-28T02:41:22.17Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", upload-time = "2025-03-28T02:41:19.028Z" }, + { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, ] - [[package]] name = "pycparser" version = "3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", upload-time = "2026-01-21T14:26:51.89Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", upload-time = "2026-01-21T14:26:50.693Z" }, + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, ] - [[package]] name = "pydantic" version = "2.11.7" @@ -941,11 +879,10 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", upload-time = "2025-06-14T08:33:17.137Z" } +sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350, upload-time = "2025-06-14T08:33:17.137Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", upload-time = "2025-06-14T08:33:14.905Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782, upload-time = "2025-06-14T08:33:14.905Z" }, ] - [[package]] name = "pydantic-core" version = "2.33.2" @@ -953,24 +890,23 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", upload-time = "2025-04-23T18:33:52.104Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", upload-time = "2025-04-23T18:31:25.863Z" }, - { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", upload-time = "2025-04-23T18:31:27.341Z" }, - { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", upload-time = "2025-04-23T18:31:28.956Z" }, - { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", upload-time = "2025-04-23T18:31:31.025Z" }, - { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", upload-time = "2025-04-23T18:31:32.514Z" }, - { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", upload-time = "2025-04-23T18:31:33.958Z" }, - { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", upload-time = "2025-04-23T18:31:39.095Z" }, - { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", upload-time = "2025-04-23T18:31:41.034Z" }, - { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", upload-time = "2025-04-23T18:31:42.757Z" }, - { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", upload-time = "2025-04-23T18:31:44.304Z" }, - { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", upload-time = "2025-04-23T18:31:45.891Z" }, - { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", upload-time = "2025-04-23T18:31:47.819Z" }, - { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", upload-time = "2025-04-23T18:31:49.635Z" }, - { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", upload-time = "2025-04-23T18:31:51.609Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" }, + { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" }, + { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" }, + { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" }, + { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" }, + { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" }, + { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" }, + { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" }, + { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" }, + { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" }, + { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" }, + { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" }, + { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" }, ] - [[package]] name = "pydoc-markdown" version = "4.8.2" @@ -991,20 +927,18 @@ dependencies = [ { name = "watchdog" }, { name = "yapf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e1/8a/2c7f7ad656d22371a596d232fc140327b958d7f1d491b889632ea0cb7e87/pydoc_markdown-4.8.2.tar.gz", hash = "sha256:fb6c927e31386de17472d42f9bd3d3be2905977d026f6216881c65145aa67f0b", upload-time = "2023-06-26T12:37:01.152Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/8a/2c7f7ad656d22371a596d232fc140327b958d7f1d491b889632ea0cb7e87/pydoc_markdown-4.8.2.tar.gz", hash = "sha256:fb6c927e31386de17472d42f9bd3d3be2905977d026f6216881c65145aa67f0b", size = 44506, upload-time = "2023-06-26T12:37:01.152Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/5a/ce0b056d9a95fd0c06a6cfa5972477d79353392d19230c748a7ba5a9df04/pydoc_markdown-4.8.2-py3-none-any.whl", hash = "sha256:203f74119e6bb2f9deba43d452422de7c8ec31955b61e0620fa4dd8c2611715f", upload-time = "2023-06-26T12:36:59.502Z" }, + { url = "https://files.pythonhosted.org/packages/83/5a/ce0b056d9a95fd0c06a6cfa5972477d79353392d19230c748a7ba5a9df04/pydoc_markdown-4.8.2-py3-none-any.whl", hash = "sha256:203f74119e6bb2f9deba43d452422de7c8ec31955b61e0620fa4dd8c2611715f", size = 67830, upload-time = "2023-06-26T12:36:59.502Z" }, ] - [[package]] name = "pyparsing" version = "3.3.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", upload-time = "2026-01-21T03:57:59.36Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", upload-time = "2026-01-21T03:57:55.912Z" }, + { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, ] - [[package]] name = "pyspark" version = "4.0.0" @@ -1012,8 +946,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "py4j" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9d/0e/5b38d51f1b1c2618cccfbf35093268665af9a3bdb493e5a3ecd991def633/pyspark-4.0.0.tar.gz", hash = "sha256:38db1b4f6095a080d7605e578d775528990e66dc326311d93e94a71cfc24e5a5", upload-time = "2025-05-23T03:29:33.916Z" } - +sdist = { url = "https://files.pythonhosted.org/packages/9d/0e/5b38d51f1b1c2618cccfbf35093268665af9a3bdb493e5a3ecd991def633/pyspark-4.0.0.tar.gz", hash = "sha256:38db1b4f6095a080d7605e578d775528990e66dc326311d93e94a71cfc24e5a5", size = 434132212, upload-time = "2025-05-23T03:29:33.916Z" } [[package]] name = "pytest" version = "8.3.5" @@ -1024,11 +957,10 @@ dependencies = [ { name = "packaging" }, { name = "pluggy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", upload-time = "2025-03-02T12:54:54.503Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891, upload-time = "2025-03-02T12:54:54.503Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", upload-time = "2025-03-02T12:54:52.069Z" }, + { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634, upload-time = "2025-03-02T12:54:52.069Z" }, ] - [[package]] name = "pytest-benchmark" version = "5.1.0" @@ -1037,11 +969,10 @@ dependencies = [ { name = "py-cpuinfo" }, { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/39/d0/a8bd08d641b393db3be3819b03e2d9bb8760ca8479080a26a5f6e540e99c/pytest-benchmark-5.1.0.tar.gz", hash = "sha256:9ea661cdc292e8231f7cd4c10b0319e56a2118e2c09d9f50e1b3d150d2aca105", upload-time = "2024-10-30T11:51:48.521Z" } +sdist = { url = "https://files.pythonhosted.org/packages/39/d0/a8bd08d641b393db3be3819b03e2d9bb8760ca8479080a26a5f6e540e99c/pytest-benchmark-5.1.0.tar.gz", hash = "sha256:9ea661cdc292e8231f7cd4c10b0319e56a2118e2c09d9f50e1b3d150d2aca105", size = 337810, upload-time = "2024-10-30T11:51:48.521Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/d6/b41653199ea09d5969d4e385df9bbfd9a100f28ca7e824ce7c0a016e3053/pytest_benchmark-5.1.0-py3-none-any.whl", hash = "sha256:922de2dfa3033c227c96da942d1878191afa135a29485fb942e85dff1c592c89", upload-time = "2024-10-30T11:51:45.94Z" }, + { url = "https://files.pythonhosted.org/packages/9e/d6/b41653199ea09d5969d4e385df9bbfd9a100f28ca7e824ce7c0a016e3053/pytest_benchmark-5.1.0-py3-none-any.whl", hash = "sha256:922de2dfa3033c227c96da942d1878191afa135a29485fb942e85dff1c592c89", size = 44259, upload-time = "2024-10-30T11:51:45.94Z" }, ] - [[package]] name = "pytest-cov" version = "6.0.0" @@ -1050,11 +981,10 @@ dependencies = [ { name = "coverage" }, { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", upload-time = "2024-10-29T20:13:35.363Z" } +sdist = { url = "https://files.pythonhosted.org/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", size = 66945, upload-time = "2024-10-29T20:13:35.363Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", upload-time = "2024-10-29T20:13:33.215Z" }, + { url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", size = 22949, upload-time = "2024-10-29T20:13:33.215Z" }, ] - [[package]] name = "pytest-mock" version = "3.15.1" @@ -1062,11 +992,10 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/68/14/eb014d26be205d38ad5ad20d9a80f7d201472e08167f0bb4361e251084a9/pytest_mock-3.15.1.tar.gz", hash = "sha256:1849a238f6f396da19762269de72cb1814ab44416fa73a8686deac10b0d87a0f", upload-time = "2025-09-16T16:37:27.081Z" } +sdist = { url = "https://files.pythonhosted.org/packages/68/14/eb014d26be205d38ad5ad20d9a80f7d201472e08167f0bb4361e251084a9/pytest_mock-3.15.1.tar.gz", hash = "sha256:1849a238f6f396da19762269de72cb1814ab44416fa73a8686deac10b0d87a0f", size = 34036, upload-time = "2025-09-16T16:37:27.081Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5a/cc/06253936f4a7fa2e0f48dfe6d851d9c56df896a9ab09ac019d70b760619c/pytest_mock-3.15.1-py3-none-any.whl", hash = "sha256:0a25e2eb88fe5168d535041d09a4529a188176ae608a6d249ee65abc0949630d", upload-time = "2025-09-16T16:37:25.734Z" }, + { url = "https://files.pythonhosted.org/packages/5a/cc/06253936f4a7fa2e0f48dfe6d851d9c56df896a9ab09ac019d70b760619c/pytest_mock-3.15.1-py3-none-any.whl", hash = "sha256:0a25e2eb88fe5168d535041d09a4529a188176ae608a6d249ee65abc0949630d", size = 10095, upload-time = "2025-09-16T16:37:25.734Z" }, ] - [[package]] name = "python-dateutil" version = "2.9.0.post0" @@ -1074,11 +1003,10 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", upload-time = "2024-03-01T18:36:20.211Z" } +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", upload-time = "2024-03-01T18:36:18.57Z" }, + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, ] - [[package]] name = "python-discovery" version = "1.2.2" @@ -1087,52 +1015,48 @@ dependencies = [ { name = "filelock" }, { name = "platformdirs" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/de/ef/3bae0e537cfe91e8431efcba4434463d2c5a65f5a89edd47c6cf2f03c55f/python_discovery-1.2.2.tar.gz", hash = "sha256:876e9c57139eb757cb5878cbdd9ae5379e5d96266c99ef731119e04fffe533bb", upload-time = "2026-04-07T17:28:49.249Z" } +sdist = { url = "https://files.pythonhosted.org/packages/de/ef/3bae0e537cfe91e8431efcba4434463d2c5a65f5a89edd47c6cf2f03c55f/python_discovery-1.2.2.tar.gz", hash = "sha256:876e9c57139eb757cb5878cbdd9ae5379e5d96266c99ef731119e04fffe533bb", size = 58872, upload-time = "2026-04-07T17:28:49.249Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d8/db/795879cc3ddfe338599bddea6388cc5100b088db0a4caf6e6c1af1c27e04/python_discovery-1.2.2-py3-none-any.whl", hash = "sha256:e1ae95d9af875e78f15e19aed0c6137ab1bb49c200f21f5061786490c9585c7a", upload-time = "2026-04-07T17:28:48.09Z" }, + { url = "https://files.pythonhosted.org/packages/d8/db/795879cc3ddfe338599bddea6388cc5100b088db0a4caf6e6c1af1c27e04/python_discovery-1.2.2-py3-none-any.whl", hash = "sha256:e1ae95d9af875e78f15e19aed0c6137ab1bb49c200f21f5061786490c9585c7a", size = 31894, upload-time = "2026-04-07T17:28:48.09Z" }, ] - [[package]] name = "pytokens" version = "0.4.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b6/34/b4e015b99031667a7b960f888889c5bd34ef585c85e1cb56a594b92836ac/pytokens-0.4.1.tar.gz", hash = "sha256:292052fe80923aae2260c073f822ceba21f3872ced9a68bb7953b348e561179a", upload-time = "2026-01-30T01:03:45.924Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b6/34/b4e015b99031667a7b960f888889c5bd34ef585c85e1cb56a594b92836ac/pytokens-0.4.1.tar.gz", hash = "sha256:292052fe80923aae2260c073f822ceba21f3872ced9a68bb7953b348e561179a", size = 23015, upload-time = "2026-01-30T01:03:45.924Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/5d/e44573011401fb82e9d51e97f1290ceb377800fb4eed650b96f4753b499c/pytokens-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:140709331e846b728475786df8aeb27d24f48cbcf7bcd449f8de75cae7a45083", upload-time = "2026-01-30T01:03:06.473Z" }, - { url = "https://files.pythonhosted.org/packages/f0/e6/5bbc3019f8e6f21d09c41f8b8654536117e5e211a85d89212d59cbdab381/pytokens-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d6c4268598f762bc8e91f5dbf2ab2f61f7b95bdc07953b602db879b3c8c18e1", upload-time = "2026-01-30T01:03:08.177Z" }, - { url = "https://files.pythonhosted.org/packages/bf/3c/2d5297d82286f6f3d92770289fd439956b201c0a4fc7e72efb9b2293758e/pytokens-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24afde1f53d95348b5a0eb19488661147285ca4dd7ed752bbc3e1c6242a304d1", upload-time = "2026-01-30T01:03:09.756Z" }, - { url = "https://files.pythonhosted.org/packages/20/01/7436e9ad693cebda0551203e0bf28f7669976c60ad07d6402098208476de/pytokens-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5ad948d085ed6c16413eb5fec6b3e02fa00dc29a2534f088d3302c47eb59adf9", upload-time = "2026-01-30T01:03:10.957Z" }, - { url = "https://files.pythonhosted.org/packages/2e/df/533c82a3c752ba13ae7ef238b7f8cdd272cf1475f03c63ac6cf3fcfb00b6/pytokens-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:3f901fe783e06e48e8cbdc82d631fca8f118333798193e026a50ce1b3757ea68", upload-time = "2026-01-30T01:03:12.066Z" }, - { url = "https://files.pythonhosted.org/packages/c6/78/397db326746f0a342855b81216ae1f0a32965deccfd7c830a2dbc66d2483/pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de", upload-time = "2026-01-30T01:03:45.029Z" }, + { url = "https://files.pythonhosted.org/packages/41/5d/e44573011401fb82e9d51e97f1290ceb377800fb4eed650b96f4753b499c/pytokens-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:140709331e846b728475786df8aeb27d24f48cbcf7bcd449f8de75cae7a45083", size = 160663, upload-time = "2026-01-30T01:03:06.473Z" }, + { url = "https://files.pythonhosted.org/packages/f0/e6/5bbc3019f8e6f21d09c41f8b8654536117e5e211a85d89212d59cbdab381/pytokens-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d6c4268598f762bc8e91f5dbf2ab2f61f7b95bdc07953b602db879b3c8c18e1", size = 255626, upload-time = "2026-01-30T01:03:08.177Z" }, + { url = "https://files.pythonhosted.org/packages/bf/3c/2d5297d82286f6f3d92770289fd439956b201c0a4fc7e72efb9b2293758e/pytokens-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24afde1f53d95348b5a0eb19488661147285ca4dd7ed752bbc3e1c6242a304d1", size = 269779, upload-time = "2026-01-30T01:03:09.756Z" }, + { url = "https://files.pythonhosted.org/packages/20/01/7436e9ad693cebda0551203e0bf28f7669976c60ad07d6402098208476de/pytokens-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5ad948d085ed6c16413eb5fec6b3e02fa00dc29a2534f088d3302c47eb59adf9", size = 268076, upload-time = "2026-01-30T01:03:10.957Z" }, + { url = "https://files.pythonhosted.org/packages/2e/df/533c82a3c752ba13ae7ef238b7f8cdd272cf1475f03c63ac6cf3fcfb00b6/pytokens-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:3f901fe783e06e48e8cbdc82d631fca8f118333798193e026a50ce1b3757ea68", size = 103552, upload-time = "2026-01-30T01:03:12.066Z" }, + { url = "https://files.pythonhosted.org/packages/c6/78/397db326746f0a342855b81216ae1f0a32965deccfd7c830a2dbc66d2483/pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de", size = 13729, upload-time = "2026-01-30T01:03:45.029Z" }, ] - [[package]] name = "pytz" version = "2026.1.post1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/56/db/b8721d71d945e6a8ac63c0fc900b2067181dbb50805958d4d4661cf7d277/pytz-2026.1.post1.tar.gz", hash = "sha256:3378dde6a0c3d26719182142c56e60c7f9af7e968076f31aae569d72a0358ee1", upload-time = "2026-03-03T07:47:50.683Z" } +sdist = { url = "https://files.pythonhosted.org/packages/56/db/b8721d71d945e6a8ac63c0fc900b2067181dbb50805958d4d4661cf7d277/pytz-2026.1.post1.tar.gz", hash = "sha256:3378dde6a0c3d26719182142c56e60c7f9af7e968076f31aae569d72a0358ee1", size = 321088, upload-time = "2026-03-03T07:47:50.683Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/99/781fe0c827be2742bcc775efefccb3b048a3a9c6ce9aec0cbf4a101677e5/pytz-2026.1.post1-py2.py3-none-any.whl", hash = "sha256:f2fd16142fda348286a75e1a524be810bb05d444e5a081f37f7affc635035f7a", upload-time = "2026-03-03T07:47:49.167Z" }, + { url = "https://files.pythonhosted.org/packages/10/99/781fe0c827be2742bcc775efefccb3b048a3a9c6ce9aec0cbf4a101677e5/pytz-2026.1.post1-py2.py3-none-any.whl", hash = "sha256:f2fd16142fda348286a75e1a524be810bb05d444e5a081f37f7affc635035f7a", size = 510489, upload-time = "2026-03-03T07:47:49.167Z" }, ] - [[package]] name = "pyyaml" version = "6.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", upload-time = "2025-09-25T21:33:16.546Z" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", upload-time = "2025-09-25T21:32:11.445Z" }, - { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", upload-time = "2025-09-25T21:32:12.492Z" }, - { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", upload-time = "2025-09-25T21:32:13.652Z" }, - { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", upload-time = "2025-09-25T21:32:15.21Z" }, - { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", upload-time = "2025-09-25T21:32:16.431Z" }, - { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", upload-time = "2025-09-25T21:32:17.56Z" }, - { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", upload-time = "2025-09-25T21:32:18.834Z" }, - { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", upload-time = "2025-09-25T21:32:20.209Z" }, - { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", upload-time = "2025-09-25T21:32:21.167Z" }, - { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, ] - [[package]] name = "requests" version = "2.33.1" @@ -1143,36 +1067,34 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517", upload-time = "2026-03-30T16:09:15.531Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517", size = 134120, upload-time = "2026-03-30T16:09:15.531Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a", upload-time = "2026-03-30T16:09:13.83Z" }, + { url = "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a", size = 64947, upload-time = "2026-03-30T16:09:13.83Z" }, ] - [[package]] name = "ruff" version = "0.9.10" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/8e/fafaa6f15c332e73425d9c44ada85360501045d5ab0b81400076aff27cf6/ruff-0.9.10.tar.gz", hash = "sha256:9bacb735d7bada9cfb0f2c227d3658fc443d90a727b47f206fb33f52f3c0eac7", upload-time = "2025-03-07T15:27:44.363Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/73/b2/af7c2cc9e438cbc19fafeec4f20bfcd72165460fe75b2b6e9a0958c8c62b/ruff-0.9.10-py3-none-linux_armv6l.whl", hash = "sha256:eb4d25532cfd9fe461acc83498361ec2e2252795b4f40b17e80692814329e42d", upload-time = "2025-03-07T15:26:51.268Z" }, - { url = "https://files.pythonhosted.org/packages/6d/12/03f6dfa1b95ddd47e6969f0225d60d9d7437c91938a310835feb27927ca0/ruff-0.9.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:188a6638dab1aa9bb6228a7302387b2c9954e455fb25d6b4470cb0641d16759d", upload-time = "2025-03-07T15:26:56.104Z" }, - { url = "https://files.pythonhosted.org/packages/02/49/1c79e0906b6ff551fb0894168763f705bf980864739572b2815ecd3c9df0/ruff-0.9.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5284dcac6b9dbc2fcb71fdfc26a217b2ca4ede6ccd57476f52a587451ebe450d", upload-time = "2025-03-07T15:27:01.385Z" }, - { url = "https://files.pythonhosted.org/packages/5b/01/85e8082e41585e0e1ceb11e41c054e9e36fed45f4b210991052d8a75089f/ruff-0.9.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47678f39fa2a3da62724851107f438c8229a3470f533894b5568a39b40029c0c", upload-time = "2025-03-07T15:27:04.023Z" }, - { url = "https://files.pythonhosted.org/packages/a1/90/0bc60bd4e5db051f12445046d0c85cc2c617095c0904f1aa81067dc64aea/ruff-0.9.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99713a6e2766b7a17147b309e8c915b32b07a25c9efd12ada79f217c9c778b3e", upload-time = "2025-03-07T15:27:06.93Z" }, - { url = "https://files.pythonhosted.org/packages/66/ea/0b7e8c42b1ec608033c4d5a02939c82097ddcb0b3e393e4238584b7054ab/ruff-0.9.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:524ee184d92f7c7304aa568e2db20f50c32d1d0caa235d8ddf10497566ea1a12", upload-time = "2025-03-07T15:27:10.082Z" }, - { url = "https://files.pythonhosted.org/packages/d5/86/3171d1eff893db4f91755175a6e1163c5887be1f1e2f4f6c0c59527c2bfd/ruff-0.9.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:df92aeac30af821f9acf819fc01b4afc3dfb829d2782884f8739fb52a8119a16", upload-time = "2025-03-07T15:27:12.727Z" }, - { url = "https://files.pythonhosted.org/packages/89/9e/700ca289f172a38eb0bca752056d0a42637fa17b81649b9331786cb791d7/ruff-0.9.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de42e4edc296f520bb84954eb992a07a0ec5a02fecb834498415908469854a52", upload-time = "2025-03-07T15:27:15.944Z" }, - { url = "https://files.pythonhosted.org/packages/f2/92/648020b3b5db180f41a931a68b1c8575cca3e63cec86fd26807422a0dbad/ruff-0.9.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d257f95b65806104b6b1ffca0ea53f4ef98454036df65b1eda3693534813ecd1", upload-time = "2025-03-07T15:27:18.996Z" }, - { url = "https://files.pythonhosted.org/packages/5e/a6/cc472161cd04d30a09d5c90698696b70c169eeba2c41030344194242db45/ruff-0.9.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60dec7201c0b10d6d11be00e8f2dbb6f40ef1828ee75ed739923799513db24c", upload-time = "2025-03-07T15:27:21.655Z" }, - { url = "https://files.pythonhosted.org/packages/6c/db/d31c361c4025b1b9102b4d032c70a69adb9ee6fde093f6c3bf29f831c85c/ruff-0.9.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d838b60007da7a39c046fcdd317293d10b845001f38bcb55ba766c3875b01e43", upload-time = "2025-03-07T15:27:24.72Z" }, - { url = "https://files.pythonhosted.org/packages/d1/86/d6374e24a14d4d93ebe120f45edd82ad7dcf3ef999ffc92b197d81cdc2a5/ruff-0.9.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ccaf903108b899beb8e09a63ffae5869057ab649c1e9231c05ae354ebc62066c", upload-time = "2025-03-07T15:27:27.282Z" }, - { url = "https://files.pythonhosted.org/packages/00/62/a61691f6eaaac1e945a1f3f59f1eea9a218513139d5b6c2b8f88b43b5b8f/ruff-0.9.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f9567d135265d46e59d62dc60c0bfad10e9a6822e231f5b24032dba5a55be6b5", upload-time = "2025-03-07T15:27:30.637Z" }, - { url = "https://files.pythonhosted.org/packages/ee/94/2c7065e1d92a8a8a46d46d9c3cf07b0aa7e0a1e0153d74baa5e6620b4102/ruff-0.9.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5f202f0d93738c28a89f8ed9eaba01b7be339e5d8d642c994347eaa81c6d75b8", upload-time = "2025-03-07T15:27:33.356Z" }, - { url = "https://files.pythonhosted.org/packages/a7/8f/1f545ea6f9fcd7bf4368551fb91d2064d8f0577b3079bb3f0ae5779fb773/ruff-0.9.10-py3-none-win32.whl", hash = "sha256:bfb834e87c916521ce46b1788fbb8484966e5113c02df216680102e9eb960029", upload-time = "2025-03-07T15:27:35.994Z" }, - { url = "https://files.pythonhosted.org/packages/4f/18/fb703603ab108e5c165f52f5b86ee2aa9be43bb781703ec87c66a5f5d604/ruff-0.9.10-py3-none-win_amd64.whl", hash = "sha256:f2160eeef3031bf4b17df74e307d4c5fb689a6f3a26a2de3f7ef4044e3c484f1", upload-time = "2025-03-07T15:27:38.66Z" }, - { url = "https://files.pythonhosted.org/packages/35/85/338e603dc68e7d9994d5d84f24adbf69bae760ba5efd3e20f5ff2cec18da/ruff-0.9.10-py3-none-win_arm64.whl", hash = "sha256:5fd804c0327a5e5ea26615550e706942f348b197d5475ff34c19733aee4b2e69", upload-time = "2025-03-07T15:27:41.687Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/20/8e/fafaa6f15c332e73425d9c44ada85360501045d5ab0b81400076aff27cf6/ruff-0.9.10.tar.gz", hash = "sha256:9bacb735d7bada9cfb0f2c227d3658fc443d90a727b47f206fb33f52f3c0eac7", size = 3759776, upload-time = "2025-03-07T15:27:44.363Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/b2/af7c2cc9e438cbc19fafeec4f20bfcd72165460fe75b2b6e9a0958c8c62b/ruff-0.9.10-py3-none-linux_armv6l.whl", hash = "sha256:eb4d25532cfd9fe461acc83498361ec2e2252795b4f40b17e80692814329e42d", size = 10049494, upload-time = "2025-03-07T15:26:51.268Z" }, + { url = "https://files.pythonhosted.org/packages/6d/12/03f6dfa1b95ddd47e6969f0225d60d9d7437c91938a310835feb27927ca0/ruff-0.9.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:188a6638dab1aa9bb6228a7302387b2c9954e455fb25d6b4470cb0641d16759d", size = 10853584, upload-time = "2025-03-07T15:26:56.104Z" }, + { url = "https://files.pythonhosted.org/packages/02/49/1c79e0906b6ff551fb0894168763f705bf980864739572b2815ecd3c9df0/ruff-0.9.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5284dcac6b9dbc2fcb71fdfc26a217b2ca4ede6ccd57476f52a587451ebe450d", size = 10155692, upload-time = "2025-03-07T15:27:01.385Z" }, + { url = "https://files.pythonhosted.org/packages/5b/01/85e8082e41585e0e1ceb11e41c054e9e36fed45f4b210991052d8a75089f/ruff-0.9.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47678f39fa2a3da62724851107f438c8229a3470f533894b5568a39b40029c0c", size = 10369760, upload-time = "2025-03-07T15:27:04.023Z" }, + { url = "https://files.pythonhosted.org/packages/a1/90/0bc60bd4e5db051f12445046d0c85cc2c617095c0904f1aa81067dc64aea/ruff-0.9.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99713a6e2766b7a17147b309e8c915b32b07a25c9efd12ada79f217c9c778b3e", size = 9912196, upload-time = "2025-03-07T15:27:06.93Z" }, + { url = "https://files.pythonhosted.org/packages/66/ea/0b7e8c42b1ec608033c4d5a02939c82097ddcb0b3e393e4238584b7054ab/ruff-0.9.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:524ee184d92f7c7304aa568e2db20f50c32d1d0caa235d8ddf10497566ea1a12", size = 11434985, upload-time = "2025-03-07T15:27:10.082Z" }, + { url = "https://files.pythonhosted.org/packages/d5/86/3171d1eff893db4f91755175a6e1163c5887be1f1e2f4f6c0c59527c2bfd/ruff-0.9.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:df92aeac30af821f9acf819fc01b4afc3dfb829d2782884f8739fb52a8119a16", size = 12155842, upload-time = "2025-03-07T15:27:12.727Z" }, + { url = "https://files.pythonhosted.org/packages/89/9e/700ca289f172a38eb0bca752056d0a42637fa17b81649b9331786cb791d7/ruff-0.9.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de42e4edc296f520bb84954eb992a07a0ec5a02fecb834498415908469854a52", size = 11613804, upload-time = "2025-03-07T15:27:15.944Z" }, + { url = "https://files.pythonhosted.org/packages/f2/92/648020b3b5db180f41a931a68b1c8575cca3e63cec86fd26807422a0dbad/ruff-0.9.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d257f95b65806104b6b1ffca0ea53f4ef98454036df65b1eda3693534813ecd1", size = 13823776, upload-time = "2025-03-07T15:27:18.996Z" }, + { url = "https://files.pythonhosted.org/packages/5e/a6/cc472161cd04d30a09d5c90698696b70c169eeba2c41030344194242db45/ruff-0.9.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60dec7201c0b10d6d11be00e8f2dbb6f40ef1828ee75ed739923799513db24c", size = 11302673, upload-time = "2025-03-07T15:27:21.655Z" }, + { url = "https://files.pythonhosted.org/packages/6c/db/d31c361c4025b1b9102b4d032c70a69adb9ee6fde093f6c3bf29f831c85c/ruff-0.9.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d838b60007da7a39c046fcdd317293d10b845001f38bcb55ba766c3875b01e43", size = 10235358, upload-time = "2025-03-07T15:27:24.72Z" }, + { url = "https://files.pythonhosted.org/packages/d1/86/d6374e24a14d4d93ebe120f45edd82ad7dcf3ef999ffc92b197d81cdc2a5/ruff-0.9.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ccaf903108b899beb8e09a63ffae5869057ab649c1e9231c05ae354ebc62066c", size = 9886177, upload-time = "2025-03-07T15:27:27.282Z" }, + { url = "https://files.pythonhosted.org/packages/00/62/a61691f6eaaac1e945a1f3f59f1eea9a218513139d5b6c2b8f88b43b5b8f/ruff-0.9.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f9567d135265d46e59d62dc60c0bfad10e9a6822e231f5b24032dba5a55be6b5", size = 10864747, upload-time = "2025-03-07T15:27:30.637Z" }, + { url = "https://files.pythonhosted.org/packages/ee/94/2c7065e1d92a8a8a46d46d9c3cf07b0aa7e0a1e0153d74baa5e6620b4102/ruff-0.9.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5f202f0d93738c28a89f8ed9eaba01b7be339e5d8d642c994347eaa81c6d75b8", size = 11360441, upload-time = "2025-03-07T15:27:33.356Z" }, + { url = "https://files.pythonhosted.org/packages/a7/8f/1f545ea6f9fcd7bf4368551fb91d2064d8f0577b3079bb3f0ae5779fb773/ruff-0.9.10-py3-none-win32.whl", hash = "sha256:bfb834e87c916521ce46b1788fbb8484966e5113c02df216680102e9eb960029", size = 10247401, upload-time = "2025-03-07T15:27:35.994Z" }, + { url = "https://files.pythonhosted.org/packages/4f/18/fb703603ab108e5c165f52f5b86ee2aa9be43bb781703ec87c66a5f5d604/ruff-0.9.10-py3-none-win_amd64.whl", hash = "sha256:f2160eeef3031bf4b17df74e307d4c5fb689a6f3a26a2de3f7ef4044e3c484f1", size = 11366360, upload-time = "2025-03-07T15:27:38.66Z" }, + { url = "https://files.pythonhosted.org/packages/35/85/338e603dc68e7d9994d5d84f24adbf69bae760ba5efd3e20f5ff2cec18da/ruff-0.9.10-py3-none-win_arm64.whl", hash = "sha256:5fd804c0327a5e5ea26615550e706942f348b197d5475ff34c19733aee4b2e69", size = 10436892, upload-time = "2025-03-07T15:27:41.687Z" }, ] - [[package]] name = "scipy" version = "1.15.1" @@ -1180,63 +1102,58 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/76/c6/8eb0654ba0c7d0bb1bf67bf8fbace101a8e4f250f7722371105e8b6f68fc/scipy-1.15.1.tar.gz", hash = "sha256:033a75ddad1463970c96a88063a1df87ccfddd526437136b6ee81ff0312ebdf6", upload-time = "2025-01-11T00:06:16.883Z" } +sdist = { url = "https://files.pythonhosted.org/packages/76/c6/8eb0654ba0c7d0bb1bf67bf8fbace101a8e4f250f7722371105e8b6f68fc/scipy-1.15.1.tar.gz", hash = "sha256:033a75ddad1463970c96a88063a1df87ccfddd526437136b6ee81ff0312ebdf6", size = 59407493, upload-time = "2025-01-11T00:06:16.883Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d8/6e/a9c42d0d39e09ed7fd203d0ac17adfea759cba61ab457671fe66e523dbec/scipy-1.15.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c09aa9d90f3500ea4c9b393ee96f96b0ccb27f2f350d09a47f533293c78ea776", upload-time = "2025-01-11T00:01:53.571Z" }, - { url = "https://files.pythonhosted.org/packages/04/ee/e3e535c81828618878a7433992fecc92fa4df79393f31a8fea1d05615091/scipy-1.15.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:0ac102ce99934b162914b1e4a6b94ca7da0f4058b6d6fd65b0cef330c0f3346f", upload-time = "2025-01-11T00:02:03.859Z" }, - { url = "https://files.pythonhosted.org/packages/c4/5e/b1b0124be8e76f87115f16b8915003eec4b7060298117715baf13f51942c/scipy-1.15.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:09c52320c42d7f5c7748b69e9f0389266fd4f82cf34c38485c14ee976cb8cb04", upload-time = "2025-01-11T00:02:12.434Z" }, - { url = "https://files.pythonhosted.org/packages/14/36/c00cb73eefda85946172c27913ab995c6ad4eee00fa4f007572e8c50cd51/scipy-1.15.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:cdde8414154054763b42b74fe8ce89d7f3d17a7ac5dd77204f0e142cdc9239e9", upload-time = "2025-01-11T00:02:20.237Z" }, - { url = "https://files.pythonhosted.org/packages/68/94/aff5c51b3799349a9d1e67a056772a0f8a47db371e83b498d43467806557/scipy-1.15.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c9d8fc81d6a3b6844235e6fd175ee1d4c060163905a2becce8e74cb0d7554ce", upload-time = "2025-01-11T00:02:30.21Z" }, - { url = "https://files.pythonhosted.org/packages/b0/3c/0de11ca154e24a57b579fb648151d901326d3102115bc4f9a7a86526ce54/scipy-1.15.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fb57b30f0017d4afa5fe5f5b150b8f807618819287c21cbe51130de7ccdaed2", upload-time = "2025-01-11T00:02:41.811Z" }, - { url = "https://files.pythonhosted.org/packages/15/09/472e8d0a6b33199d1bb95e49bedcabc0976c3724edd9b0ef7602ccacf41e/scipy-1.15.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:491d57fe89927fa1aafbe260f4cfa5ffa20ab9f1435025045a5315006a91b8f5", upload-time = "2025-01-11T00:02:53.118Z" }, - { url = "https://files.pythonhosted.org/packages/ff/ba/31c7a8131152822b3a2cdeba76398ffb404d81d640de98287d236da90c49/scipy-1.15.1-cp312-cp312-win_amd64.whl", hash = "sha256:900f3fa3db87257510f011c292a5779eb627043dd89731b9c461cd16ef76ab3d", upload-time = "2025-01-11T00:03:04.53Z" }, + { url = "https://files.pythonhosted.org/packages/d8/6e/a9c42d0d39e09ed7fd203d0ac17adfea759cba61ab457671fe66e523dbec/scipy-1.15.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c09aa9d90f3500ea4c9b393ee96f96b0ccb27f2f350d09a47f533293c78ea776", size = 41478318, upload-time = "2025-01-11T00:01:53.571Z" }, + { url = "https://files.pythonhosted.org/packages/04/ee/e3e535c81828618878a7433992fecc92fa4df79393f31a8fea1d05615091/scipy-1.15.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:0ac102ce99934b162914b1e4a6b94ca7da0f4058b6d6fd65b0cef330c0f3346f", size = 32596696, upload-time = "2025-01-11T00:02:03.859Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5e/b1b0124be8e76f87115f16b8915003eec4b7060298117715baf13f51942c/scipy-1.15.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:09c52320c42d7f5c7748b69e9f0389266fd4f82cf34c38485c14ee976cb8cb04", size = 24870366, upload-time = "2025-01-11T00:02:12.434Z" }, + { url = "https://files.pythonhosted.org/packages/14/36/c00cb73eefda85946172c27913ab995c6ad4eee00fa4f007572e8c50cd51/scipy-1.15.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:cdde8414154054763b42b74fe8ce89d7f3d17a7ac5dd77204f0e142cdc9239e9", size = 28007461, upload-time = "2025-01-11T00:02:20.237Z" }, + { url = "https://files.pythonhosted.org/packages/68/94/aff5c51b3799349a9d1e67a056772a0f8a47db371e83b498d43467806557/scipy-1.15.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c9d8fc81d6a3b6844235e6fd175ee1d4c060163905a2becce8e74cb0d7554ce", size = 38068174, upload-time = "2025-01-11T00:02:30.21Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3c/0de11ca154e24a57b579fb648151d901326d3102115bc4f9a7a86526ce54/scipy-1.15.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fb57b30f0017d4afa5fe5f5b150b8f807618819287c21cbe51130de7ccdaed2", size = 40249869, upload-time = "2025-01-11T00:02:41.811Z" }, + { url = "https://files.pythonhosted.org/packages/15/09/472e8d0a6b33199d1bb95e49bedcabc0976c3724edd9b0ef7602ccacf41e/scipy-1.15.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:491d57fe89927fa1aafbe260f4cfa5ffa20ab9f1435025045a5315006a91b8f5", size = 42629068, upload-time = "2025-01-11T00:02:53.118Z" }, + { url = "https://files.pythonhosted.org/packages/ff/ba/31c7a8131152822b3a2cdeba76398ffb404d81d640de98287d236da90c49/scipy-1.15.1-cp312-cp312-win_amd64.whl", hash = "sha256:900f3fa3db87257510f011c292a5779eb627043dd89731b9c461cd16ef76ab3d", size = 43621992, upload-time = "2025-01-11T00:03:04.53Z" }, ] - [[package]] name = "setuptools" version = "75.8.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d1/53/43d99d7687e8cdef5ab5f9ec5eaf2c0423c2b35133a2b7e7bc276fc32b21/setuptools-75.8.2.tar.gz", hash = "sha256:4880473a969e5f23f2a2be3646b2dfd84af9028716d398e46192f84bc36900d2", upload-time = "2025-02-26T20:45:19.103Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d1/53/43d99d7687e8cdef5ab5f9ec5eaf2c0423c2b35133a2b7e7bc276fc32b21/setuptools-75.8.2.tar.gz", hash = "sha256:4880473a969e5f23f2a2be3646b2dfd84af9028716d398e46192f84bc36900d2", size = 1344083, upload-time = "2025-02-26T20:45:19.103Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/38/7d7362e031bd6dc121e5081d8cb6aa6f6fedf2b67bf889962134c6da4705/setuptools-75.8.2-py3-none-any.whl", hash = "sha256:558e47c15f1811c1fa7adbd0096669bf76c1d3f433f58324df69f3f5ecac4e8f", upload-time = "2025-02-26T20:45:17.259Z" }, + { url = "https://files.pythonhosted.org/packages/a9/38/7d7362e031bd6dc121e5081d8cb6aa6f6fedf2b67bf889962134c6da4705/setuptools-75.8.2-py3-none-any.whl", hash = "sha256:558e47c15f1811c1fa7adbd0096669bf76c1d3f433f58324df69f3f5ecac4e8f", size = 1229385, upload-time = "2025-02-26T20:45:17.259Z" }, ] - [[package]] name = "six" version = "1.17.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", upload-time = "2024-12-04T17:35:28.174Z" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", upload-time = "2024-12-04T17:35:26.475Z" }, + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, ] - [[package]] name = "tomli" version = "2.4.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", upload-time = "2026-03-25T20:22:03.828Z" } +sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543, upload-time = "2026-03-25T20:22:03.828Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", upload-time = "2026-03-25T20:21:21.626Z" }, - { url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", upload-time = "2026-03-25T20:21:23.002Z" }, - { url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", upload-time = "2026-03-25T20:21:24.04Z" }, - { url = "https://files.pythonhosted.org/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", upload-time = "2026-03-25T20:21:25.177Z" }, - { url = "https://files.pythonhosted.org/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", upload-time = "2026-03-25T20:21:26.364Z" }, - { url = "https://files.pythonhosted.org/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", upload-time = "2026-03-25T20:21:27.46Z" }, - { url = "https://files.pythonhosted.org/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", upload-time = "2026-03-25T20:21:28.492Z" }, - { url = "https://files.pythonhosted.org/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", upload-time = "2026-03-25T20:21:29.386Z" }, - { url = "https://files.pythonhosted.org/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", upload-time = "2026-03-25T20:21:30.677Z" }, - { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", upload-time = "2026-03-25T20:22:03.012Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", size = 155924, upload-time = "2026-03-25T20:21:21.626Z" }, + { url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", size = 150018, upload-time = "2026-03-25T20:21:23.002Z" }, + { url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", size = 244948, upload-time = "2026-03-25T20:21:24.04Z" }, + { url = "https://files.pythonhosted.org/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", size = 253341, upload-time = "2026-03-25T20:21:25.177Z" }, + { url = "https://files.pythonhosted.org/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", size = 248159, upload-time = "2026-03-25T20:21:26.364Z" }, + { url = "https://files.pythonhosted.org/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", size = 253290, upload-time = "2026-03-25T20:21:27.46Z" }, + { url = "https://files.pythonhosted.org/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", size = 98141, upload-time = "2026-03-25T20:21:28.492Z" }, + { url = "https://files.pythonhosted.org/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", size = 108847, upload-time = "2026-03-25T20:21:29.386Z" }, + { url = "https://files.pythonhosted.org/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", size = 95088, upload-time = "2026-03-25T20:21:30.677Z" }, + { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" }, ] - [[package]] name = "tomli-w" version = "1.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/19/75/241269d1da26b624c0d5e110e8149093c759b7a286138f4efd61a60e75fe/tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021", upload-time = "2025-01-15T12:07:24.262Z" } +sdist = { url = "https://files.pythonhosted.org/packages/19/75/241269d1da26b624c0d5e110e8149093c759b7a286138f4efd61a60e75fe/tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021", size = 7184, upload-time = "2025-01-15T12:07:24.262Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", upload-time = "2025-01-15T12:07:22.074Z" }, + { url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", size = 6675, upload-time = "2025-01-15T12:07:22.074Z" }, ] - [[package]] name = "typeapi" version = "2.3.0" @@ -1244,20 +1161,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d5/92/5a23ad34aa877edf00906166e339bfdc571543ea183ea7ab727bb01516c7/typeapi-2.3.0.tar.gz", hash = "sha256:a60d11f72c5ec27338cfd1c807f035b0b16ed2e3b798fb1c1d34fc5589f544be", upload-time = "2025-10-23T13:44:11.26Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d5/92/5a23ad34aa877edf00906166e339bfdc571543ea183ea7ab727bb01516c7/typeapi-2.3.0.tar.gz", hash = "sha256:a60d11f72c5ec27338cfd1c807f035b0b16ed2e3b798fb1c1d34fc5589f544be", size = 122687, upload-time = "2025-10-23T13:44:11.26Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/84/021bbeb7edb990dd6875cb6ab08d32faaa49fec63453d863730260a01f9e/typeapi-2.3.0-py3-none-any.whl", hash = "sha256:576b7dcb94412e91c5cae107a393674f8f99c10a24beb8be2302e3fed21d5cc2", upload-time = "2025-10-23T13:44:09.833Z" }, + { url = "https://files.pythonhosted.org/packages/d4/84/021bbeb7edb990dd6875cb6ab08d32faaa49fec63453d863730260a01f9e/typeapi-2.3.0-py3-none-any.whl", hash = "sha256:576b7dcb94412e91c5cae107a393674f8f99c10a24beb8be2302e3fed21d5cc2", size = 26858, upload-time = "2025-10-23T13:44:09.833Z" }, ] - [[package]] name = "typing-extensions" version = "4.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", upload-time = "2025-08-25T13:49:26.313Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", upload-time = "2025-08-25T13:49:24.86Z" }, + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, ] - [[package]] name = "typing-inspection" version = "0.4.2" @@ -1265,29 +1180,26 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", upload-time = "2025-10-01T02:14:41.687Z" } +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", upload-time = "2025-10-01T02:14:40.154Z" }, + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, ] - [[package]] name = "tzdata" version = "2026.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/19/1b9b0e29f30c6d35cb345486df41110984ea67ae69dddbc0e8a100999493/tzdata-2026.2.tar.gz", hash = "sha256:9173fde7d80d9018e02a662e168e5a2d04f87c41ea174b139fbef642eda62d10", upload-time = "2026-04-24T15:22:08.651Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/19/1b9b0e29f30c6d35cb345486df41110984ea67ae69dddbc0e8a100999493/tzdata-2026.2.tar.gz", hash = "sha256:9173fde7d80d9018e02a662e168e5a2d04f87c41ea174b139fbef642eda62d10", size = 198254, upload-time = "2026-04-24T15:22:08.651Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl", hash = "sha256:bbe9af844f658da81a5f95019480da3a89415801f6cc966806612cc7169bffe7", upload-time = "2026-04-24T15:22:05.876Z" }, + { url = "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl", hash = "sha256:bbe9af844f658da81a5f95019480da3a89415801f6cc966806612cc7169bffe7", size = 349321, upload-time = "2026-04-24T15:22:05.876Z" }, ] - [[package]] name = "urllib3" version = "2.6.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", upload-time = "2026-01-07T16:24:43.925Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", upload-time = "2026-01-07T16:24:42.685Z" }, + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, ] - [[package]] name = "virtualenv" version = "21.3.0" @@ -1298,52 +1210,49 @@ dependencies = [ { name = "platformdirs" }, { name = "python-discovery" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3f/8b/6331f7a7fe70131c301106ec1e7cf23e2501bf7d4ca3636805801ca191bb/virtualenv-21.3.0.tar.gz", hash = "sha256:733750db978ec95c2d8eb4feadaa57091002bce404cb39ba69899cf7bd28944e", upload-time = "2026-04-27T17:05:58.927Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3f/8b/6331f7a7fe70131c301106ec1e7cf23e2501bf7d4ca3636805801ca191bb/virtualenv-21.3.0.tar.gz", hash = "sha256:733750db978ec95c2d8eb4feadaa57091002bce404cb39ba69899cf7bd28944e", size = 7614069, upload-time = "2026-04-27T17:05:58.927Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/eb/03bfb1299d4c4510329e470f13f9a4ce793df7fcb5a2fd3510f911066f61/virtualenv-21.3.0-py3-none-any.whl", hash = "sha256:4d28ee41f6d9ec8f1f00cd472b9ffbcedda1b3d3b9a575b5c94a2d004fd51bd7", upload-time = "2026-04-27T17:05:55.468Z" }, + { url = "https://files.pythonhosted.org/packages/4b/eb/03bfb1299d4c4510329e470f13f9a4ce793df7fcb5a2fd3510f911066f61/virtualenv-21.3.0-py3-none-any.whl", hash = "sha256:4d28ee41f6d9ec8f1f00cd472b9ffbcedda1b3d3b9a575b5c94a2d004fd51bd7", size = 7594690, upload-time = "2026-04-27T17:05:55.468Z" }, ] - [[package]] name = "watchdog" version = "6.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", upload-time = "2024-11-01T14:07:13.037Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", upload-time = "2024-11-01T14:06:37.745Z" }, - { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", upload-time = "2024-11-01T14:06:39.748Z" }, - { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", upload-time = "2024-11-01T14:06:41.009Z" }, - { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", upload-time = "2024-11-01T14:06:59.472Z" }, - { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", upload-time = "2024-11-01T14:07:01.431Z" }, - { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", upload-time = "2024-11-01T14:07:02.568Z" }, - { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", upload-time = "2024-11-01T14:07:03.893Z" }, - { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", upload-time = "2024-11-01T14:07:05.189Z" }, - { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", upload-time = "2024-11-01T14:07:06.376Z" }, - { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", upload-time = "2024-11-01T14:07:07.547Z" }, - { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", upload-time = "2024-11-01T14:07:09.525Z" }, - { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", upload-time = "2024-11-01T14:07:10.686Z" }, - { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", upload-time = "2024-11-01T14:07:11.845Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471, upload-time = "2024-11-01T14:06:37.745Z" }, + { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449, upload-time = "2024-11-01T14:06:39.748Z" }, + { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054, upload-time = "2024-11-01T14:06:41.009Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, ] - [[package]] name = "wrapt" version = "2.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2e/64/925f213fdcbb9baeb1530449ac71a4d57fc361c053d06bf78d0c5c7cd80c/wrapt-2.1.2.tar.gz", hash = "sha256:3996a67eecc2c68fd47b4e3c564405a5777367adfd9b8abb58387b63ee83b21e", upload-time = "2026-03-06T02:53:25.134Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4c/b6/1db817582c49c7fcbb7df6809d0f515af29d7c2fbf57eb44c36e98fb1492/wrapt-2.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ff2aad9c4cda28a8f0653fc2d487596458c2a3f475e56ba02909e950a9efa6a9", upload-time = "2026-03-06T02:52:45.663Z" }, - { url = "https://files.pythonhosted.org/packages/a2/16/9b02a6b99c09227c93cd4b73acc3678114154ec38da53043c0ddc1fba0dc/wrapt-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6433ea84e1cfacf32021d2a4ee909554ade7fd392caa6f7c13f1f4bf7b8e8748", upload-time = "2026-03-06T02:53:48.728Z" }, - { url = "https://files.pythonhosted.org/packages/af/aa/ead46a88f9ec3a432a4832dfedb84092fc35af2d0ba40cd04aea3889f247/wrapt-2.1.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c20b757c268d30d6215916a5fa8461048d023865d888e437fab451139cad6c8e", upload-time = "2026-03-06T02:54:40.328Z" }, - { url = "https://files.pythonhosted.org/packages/3a/9f/742c7c7cdf58b59085a1ee4b6c37b013f66ac33673a7ef4aaed5e992bc33/wrapt-2.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79847b83eb38e70d93dc392c7c5b587efe65b3e7afcc167aa8abd5d60e8761c8", upload-time = "2026-03-06T02:53:26.58Z" }, - { url = "https://files.pythonhosted.org/packages/e8/44/2c3dd45d53236b7ed7c646fcf212251dc19e48e599debd3926b52310fafb/wrapt-2.1.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f8fba1bae256186a83d1875b2b1f4e2d1242e8fac0f58ec0d7e41b26967b965c", upload-time = "2026-03-06T02:53:11.547Z" }, - { url = "https://files.pythonhosted.org/packages/74/e2/b17d66abc26bd96f89dec0ecd0ef03da4a1286e6ff793839ec431b9fae57/wrapt-2.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e3d3b35eedcf5f7d022291ecd7533321c4775f7b9cd0050a31a68499ba45757c", upload-time = "2026-03-06T02:54:09.5Z" }, - { url = "https://files.pythonhosted.org/packages/3c/62/e2977843fdf9f03daf1586a0ff49060b1b2fc7ff85a7ea82b6217c1ae36e/wrapt-2.1.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:6f2c5390460de57fa9582bc8a1b7a6c86e1a41dfad74c5225fc07044c15cc8d1", upload-time = "2026-03-06T02:54:03.884Z" }, - { url = "https://files.pythonhosted.org/packages/88/dd/27fc67914e68d740bce512f11734aec08696e6b17641fef8867c00c949fc/wrapt-2.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7dfa9f2cf65d027b951d05c662cc99ee3bd01f6e4691ed39848a7a5fffc902b2", upload-time = "2026-03-06T02:53:20.412Z" }, - { url = "https://files.pythonhosted.org/packages/ec/9f/b750b3692ed2ef4705cb305bd68858e73010492b80e43d2a4faa5573cbe7/wrapt-2.1.2-cp312-cp312-win32.whl", hash = "sha256:eba8155747eb2cae4a0b913d9ebd12a1db4d860fc4c829d7578c7b989bd3f2f0", upload-time = "2026-03-06T02:53:37.732Z" }, - { url = "https://files.pythonhosted.org/packages/8e/b2/feecfe29f28483d888d76a48f03c4c4d8afea944dbee2b0cd3380f9df032/wrapt-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:1c51c738d7d9faa0b3601708e7e2eda9bf779e1b601dce6c77411f2a1b324a63", upload-time = "2026-03-06T02:52:47.138Z" }, - { url = "https://files.pythonhosted.org/packages/44/e1/e328f605d6e208547ea9fd120804fcdec68536ac748987a68c47c606eea8/wrapt-2.1.2-cp312-cp312-win_arm64.whl", hash = "sha256:c8e46ae8e4032792eb2f677dbd0d557170a8e5524d22acc55199f43efedd39bf", upload-time = "2026-03-06T02:53:22.053Z" }, - { url = "https://files.pythonhosted.org/packages/1a/c7/8528ac2dfa2c1e6708f647df7ae144ead13f0a31146f43c7264b4942bf12/wrapt-2.1.2-py3-none-any.whl", hash = "sha256:b8fd6fa2b2c4e7621808f8c62e8317f4aae56e59721ad933bac5239d913cf0e8", upload-time = "2026-03-06T02:53:12.905Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/2e/64/925f213fdcbb9baeb1530449ac71a4d57fc361c053d06bf78d0c5c7cd80c/wrapt-2.1.2.tar.gz", hash = "sha256:3996a67eecc2c68fd47b4e3c564405a5777367adfd9b8abb58387b63ee83b21e", size = 81678, upload-time = "2026-03-06T02:53:25.134Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/b6/1db817582c49c7fcbb7df6809d0f515af29d7c2fbf57eb44c36e98fb1492/wrapt-2.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ff2aad9c4cda28a8f0653fc2d487596458c2a3f475e56ba02909e950a9efa6a9", size = 61255, upload-time = "2026-03-06T02:52:45.663Z" }, + { url = "https://files.pythonhosted.org/packages/a2/16/9b02a6b99c09227c93cd4b73acc3678114154ec38da53043c0ddc1fba0dc/wrapt-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6433ea84e1cfacf32021d2a4ee909554ade7fd392caa6f7c13f1f4bf7b8e8748", size = 61848, upload-time = "2026-03-06T02:53:48.728Z" }, + { url = "https://files.pythonhosted.org/packages/af/aa/ead46a88f9ec3a432a4832dfedb84092fc35af2d0ba40cd04aea3889f247/wrapt-2.1.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c20b757c268d30d6215916a5fa8461048d023865d888e437fab451139cad6c8e", size = 121433, upload-time = "2026-03-06T02:54:40.328Z" }, + { url = "https://files.pythonhosted.org/packages/3a/9f/742c7c7cdf58b59085a1ee4b6c37b013f66ac33673a7ef4aaed5e992bc33/wrapt-2.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79847b83eb38e70d93dc392c7c5b587efe65b3e7afcc167aa8abd5d60e8761c8", size = 123013, upload-time = "2026-03-06T02:53:26.58Z" }, + { url = "https://files.pythonhosted.org/packages/e8/44/2c3dd45d53236b7ed7c646fcf212251dc19e48e599debd3926b52310fafb/wrapt-2.1.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f8fba1bae256186a83d1875b2b1f4e2d1242e8fac0f58ec0d7e41b26967b965c", size = 117326, upload-time = "2026-03-06T02:53:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/74/e2/b17d66abc26bd96f89dec0ecd0ef03da4a1286e6ff793839ec431b9fae57/wrapt-2.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e3d3b35eedcf5f7d022291ecd7533321c4775f7b9cd0050a31a68499ba45757c", size = 121444, upload-time = "2026-03-06T02:54:09.5Z" }, + { url = "https://files.pythonhosted.org/packages/3c/62/e2977843fdf9f03daf1586a0ff49060b1b2fc7ff85a7ea82b6217c1ae36e/wrapt-2.1.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:6f2c5390460de57fa9582bc8a1b7a6c86e1a41dfad74c5225fc07044c15cc8d1", size = 116237, upload-time = "2026-03-06T02:54:03.884Z" }, + { url = "https://files.pythonhosted.org/packages/88/dd/27fc67914e68d740bce512f11734aec08696e6b17641fef8867c00c949fc/wrapt-2.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7dfa9f2cf65d027b951d05c662cc99ee3bd01f6e4691ed39848a7a5fffc902b2", size = 120563, upload-time = "2026-03-06T02:53:20.412Z" }, + { url = "https://files.pythonhosted.org/packages/ec/9f/b750b3692ed2ef4705cb305bd68858e73010492b80e43d2a4faa5573cbe7/wrapt-2.1.2-cp312-cp312-win32.whl", hash = "sha256:eba8155747eb2cae4a0b913d9ebd12a1db4d860fc4c829d7578c7b989bd3f2f0", size = 58198, upload-time = "2026-03-06T02:53:37.732Z" }, + { url = "https://files.pythonhosted.org/packages/8e/b2/feecfe29f28483d888d76a48f03c4c4d8afea944dbee2b0cd3380f9df032/wrapt-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:1c51c738d7d9faa0b3601708e7e2eda9bf779e1b601dce6c77411f2a1b324a63", size = 60441, upload-time = "2026-03-06T02:52:47.138Z" }, + { url = "https://files.pythonhosted.org/packages/44/e1/e328f605d6e208547ea9fd120804fcdec68536ac748987a68c47c606eea8/wrapt-2.1.2-cp312-cp312-win_arm64.whl", hash = "sha256:c8e46ae8e4032792eb2f677dbd0d557170a8e5524d22acc55199f43efedd39bf", size = 58836, upload-time = "2026-03-06T02:53:22.053Z" }, + { url = "https://files.pythonhosted.org/packages/1a/c7/8528ac2dfa2c1e6708f647df7ae144ead13f0a31146f43c7264b4942bf12/wrapt-2.1.2-py3-none-any.whl", hash = "sha256:b8fd6fa2b2c4e7621808f8c62e8317f4aae56e59721ad933bac5239d913cf0e8", size = 43993, upload-time = "2026-03-06T02:53:12.905Z" }, ] - [[package]] name = "yapf" version = "0.43.0" @@ -1351,16 +1260,15 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "platformdirs" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/23/97/b6f296d1e9cc1ec25c7604178b48532fa5901f721bcf1b8d8148b13e5588/yapf-0.43.0.tar.gz", hash = "sha256:00d3aa24bfedff9420b2e0d5d9f5ab6d9d4268e72afbf59bb3fa542781d5218e", upload-time = "2024-11-14T00:11:41.584Z" } +sdist = { url = "https://files.pythonhosted.org/packages/23/97/b6f296d1e9cc1ec25c7604178b48532fa5901f721bcf1b8d8148b13e5588/yapf-0.43.0.tar.gz", hash = "sha256:00d3aa24bfedff9420b2e0d5d9f5ab6d9d4268e72afbf59bb3fa542781d5218e", size = 254907, upload-time = "2024-11-14T00:11:41.584Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/37/81/6acd6601f61e31cfb8729d3da6d5df966f80f374b78eff83760714487338/yapf-0.43.0-py3-none-any.whl", hash = "sha256:224faffbc39c428cb095818cf6ef5511fdab6f7430a10783fdfb292ccf2852ca", upload-time = "2024-11-14T00:11:39.37Z" }, + { url = "https://files.pythonhosted.org/packages/37/81/6acd6601f61e31cfb8729d3da6d5df966f80f374b78eff83760714487338/yapf-0.43.0-py3-none-any.whl", hash = "sha256:224faffbc39c428cb095818cf6ef5511fdab6f7430a10783fdfb292ccf2852ca", size = 256158, upload-time = "2024-11-14T00:11:39.37Z" }, ] - [[package]] name = "zipp" version = "3.23.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/21/093488dfc7cc8964ded15ab726fad40f25fd3d788fd741cc1c5a17d78ee8/zipp-3.23.1.tar.gz", hash = "sha256:32120e378d32cd9714ad503c1d024619063ec28aad2248dc6672ad13edfa5110", upload-time = "2026-04-13T23:21:46.6Z" } +sdist = { url = "https://files.pythonhosted.org/packages/30/21/093488dfc7cc8964ded15ab726fad40f25fd3d788fd741cc1c5a17d78ee8/zipp-3.23.1.tar.gz", hash = "sha256:32120e378d32cd9714ad503c1d024619063ec28aad2248dc6672ad13edfa5110", size = 25965, upload-time = "2026-04-13T23:21:46.6Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/08/8a/0861bec20485572fbddf3dfba2910e38fe249796cb73ecdeb74e07eeb8d3/zipp-3.23.1-py3-none-any.whl", hash = "sha256:0b3596c50a5c700c9cb40ba8d86d9f2cc4807e9bedb06bcdf7fac85633e444dc", upload-time = "2026-04-13T23:21:45.386Z" }, + { url = "https://files.pythonhosted.org/packages/08/8a/0861bec20485572fbddf3dfba2910e38fe249796cb73ecdeb74e07eeb8d3/zipp-3.23.1-py3-none-any.whl", hash = "sha256:0b3596c50a5c700c9cb40ba8d86d9f2cc4807e9bedb06bcdf7fac85633e444dc", size = 10378, upload-time = "2026-04-13T23:21:45.386Z" }, ] From 5577a5f4e26f5cfdcfa39c64434a609fb86de261 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Br=C3=A4uer?= Date: Tue, 4 Aug 2026 14:48:51 +0200 Subject: [PATCH 8/8] added data_sources tests to acceptance test matrix --- .github/codecov.yml | 3 +++ .github/workflows/acceptance.yml | 2 ++ Makefile | 6 +++--- .../mdf/test_mdf_coverage_gaps.py | 12 +++++++++--- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/.github/codecov.yml b/.github/codecov.yml index 639322ad..c6b8e2f3 100644 --- a/.github/codecov.yml +++ b/.github/codecov.yml @@ -29,6 +29,9 @@ flags: reporting: paths: - src/impulse_reporting/ + data_sources: + paths: + - src/impulse_data_sources/ comment: # this is a top-level key layout: "diff, flags, files" diff --git a/.github/workflows/acceptance.yml b/.github/workflows/acceptance.yml index 96819e29..d1f2dd6e 100644 --- a/.github/workflows/acceptance.yml +++ b/.github/workflows/acceptance.yml @@ -71,6 +71,8 @@ jobs: path: tests/impulse_query_engine - component: reporting path: tests/impulse_reporting + - component: data_sources + path: tests/impulse_data_sources steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 diff --git a/Makefile b/Makefile index 443d1294..eae76c43 100644 --- a/Makefile +++ b/Makefile @@ -39,9 +39,9 @@ coverage: open htmlcov/index.html mdf-coverage: - $(UV_RUN) coverage run -m pytest tests/impulse_ds/mdf -q --no-cov - $(UV_RUN) coverage report --include='src/impulse_ds/mdf/*' \ - --omit='src/impulse_ds/mdf/converter.py' \ + $(UV_RUN) coverage run -m pytest tests/impulse_data_sources/mdf -q --no-cov + $(UV_RUN) coverage report --include='src/impulse_data_sources/mdf/*' \ + --omit='src/impulse_data_sources/mdf/converter.py' \ --fail-under=95 --precision=1 build: diff --git a/tests/impulse_data_sources/mdf/test_mdf_coverage_gaps.py b/tests/impulse_data_sources/mdf/test_mdf_coverage_gaps.py index f150c97f..f84f50e7 100644 --- a/tests/impulse_data_sources/mdf/test_mdf_coverage_gaps.py +++ b/tests/impulse_data_sources/mdf/test_mdf_coverage_gaps.py @@ -1270,7 +1270,9 @@ def test_stripe_decompress_failure_skipped(self, monkeypatch): def _bad_decompress(*a, **k): raise ValueError("bad") - monkeypatch.setattr("impulse_data_sources.mdf.arrow_emit._decompress_subblock_blob", _bad_decompress) + monkeypatch.setattr( + "impulse_data_sources.mdf.arrow_emit._decompress_subblock_blob", _bad_decompress + ) assert list(convert_stripe_spec_to_arrow_batches(specs[0])) == [] def test_convert_spec_extent_error_and_empty_slice(self, monkeypatch): @@ -1399,7 +1401,9 @@ def test_stripe_unsorted_decompress_failure(self, monkeypatch): def _bad(*a, **k): raise ValueError("bad") - monkeypatch.setattr("impulse_data_sources.mdf.arrow_emit._decompress_subblock_blob", _bad) + monkeypatch.setattr( + "impulse_data_sources.mdf.arrow_emit._decompress_subblock_blob", _bad + ) assert list(convert_stripe_spec_to_arrow_batches(spec)) == [] finally: Path(path).unlink(missing_ok=True) @@ -1890,7 +1894,9 @@ def test_dt_stream_none_values(self, monkeypatch): org["channel_id_map"], target_partition_mb=16, )[0] - monkeypatch.setattr("impulse_data_sources.mdf.arrow_emit.extract_signal", lambda *_a, **_k: None) + monkeypatch.setattr( + "impulse_data_sources.mdf.arrow_emit.extract_signal", lambda *_a, **_k: None + ) assert list(convert_spec_to_arrow_batches(spec)) == [] def test_stripe_short_subblock_and_none_values(self, monkeypatch):