├── tests ├── __init__.py ├── ceil_test.py ├── julian_date_test.py ├── test_date_range.py ├── test_is_busday.py ├── test_format_localized.py ├── test_timezone.py └── test_month_delta.py ├── polars_xdt ├── py.typed ├── .mypy.ini ├── _internal.pyi ├── typing.py ├── namespace.py ├── __init__.py ├── utils.py ├── ranges.py └── functions.py ├── rust-toolchain.toml ├── assets ├── .DS_Store └── polars-business.png ├── docs ├── api │ └── polars_xdt.date_range.rst ├── requirements-docs.txt ├── API.rst ├── installation.rst ├── index.rst ├── Makefile └── conf.py ├── requirements.txt ├── .gitignore ├── dprint.json ├── src ├── lib.rs ├── arg_previous_greater.rs ├── format_localized.rs ├── to_julian.rs ├── expressions.rs ├── month_delta.rs └── timezone.rs ├── Cargo.toml ├── .readthedocs.yaml ├── Makefile ├── LICENSE ├── bump_version.py ├── licenses ├── NUMPY_LICENSE.txt └── PANDAS_LICENSE.txt ├── pyproject.toml ├── README.md ├── CODE_OF_CONDUCT.md ├── .github └── workflows │ └── CI.yml └── Cargo.lock /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /polars_xdt/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /polars_xdt/.mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | strict=True 3 | -------------------------------------------------------------------------------- /polars_xdt/_internal.pyi: -------------------------------------------------------------------------------- 1 | __version__: str 2 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2025-10-24" 3 | 4 | -------------------------------------------------------------------------------- /assets/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pola-rs/polars-xdt/HEAD/assets/.DS_Store -------------------------------------------------------------------------------- /assets/polars-business.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pola-rs/polars-xdt/HEAD/assets/polars-business.png -------------------------------------------------------------------------------- /docs/api/polars_xdt.date_range.rst: -------------------------------------------------------------------------------- 1 | polars\_xdt.date\_range 2 | ======================= 3 | 4 | .. currentmodule:: polars_xdt 5 | 6 | .. autofunction:: date_range -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | maturin 2 | python-dateutil 3 | polars 4 | hypothesis 5 | numpy 6 | pandas 7 | pytest 8 | holidays 9 | mypy 10 | black 11 | ruff 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /pyo3-polars/target 2 | .idea/ 3 | venv/ 4 | target/ 5 | *.pyc 6 | .hypothesis/ 7 | *.html 8 | *.bat 9 | *.js 10 | docs/_build 11 | docs/api/* 12 | *.so 13 | -------------------------------------------------------------------------------- /docs/requirements-docs.txt: -------------------------------------------------------------------------------- 1 | sphinx 2 | numpydoc 3 | sphinx_autosummary_accessors 4 | sphinx_copybutton 5 | sphinx-design 6 | sphinx-favicon 7 | pydata_sphinx_theme 8 | polars-xdt 9 | -------------------------------------------------------------------------------- /dprint.json: -------------------------------------------------------------------------------- 1 | { 2 | "json": { 3 | }, 4 | "markdown": { 5 | }, 6 | "toml": { 7 | }, 8 | "includes": ["**/*.{json,md,toml}"], 9 | "excludes": [ 10 | "**/*-lock.json" 11 | ], 12 | "plugins": [ 13 | "https://plugins.dprint.dev/json-0.17.4.wasm", 14 | "https://plugins.dprint.dev/markdown-0.16.1.wasm", 15 | "https://plugins.dprint.dev/toml-0.5.4.wasm" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /docs/API.rst: -------------------------------------------------------------------------------- 1 | API 2 | === 3 | 4 | .. autosummary:: 5 | :toctree: api/ 6 | 7 | polars_xdt.date_range 8 | polars_xdt.ceil 9 | polars_xdt.day_name 10 | polars_xdt.format_localized 11 | polars_xdt.from_local_datetime 12 | polars_xdt.is_workday 13 | polars_xdt.month_name 14 | polars_xdt.month_delta 15 | polars_xdt.to_local_datetime 16 | polars_xdt.to_julian_date 17 | -------------------------------------------------------------------------------- /docs/installation.rst: -------------------------------------------------------------------------------- 1 | Installation 2 | ============ 3 | 4 | First, you need to `install Polars `_. 5 | 6 | Then, you'll need to install `polars-xdt`: 7 | 8 | .. code-block:: 9 | 10 | pip install polars-xdt 11 | 12 | Then, if you can run 13 | 14 | .. code-block:: 15 | 16 | import polars as pl 17 | import polars_xdt 18 | 19 | without errors it means installation all worked correctly! 20 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | polars-xdt 2 | =============== 3 | 4 | **polars-xdt** is a Python library which is a plugin for 5 | Polars, a blazingly fast dataframe library. 6 | 7 | .. image:: https://github.com/MarcoGorelli/polars-xdt/assets/33491632/928c68c4-4e71-45a7-bc89-14922c7ce61b 8 | :width: 400 9 | :alt: Polar bear in an office with a nice warm cup of coffee 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | :caption: Contents: 14 | 15 | installation 16 | API 17 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | mod arg_previous_greater; 2 | mod expressions; 3 | mod format_localized; 4 | mod month_delta; 5 | mod timezone; 6 | mod to_julian; 7 | 8 | use pyo3::prelude::*; 9 | use pyo3_polars::PolarsAllocator; 10 | 11 | #[pymodule] 12 | fn _internal(_py: Python, m: &Bound) -> PyResult<()> { 13 | m.add("__version__", env!("CARGO_PKG_VERSION"))?; 14 | Ok(()) 15 | } 16 | 17 | #[global_allocator] 18 | static ALLOC: PolarsAllocator = PolarsAllocator::new(); 19 | -------------------------------------------------------------------------------- /polars_xdt/typing.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Union 2 | 3 | if TYPE_CHECKING: 4 | import sys 5 | 6 | import polars as pl 7 | 8 | if sys.version_info >= (3, 10): 9 | from typing import TypeAlias 10 | else: 11 | from typing_extensions import TypeAlias 12 | from polars.datatypes import DataType, DataTypeClass 13 | 14 | IntoExprColumn: TypeAlias = Union[pl.Expr, str, pl.Series] 15 | PolarsDataType: TypeAlias = Union[DataType, DataTypeClass] 16 | -------------------------------------------------------------------------------- /tests/ceil_test.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | import polars as pl 4 | 5 | import polars_xdt as xdt 6 | 7 | 8 | def test_ceil() -> None: 9 | df = pl.DataFrame( 10 | { 11 | "date_col": [ 12 | datetime(2024, 8, 24, 1, 2, 3, 123456), 13 | datetime(2024, 10, 1), 14 | ], 15 | }, 16 | schema={"date_col": pl.Datetime("ms")}, 17 | ) 18 | result = df.select(result=xdt.ceil("date_col", "1mo"))["result"] 19 | assert result[0] == datetime(2024, 9, 1, 0, 0, 0, 0) 20 | assert result[1] == datetime(2024, 10, 1, 0, 0, 0, 0) 21 | -------------------------------------------------------------------------------- /polars_xdt/namespace.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import Any, Callable 4 | 5 | import polars as pl 6 | 7 | from polars_xdt import functions 8 | 9 | 10 | @pl.api.register_expr_namespace("xdt") 11 | class ExprXDTNamespace: 12 | """eXtra stuff for DateTimes.""" 13 | 14 | def __init__(self, expr: pl.Expr) -> None: 15 | self._expr = expr 16 | 17 | def __getattr__(self, function_name: str) -> Callable[[Any], pl.Expr]: 18 | def func(*args: Any, **kwargs: Any) -> pl.Expr: 19 | return getattr(functions, function_name)( 20 | self._expr, *args, **kwargs 21 | ) 22 | 23 | return func 24 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /polars_xdt/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import polars_xdt.namespace # noqa: F401 4 | from polars_xdt.functions import ( 5 | arg_previous_greater, 6 | ceil, 7 | day_name, 8 | format_localized, 9 | from_local_datetime, 10 | is_workday, 11 | month_delta, 12 | month_name, 13 | to_julian_date, 14 | to_local_datetime, 15 | ) 16 | from polars_xdt.ranges import date_range 17 | 18 | from ._internal import __version__ 19 | 20 | __all__ = [ 21 | "__version__", 22 | "arg_previous_greater", 23 | "ceil", 24 | "date_range", 25 | "day_name", 26 | "format_localized", 27 | "from_local_datetime", 28 | "is_workday", 29 | "month_delta", 30 | "month_name", 31 | "to_julian_date", 32 | "to_local_datetime", 33 | ] 34 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "polars_xdt" 3 | version = "0.17.1" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | [lib] 8 | name = "polars_xdt" 9 | crate-type = ["cdylib"] 10 | 11 | [dependencies] 12 | pyo3 = { version = "0.26", features = ["extension-module", "abi3-py39"] } 13 | pyo3-polars = { version = "0.25.0", features = ["derive", "dtype-struct", "dtype-array"] } 14 | serde = { version = "1", features = ["derive"] } 15 | chrono = { version = "0.4.42", default-features = false, features = ["std", "unstable-locales"] } 16 | chrono-tz = "0.10.4" 17 | polars = { version = "0.52.0", features = ["strings", "timezones"]} 18 | polars-ops = { version = "0.52.0", default-features = false } 19 | polars-arrow = { version = "0.52.0", default-features = false } 20 | 21 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the OS, Python version and other tools you might need 9 | build: 10 | os: ubuntu-22.04 11 | tools: 12 | python: "3.11" 13 | # You can also specify other tool versions: 14 | # nodejs: "19" 15 | # rust: "1.64" 16 | # golang: "1.19" 17 | 18 | # Build documentation in the "docs/" directory with Sphinx 19 | sphinx: 20 | configuration: polars_xdt/docs/conf.py 21 | 22 | # Optionally build your docs in additional formats such as PDF and ePub 23 | # formats: 24 | # - pdf 25 | # - epub 26 | 27 | # Optional but recommended, declare the Python requirements required 28 | # to build your documentation 29 | # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html 30 | python: 31 | install: 32 | - requirements: polars_xdt/docs/requirements-docs.txt 33 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | SHELL=/bin/bash 3 | 4 | venv: ## Set up virtual environment 5 | python3 -m venv .venv 6 | .venv/bin/pip install -r requirements.txt -r docs/requirements-docs.txt 7 | 8 | install: venv 9 | unset CONDA_PREFIX && \ 10 | source .venv/bin/activate && maturin develop 11 | 12 | install-release: venv 13 | unset CONDA_PREFIX && \ 14 | source .venv/bin/activate && maturin develop --release 15 | 16 | pre-commit: venv 17 | rustup component add rustfmt clippy --toolchain nightly-2025-10-24 18 | cargo fmt --all && cargo clippy --all-features 19 | .venv/bin/python -m ruff check polars_xdt tests --fix --exit-non-zero-on-fix 20 | .venv/bin/python -m ruff format polars_xdt tests 21 | .venv/bin/python -m mypy polars_xdt tests 22 | 23 | test: venv 24 | .venv/bin/python -m pytest tests 25 | .venv/bin/python -m pytest polars_xdt --doctest-modules 26 | 27 | run: install 28 | source .venv/bin/activate && python run.py 29 | 30 | run-release: install-release 31 | source .venv/bin/activate && python run.py 32 | -------------------------------------------------------------------------------- /tests/julian_date_test.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import datetime as dt 4 | 5 | import hypothesis.strategies as st 6 | import pandas as pd 7 | import polars as pl 8 | from hypothesis import given 9 | 10 | import polars_xdt as xdt 11 | 12 | 13 | @given( 14 | date=st.datetimes( 15 | min_value=dt.datetime(1, 1, 1), max_value=dt.datetime(9999, 12, 31) 16 | ), 17 | ) 18 | def test_against_pandas( 19 | date: dt.date, 20 | ) -> None: 21 | df = pl.DataFrame({"a": [date]}, schema={"a": pl.Datetime("ms")}) 22 | result = df.select(xdt.to_julian_date("a"))["a"].item() 23 | expected = pd.Timestamp(df["a"].item()).to_julian_date() 24 | assert result == expected 25 | 26 | 27 | @given( 28 | date=st.dates(min_value=dt.date(1, 1, 1), max_value=dt.date(9999, 12, 31)), 29 | ) 30 | def test_against_pandas_date( 31 | date: dt.date, 32 | ) -> None: 33 | df = pl.DataFrame({"a": [date]}) 34 | result = df.select(xdt.to_julian_date("a"))["a"].item() 35 | expected = pd.Timestamp(df["a"].item()).to_julian_date() 36 | assert result == expected 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Marco Edward Gorelli 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/arg_previous_greater.rs: -------------------------------------------------------------------------------- 1 | use polars::prelude::*; 2 | 3 | pub(crate) fn impl_arg_previous_greater(ca: &ChunkedArray) -> IdxCa 4 | where 5 | T: PolarsNumericType, 6 | { 7 | let mut idx: Vec = Vec::with_capacity(ca.len()); 8 | let out: IdxCa = ca 9 | .iter() 10 | .enumerate() 11 | .map(|(i, opt_val)| { 12 | if opt_val.is_none() { 13 | idx.push(-1); 14 | return None; 15 | } 16 | let i_curr = i; 17 | let mut i = (i as i32) - 1; // look at previous element 18 | while i >= 0 && ca.get(i as usize).is_none() { 19 | // find previous non-null value 20 | i -= 1; 21 | } 22 | if i < 0 { 23 | idx.push(-1); 24 | return None; 25 | } 26 | while (i != -1) && opt_val >= ca.get(i as usize) { 27 | i = idx[i as usize]; 28 | } 29 | if i == -1 { 30 | idx.push(-1); 31 | return Some(i_curr as IdxSize); 32 | } 33 | idx.push(i); 34 | if i == -1 { 35 | None 36 | } else { 37 | Some(i as IdxSize) 38 | } 39 | }) 40 | .collect(); 41 | out 42 | } 43 | -------------------------------------------------------------------------------- /polars_xdt/utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | import polars as pl 6 | 7 | if TYPE_CHECKING: 8 | from polars_xdt.typing import IntoExprColumn, PolarsDataType 9 | 10 | 11 | def parse_into_expr( 12 | expr: IntoExprColumn, 13 | *, 14 | str_as_lit: bool = False, 15 | list_as_lit: bool = True, 16 | dtype: PolarsDataType | None = None, 17 | ) -> pl.Expr: 18 | """ 19 | Parse a single input into an expression. 20 | 21 | Parameters 22 | ---------- 23 | expr 24 | The input to be parsed as an expression. 25 | str_as_lit 26 | Interpret string input as a string literal. If set to `False` (default), 27 | strings are parsed as column names. 28 | list_as_lit 29 | Interpret list input as a lit literal, If set to `False`, 30 | lists are parsed as `Series` literals. 31 | dtype 32 | If the input is expected to resolve to a literal with a known dtype, pass 33 | this to the `lit` constructor. 34 | 35 | Returns 36 | ------- 37 | polars.Expr 38 | 39 | """ 40 | if isinstance(expr, pl.Expr): 41 | pass 42 | elif isinstance(expr, str) and not str_as_lit: 43 | expr = pl.col(expr) 44 | elif isinstance(expr, list) and not list_as_lit: 45 | expr = pl.lit(pl.Series(expr), dtype=dtype) 46 | else: 47 | expr = pl.lit(expr, dtype=dtype) 48 | 49 | return expr 50 | -------------------------------------------------------------------------------- /bump_version.py: -------------------------------------------------------------------------------- 1 | # ruff: noqa 2 | # type: ignore 3 | import sys 4 | import re 5 | import subprocess 6 | import os 7 | 8 | # Docs are in a a separate repo cause I couldn't figure out 9 | # how to deploy from readthedocs 10 | subprocess.run(["make", "install"]) 11 | subprocess.run(["make", "clean"], cwd="docs") 12 | subprocess.run(["make", "html"], cwd="docs") 13 | os.system("cp docs/_build/html/* ../docs-polars-xdt/ -r") 14 | subprocess.run(["git", "add", "."], cwd="../docs-polars-xdt") 15 | subprocess.run( 16 | ["git", "commit", "-m", '"new version"', "--allow-empty"], 17 | cwd="../docs-polars-xdt", 18 | ) 19 | subprocess.run(["git", "push", "origin", "HEAD"], cwd="../docs-polars-xdt") 20 | 21 | how = sys.argv[1] 22 | 23 | with open("Cargo.toml", "r", encoding="utf-8") as f: 24 | content = f.read() 25 | old_version = re.search(r'^version = "(.*)"', content, re.MULTILINE).group(1) 26 | version = old_version.split(".") 27 | if how == "patch": 28 | version = ".".join(version[:-1] + [str(int(version[-1]) + 1)]) 29 | elif how == "minor": 30 | version = ".".join(version[:-2] + [str(int(version[-2]) + 1), "0"]) 31 | elif how == "major": 32 | version = ".".join([str(int(version[0]) + 1), "0", "0"]) 33 | else: 34 | sys.exit(1) 35 | content = content.replace( 36 | f'version = "{old_version}"', f'version = "{version}"' 37 | ) 38 | with open("Cargo.toml", "w", encoding="utf-8") as f: 39 | f.write(content) 40 | 41 | subprocess.run(["git", "commit", "-a", "-m", f"Bump version to {version}"]) 42 | subprocess.run(["git", "tag", "-a", version, "-m", version]) 43 | subprocess.run(["git", "push", "origin", "HEAD", "--follow-tags"]) 44 | -------------------------------------------------------------------------------- /licenses/NUMPY_LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2005-2023, NumPy Developers. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following 13 | disclaimer in the documentation and/or other materials provided 14 | with the distribution. 15 | 16 | * Neither the name of the NumPy Developers nor the names of any 17 | contributors may be used to endorse or promote products derived 18 | from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /licenses/PANDAS_LICENSE.txt: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2008-2011, AQR Capital Management, LLC, Lambda Foundry, Inc. and PyData Development Team 4 | All rights reserved. 5 | 6 | Copyright (c) 2011-2023, Open source contributors. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | * Redistributions of source code must retain the above copyright notice, this 12 | list of conditions and the following disclaimer. 13 | 14 | * Redistributions in binary form must reproduce the above copyright notice, 15 | this list of conditions and the following disclaimer in the documentation 16 | and/or other materials provided with the distribution. 17 | 18 | * Neither the name of the copyright holder nor the names of its 19 | contributors may be used to endorse or promote products derived from 20 | this software without specific prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 26 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # ruff: noqa 2 | # Configuration file for the Sphinx documentation builder. 3 | # 4 | # For the full list of built-in configuration values, see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Project information ----------------------------------------------------- 8 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information 9 | import sphinx_autosummary_accessors # noqa: F401 10 | 11 | project = "polars-xdt" 12 | copyright = "2023, Marco Gorelli" 13 | author = "Marco Gorelli" 14 | 15 | 16 | # -- General configuration --------------------------------------------------- 17 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration 18 | 19 | extensions = [ 20 | "sphinx.ext.autodoc", 21 | "sphinx.ext.autosummary", 22 | "sphinx.ext.githubpages", 23 | "sphinx.ext.intersphinx", 24 | "numpydoc", 25 | "sphinx_copybutton", 26 | "sphinx_design", 27 | "sphinx_favicon", 28 | ] 29 | 30 | templates_path = ["_templates"] 31 | exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] 32 | numpydoc_show_class_members = False 33 | 34 | 35 | # -- Options for HTML output ------------------------------------------------- 36 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output 37 | 38 | html_theme = "alabaster" 39 | # html_static_path = ["_static"] 40 | 41 | intersphinx_mapping = { 42 | "polars": ("https://pola-rs.github.io/polars/py-polars/html/", None), 43 | } 44 | 45 | copybutton_prompt_text = r">>> |\.\.\. " 46 | copybutton_prompt_is_regexp = True 47 | 48 | html_theme = "pydata_sphinx_theme" 49 | 50 | html_theme_options = { 51 | "navigation_with_keys": False, 52 | } 53 | 54 | numpydoc_show_class_members = False 55 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0", "polars>=1.5.0"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "polars-xdt" 7 | description = "eXtra stuff for Dates and Times in Polars" 8 | readme = "README.md" 9 | authors = [ 10 | { name="Marco Gorelli", email="33491632+MarcoGorelli@users.noreply.github.com" }, 11 | ] 12 | license = { file = "LICENSE" } 13 | classifiers = [ 14 | "Programming Language :: Rust", 15 | "Programming Language :: Python :: Implementation :: CPython", 16 | "Programming Language :: Python :: Implementation :: PyPy", 17 | ] 18 | requires-python = ">=3.9" 19 | dynamic = ["version"] 20 | 21 | [project.urls] 22 | "Repository" = "https://github.com/MarcoGorelli/polars-xdt" 23 | "Documentation" = "https://marcogorelli.github.io/polars-xdt-docs/" 24 | "Change Log" = "https://github.com/MarcoGorelli/polars-xdt/releases" 25 | "Issue Tracker" = "https://github.com/MarcoGorelli/polars-xdt/issues" 26 | 27 | 28 | [tool.maturin] 29 | module-name = "polars_xdt._internal" 30 | 31 | [tool.ruff.format] 32 | docstring-code-format = true 33 | 34 | [tool.ruff] 35 | lint.select = [ 36 | "ALL", 37 | ] 38 | lint.ignore = [ 39 | 'A003', 40 | 'ANN401', 41 | 'ARG002', # todo: enable 42 | 'ARG003', # todo: enable 43 | 'C901', 44 | 'COM812', 45 | 'D100', 46 | 'D103', 47 | 'D104', 48 | 'D105', 49 | 'D107', 50 | 'D203', 51 | 'D212', 52 | 'DTZ', 53 | 'E501', 54 | 'FBT003', # todo: enable 55 | 'FIX', 56 | 'ISC001', 57 | 'PD', 58 | 'PLR0911', 59 | 'PLR0912', 60 | 'PLR5501', 61 | 'PLR2004', 62 | 'PT011', 63 | 'PTH', 64 | 'RET505', 65 | 'S', 66 | 'SLF001', 67 | 'TD', 68 | 'TRY004' 69 | ] 70 | 71 | # Allow autofix for all enabled rules (when `--fix`) is provided. 72 | lint.fixable = ["ALL"] 73 | 74 | # Exclude a variety of commonly ignored directories. 75 | exclude = [ 76 | "tests", 77 | ".git", 78 | ".git-rewrite", 79 | ".mypy_cache", 80 | ".ruff_cache", 81 | "venv", 82 | ".ipynb", 83 | "venv", 84 | ] 85 | line-length = 80 86 | 87 | [[tool.mypy.overrides]] 88 | module = [ 89 | "pandas", 90 | "dateutil.*", 91 | ] 92 | ignore_missing_imports = true 93 | -------------------------------------------------------------------------------- /tests/test_date_range.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from datetime import date 4 | 5 | import polars as pl 6 | import pytest 7 | from polars.testing import assert_series_equal 8 | 9 | import polars_xdt as xdt 10 | 11 | 12 | def test_eager() -> None: 13 | result = xdt.date_range(date(2023, 1, 1), date(2023, 1, 10), eager=True) 14 | expected = pl.Series( 15 | "literal", 16 | [ 17 | date(2023, 1, 2), 18 | date(2023, 1, 3), 19 | date(2023, 1, 4), 20 | date(2023, 1, 5), 21 | date(2023, 1, 6), 22 | date(2023, 1, 9), 23 | date(2023, 1, 10), 24 | ], 25 | ) 26 | assert_series_equal(result, expected) 27 | 28 | 29 | def test_expr() -> None: 30 | expected = pl.Series( 31 | "literal", 32 | [ 33 | date(2023, 1, 2), 34 | date(2023, 1, 3), 35 | date(2023, 1, 4), 36 | date(2023, 1, 5), 37 | date(2023, 1, 6), 38 | date(2023, 1, 9), 39 | date(2023, 1, 10), 40 | ], 41 | ) 42 | result = pl.select( 43 | xdt.date_range(date(2023, 1, 1), date(2023, 1, 10), eager=True) 44 | )["literal"] 45 | assert_series_equal(result, expected) 46 | 47 | 48 | def test_invalid() -> None: 49 | with pytest.raises(ValueError): 50 | xdt.date_range(date(2023, 1, 1), date(2023, 1, 10), "1bd1h") 51 | 52 | 53 | def test_eager_custom_weekend() -> None: 54 | result = xdt.date_range( 55 | date(2023, 1, 1), date(2023, 1, 10), eager=True, weekend=["Fri", "Sat"] 56 | ) 57 | expected = pl.Series( 58 | "literal", 59 | [ 60 | date(2023, 1, 1), 61 | date(2023, 1, 2), 62 | date(2023, 1, 3), 63 | date(2023, 1, 4), 64 | date(2023, 1, 5), 65 | date(2023, 1, 8), 66 | date(2023, 1, 9), 67 | date(2023, 1, 10), 68 | ], 69 | ) 70 | assert_series_equal(result, expected) 71 | 72 | 73 | def test_eager_custom_holiday() -> None: 74 | result = xdt.date_range( 75 | date(2023, 1, 1), 76 | date(2023, 1, 10), 77 | eager=True, 78 | weekend=["Fri", "Sat"], 79 | holidays=[date(2023, 1, 2)], 80 | ) 81 | expected = pl.Series( 82 | "literal", 83 | [ 84 | date(2023, 1, 1), 85 | date(2023, 1, 3), 86 | date(2023, 1, 4), 87 | date(2023, 1, 5), 88 | date(2023, 1, 8), 89 | date(2023, 1, 9), 90 | date(2023, 1, 10), 91 | ], 92 | ) 93 | assert_series_equal(result, expected) 94 | -------------------------------------------------------------------------------- /tests/test_is_busday.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import datetime as dt 4 | 5 | import hypothesis.strategies as st 6 | import numpy as np 7 | import polars as pl 8 | from hypothesis import given 9 | 10 | import polars_xdt as xdt 11 | 12 | mapping = {"Mon": 1, "Tue": 2, "Wed": 3, "Thu": 4, "Fri": 5, "Sat": 6, "Sun": 7} 13 | reverse_mapping = {value: key for key, value in mapping.items()} 14 | 15 | 16 | def get_result( 17 | date: dt.date, 18 | weekend: list[str], 19 | holidays: list[dt.date], 20 | ) -> int: 21 | return ( # type: ignore[no-any-return] 22 | pl.DataFrame({"date": [date]}) 23 | .select(xdt.is_workday("date", weekend=weekend, holidays=holidays))[ 24 | "date" 25 | ] 26 | .item() 27 | ) 28 | 29 | 30 | @given( 31 | date=st.dates( 32 | min_value=dt.date(2000, 1, 1), max_value=dt.date(2000, 12, 31) 33 | ), 34 | weekend=st.lists( 35 | st.sampled_from(["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]), 36 | min_size=0, 37 | max_size=6, 38 | unique=True, 39 | ), 40 | holidays=st.lists( 41 | st.dates( 42 | min_value=dt.date(2000, 1, 1), max_value=dt.date(2000, 12, 31) 43 | ), 44 | min_size=1, 45 | max_size=300, 46 | ), 47 | ) 48 | def test_against_np_is_busday( 49 | date: dt.date, 50 | weekend: list[str], 51 | holidays: list[dt.date], 52 | ) -> None: 53 | result = get_result(date, weekend=weekend, holidays=holidays) 54 | weekmask = [0 if reverse_mapping[i] in weekend else 1 for i in range(1, 8)] 55 | expected = np.is_busday(date, weekmask=weekmask, holidays=holidays) 56 | assert result == expected 57 | 58 | 59 | @given( 60 | datetime=st.datetimes( 61 | min_value=dt.datetime(2000, 1, 1), max_value=dt.datetime(2000, 12, 31) 62 | ), 63 | weekend=st.lists( 64 | st.sampled_from(["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]), 65 | min_size=0, 66 | max_size=6, 67 | unique=True, 68 | ), 69 | holidays=st.lists( 70 | st.dates( 71 | min_value=dt.date(2000, 1, 1), max_value=dt.date(2000, 12, 31) 72 | ), 73 | min_size=1, 74 | max_size=300, 75 | ), 76 | ) 77 | def test_against_np_is_busday_datetime( 78 | datetime: dt.datetime, 79 | weekend: list[str], 80 | holidays: list[dt.date], 81 | ) -> None: 82 | result = get_result(datetime, weekend=weekend, holidays=holidays) 83 | weekmask = [0 if reverse_mapping[i] in weekend else 1 for i in range(1, 8)] 84 | date = dt.date(datetime.year, datetime.month, datetime.day) 85 | expected = np.is_busday(date, weekmask=weekmask, holidays=holidays) 86 | assert result == expected 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # polars-xdt 2 | 3 | ## eXtra stuff for DateTimes 4 | 5 |

6 | polars-xdt 10 |

11 | 12 | [![PyPI version](https://badge.fury.io/py/polars-xdt.svg)](https://badge.fury.io/py/polars-xdt) 13 | [![Read the docs!](https://img.shields.io/badge/Read%20the%20docs!-coolgreen?style=flat&link=https://marcogorelli.github.io/polars-xdt-docs/)](https://marcogorelli.github.io/polars-xdt-docs/) 14 | 15 | eXtra stuff for DateTimes in [Polars](https://www.pola.rs/). 16 | 17 | - ✅ blazingly fast, written in Rust 18 | - ✅ convert to and from multiple time zones 19 | - ✅ format datetime in different locales 20 | - ✅ convert to Julian Dates 21 | - ✅ ~time-based EWMA~ (upstreamed to Polars itself) 22 | - ✅ ~custom business-day arithmetic~ (upstreamed to Polars itself) 23 | 24 | Installation 25 | ------------ 26 | 27 | First, you need to [install Polars](https://pola-rs.github.io/polars/user-guide/installation/). 28 | 29 | Then, you'll need to install `polars-xdt`: 30 | ```console 31 | pip install polars-xdt 32 | ``` 33 | 34 | Read the [documentation](https://marcogorelli.github.io/polars-xdt-docs/) for a more examples and functionality. 35 | 36 | Basic Example 37 | ------------- 38 | Say we start with 39 | ```python 40 | from datetime import datetime 41 | 42 | import polars as pl 43 | import polars_xdt as xdt 44 | 45 | df = pl.DataFrame( 46 | { 47 | "local_dt": [ 48 | datetime(2020, 10, 10, 1), 49 | datetime(2020, 10, 10, 2), 50 | datetime(2020, 10, 9, 20), 51 | ], 52 | "timezone": [ 53 | "Europe/London", 54 | "Africa/Kigali", 55 | "America/New_York", 56 | ], 57 | } 58 | ) 59 | ``` 60 | 61 | Let's localize each datetime to the given timezone and convert to 62 | UTC, all in one step: 63 | 64 | ```python 65 | result = df.with_columns( 66 | xdt.from_local_datetime( 67 | "local_dt", pl.col("timezone"), "UTC" 68 | ).alias("date") 69 | ) 70 | print(result) 71 | ``` 72 | ``` 73 | shape: (3, 3) 74 | ┌─────────────────────┬──────────────────┬─────────────────────────┐ 75 | │ local_dt ┆ timezone ┆ date │ 76 | │ --- ┆ --- ┆ --- │ 77 | │ datetime[μs] ┆ str ┆ datetime[μs, UTC] │ 78 | ╞═════════════════════╪══════════════════╪═════════════════════════╡ 79 | │ 2020-10-10 01:00:00 ┆ Europe/London ┆ 2020-10-10 00:00:00 UTC │ 80 | │ 2020-10-10 02:00:00 ┆ Africa/Kigali ┆ 2020-10-10 00:00:00 UTC │ 81 | │ 2020-10-09 20:00:00 ┆ America/New_York ┆ 2020-10-10 00:00:00 UTC │ 82 | └─────────────────────┴──────────────────┴─────────────────────────┘ 83 | ``` 84 | 85 | Read the [documentation](https://marcogorelli.github.io/polars-xdt-docs/) for more examples! 86 | 87 | Logo 88 | ---- 89 | 90 | Thanks to [Olha Urdeichuk](https://www.fiverr.com/olhaurdeichuk) for the illustration. 91 | -------------------------------------------------------------------------------- /tests/test_format_localized.py: -------------------------------------------------------------------------------- 1 | from datetime import date, datetime 2 | from typing import Any 3 | 4 | import polars as pl 5 | import pytest 6 | 7 | import polars_xdt as xdt 8 | 9 | 10 | @pytest.mark.parametrize( 11 | ("time_unit", "expected_us", "expected_ukr"), 12 | [ 13 | ( 14 | "ms", 15 | "Wednesday, 01 January 2020 00:00:00.123", 16 | "середа, 01 січня 2020 00:00:00,123", 17 | ), 18 | ( 19 | "us", 20 | "Wednesday, 01 January 2020 00:00:00.123456", 21 | "середа, 01 січня 2020 00:00:00,123456", 22 | ), 23 | ( 24 | "ns", 25 | "Wednesday, 01 January 2020 00:00:00.123456789", 26 | "середа, 01 січня 2020 00:00:00,123456789", 27 | ), 28 | ], 29 | ) 30 | def test_format_localized_datetime( 31 | time_unit: Any, expected_us: str, expected_ukr: str 32 | ) -> None: 33 | df = pl.DataFrame( 34 | { 35 | "date_col": ["2020-01-01T00:00:00.123456789"], 36 | }, 37 | ).select(pl.col("date_col").str.to_datetime(time_unit=time_unit)) 38 | result = df.select( 39 | result=xdt.format_localized( 40 | "date_col", "%A, %d %B %Y %H:%M:%S%.f", "en_US" 41 | ) 42 | )["result"] 43 | assert result[0] == expected_us 44 | result = df.select( 45 | result=xdt.format_localized( 46 | "date_col", "%A, %d %B %Y %H:%M:%S%.f", "uk_UA" 47 | ) 48 | )["result"] 49 | assert result[0] == expected_ukr 50 | 51 | 52 | def test_format_localized_date() -> None: 53 | df = pl.DataFrame( 54 | { 55 | "date_col": [date(2024, 8, 24), date(2024, 10, 1)], 56 | }, 57 | ) 58 | result = df.select( 59 | result=xdt.format_localized("date_col", "%A, %d %B %Y", "en_US") 60 | )["result"] 61 | assert result[0] == "Saturday, 24 August 2024" 62 | assert result[1] == "Tuesday, 01 October 2024" 63 | result = df.select( 64 | result=xdt.format_localized("date_col", "%A, %d %B %Y", "uk_UA") 65 | )["result"] 66 | assert result[0] == "субота, 24 серпня 2024" 67 | assert result[1] == "вівторок, 01 жовтня 2024" 68 | 69 | 70 | def test_tz_aware() -> None: 71 | df = pl.DataFrame( 72 | { 73 | "date_col": [datetime(2024, 8, 24), datetime(2024, 10, 1)], 74 | }, 75 | schema={"date_col": pl.Datetime("ns", "Europe/London")}, 76 | ) 77 | result = df.select( 78 | result=xdt.format_localized("date_col", "%A, %d %B %Y %z", "uk_UA") 79 | ) 80 | assert result["result"][0] == "субота, 24 серпня 2024 +0100" 81 | assert result["result"][1] == "вівторок, 01 жовтня 2024 +0100" 82 | 83 | 84 | @pytest.mark.parametrize("time_unit", ["ms", "us", "ns"]) 85 | def test_pre_epoch(time_unit: Any) -> None: 86 | df = pl.DataFrame( 87 | { 88 | "date_col": [datetime(1960, 1, 1, 0, 0, 0, 1)], 89 | }, 90 | schema={"date_col": pl.Datetime(time_unit, "Europe/London")}, 91 | ) 92 | result = df.select( 93 | result=xdt.format_localized("date_col", "%A, %d %B %Y %z", "en_US") 94 | ) 95 | assert result["result"][0] == "Friday, 01 January 1960 +0000" 96 | -------------------------------------------------------------------------------- /src/format_localized.rs: -------------------------------------------------------------------------------- 1 | use chrono::format::StrftimeItems; 2 | use chrono::TimeZone; 3 | use chrono::{self, format::DelayedFormat}; 4 | use polars::prelude::*; 5 | use polars_arrow::array::MutablePlString; 6 | use polars_arrow::temporal_conversions::MILLISECONDS_IN_DAY; 7 | use polars_arrow::temporal_conversions::{ 8 | timestamp_ms_to_datetime, timestamp_ns_to_datetime, timestamp_us_to_datetime, 9 | }; 10 | use std::fmt::Write; 11 | use std::str::FromStr; 12 | 13 | fn format_ndt( 14 | ndt: chrono::NaiveDateTime, 15 | format: &str, 16 | locale: chrono::prelude::Locale, 17 | tz: chrono_tz::Tz, 18 | ) -> DelayedFormat> { 19 | let dt = tz.from_utc_datetime(&ndt); 20 | dt.format_localized(format, locale) 21 | } 22 | 23 | pub(crate) fn impl_format_localized( 24 | s: &Series, 25 | format: &str, 26 | locale: &str, 27 | ) -> PolarsResult { 28 | let locale = chrono::Locale::try_from(locale).map_err( 29 | |_| polars_err!(ComputeError: format!("given locale {} could not be parsed", locale)), 30 | )?; 31 | 32 | let ca: StringChunked = match s.dtype() { 33 | DataType::Date => { 34 | let ca = s.date()?; 35 | ca.phys.apply_kernel_cast(&|arr| { 36 | let mut buf = String::new(); 37 | let mut mutarr = MutablePlString::with_capacity(arr.len()); 38 | 39 | for opt in arr.into_iter() { 40 | match opt { 41 | None => mutarr.push_null(), 42 | Some(timestamp) => { 43 | buf.clear(); 44 | let ndt = 45 | timestamp_ms_to_datetime((*timestamp as i64) * MILLISECONDS_IN_DAY); 46 | let fmted = format_ndt(ndt, format, locale, chrono_tz::UTC); 47 | write!(buf, "{fmted}").unwrap(); 48 | mutarr.push(Some(&buf)) 49 | } 50 | } 51 | } 52 | 53 | mutarr.freeze().boxed() 54 | }) 55 | } 56 | DataType::Datetime(time_unit, time_zone) => { 57 | let ca = s.datetime()?; 58 | let timestamp_to_datetime = match time_unit { 59 | TimeUnit::Nanoseconds => timestamp_ns_to_datetime, 60 | TimeUnit::Microseconds => timestamp_us_to_datetime, 61 | TimeUnit::Milliseconds => timestamp_ms_to_datetime, 62 | }; 63 | let tz = match time_zone { 64 | None => chrono_tz::UTC, 65 | Some(tz) => chrono_tz::Tz::from_str(tz).unwrap(), 66 | }; 67 | ca.phys.apply_kernel_cast(&|arr| { 68 | let mut buf = String::new(); 69 | let mut mutarr = MutablePlString::with_capacity(arr.len()); 70 | 71 | for opt in arr.into_iter() { 72 | match opt { 73 | None => mutarr.push_null(), 74 | Some(timestamp) => { 75 | buf.clear(); 76 | let ndt = timestamp_to_datetime(*timestamp); 77 | let fmted = format_ndt(ndt, format, locale, tz); 78 | write!(buf, "{fmted}").unwrap(); 79 | mutarr.push(Some(&buf)) 80 | } 81 | } 82 | } 83 | 84 | mutarr.freeze().boxed() 85 | }) 86 | } 87 | _ => unreachable!(), 88 | }; 89 | Ok(ca.into_series()) 90 | } 91 | -------------------------------------------------------------------------------- /src/to_julian.rs: -------------------------------------------------------------------------------- 1 | use chrono::{Datelike, Timelike}; 2 | use polars::prelude::*; 3 | use polars_arrow::legacy::utils::CustomIterTools; 4 | use polars_arrow::temporal_conversions::{ 5 | timestamp_ms_to_datetime, timestamp_ns_to_datetime, timestamp_us_to_datetime, 6 | }; 7 | use polars_arrow::{array::Float64Array, temporal_conversions::MILLISECONDS_IN_DAY}; 8 | 9 | fn to_julian_date( 10 | mut year: i32, 11 | mut month: u32, 12 | day: u32, 13 | hour: u32, 14 | minute: u32, 15 | second: u32, 16 | nanosecond: u32, 17 | ) -> f64 { 18 | if month < 3 { 19 | year -= 1; 20 | month += 12; 21 | } 22 | day as f64 + (((153 * month - 457) / 5) as i64) as f64 + (365 * year) as f64 + (year / 4) as f64 23 | - (year / 100) as f64 24 | + (year / 400) as f64 25 | + 1_721_118.5 26 | + (hour as f64 27 | + minute as f64 / 60. 28 | + second as f64 / 3600. 29 | + nanosecond as f64 / 3600. / (10_i32.pow(9) as f64)) 30 | / 24. 31 | } 32 | 33 | pub(crate) fn impl_to_julian_date(s: &Series) -> PolarsResult { 34 | match s.dtype() { 35 | DataType::Date => { 36 | let ca = s.date()?; 37 | let chunks = ca.phys.downcast_iter().map(|arr| -> Float64Array { 38 | arr.into_iter() 39 | .map(|timestamp_opt| { 40 | timestamp_opt.map(|timestamp| { 41 | let ndt = 42 | timestamp_ms_to_datetime((*timestamp as i64) * MILLISECONDS_IN_DAY); 43 | to_julian_date(ndt.year(), ndt.month(), ndt.day(), 0, 0, 0, 0) 44 | }) 45 | }) 46 | .collect_trusted() 47 | }); 48 | Ok(Float64Chunked::from_chunk_iter(PlSmallStr::EMPTY, chunks).into_series()) 49 | } 50 | DataType::Datetime(time_unit, time_zone) => { 51 | if !(time_zone.is_none() || time_zone.as_deref() == Some(&PlSmallStr::from("UTC"))) { 52 | polars_bail!(InvalidOperation: "polars_xdt to_julian currently only works on UTC or naive Datetime type. \ 53 | For now, please cast to UTC Datetime first.") 54 | }; 55 | let timestamp_to_datetime = match time_unit { 56 | TimeUnit::Nanoseconds => timestamp_ns_to_datetime, 57 | TimeUnit::Microseconds => timestamp_us_to_datetime, 58 | TimeUnit::Milliseconds => timestamp_ms_to_datetime, 59 | }; 60 | let ca = &polars_ops::prelude::replace_time_zone( 61 | s.datetime()?, 62 | None, 63 | &StringChunked::from_iter(std::iter::once("raise")), 64 | NonExistent::Raise, 65 | )?; 66 | let chunks = ca.phys.downcast_iter().map(|arr| -> Float64Array { 67 | arr.into_iter() 68 | .map(|timestamp_opt| { 69 | timestamp_opt.map(|timestamp| { 70 | let ndt = timestamp_to_datetime(*timestamp); 71 | to_julian_date( 72 | ndt.year(), 73 | ndt.month(), 74 | ndt.day(), 75 | ndt.hour(), 76 | ndt.minute(), 77 | ndt.second(), 78 | ndt.nanosecond(), 79 | ) 80 | }) 81 | }) 82 | .collect_trusted() 83 | }); 84 | Ok(Float64Chunked::from_chunk_iter(PlSmallStr::EMPTY, chunks).into_series()) 85 | } 86 | _ => { 87 | polars_bail!(InvalidOperation: "polars_xdt to_julian currently only works on Date type. \ 88 | For now, please cast to Date first.") 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/expressions.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::unit_arg, clippy::unused_unit)] 2 | use crate::arg_previous_greater::*; 3 | use crate::format_localized::*; 4 | use crate::month_delta::*; 5 | use crate::timezone::*; 6 | use crate::to_julian::*; 7 | use polars::prelude::*; 8 | use pyo3_polars::derive::polars_expr; 9 | use pyo3_polars::export::polars_core::datatypes::TimeZone as PolarsTimeZone; 10 | use serde::Deserialize; 11 | 12 | #[derive(Deserialize)] 13 | pub struct FromLocalDatetimeKwargs { 14 | to_tz: String, 15 | ambiguous: String, 16 | } 17 | #[derive(Deserialize)] 18 | pub struct FormatLocalizedKwargs { 19 | format: String, 20 | locale: String, 21 | } 22 | 23 | pub fn to_local_datetime_output(input_fields: &[Field]) -> PolarsResult { 24 | let field = input_fields[0].clone(); 25 | let dtype = match field.dtype { 26 | DataType::Datetime(unit, _) => DataType::Datetime(unit, None), 27 | _ => polars_bail!(InvalidOperation: 28 | "dtype '{}' not supported", field.dtype 29 | ), 30 | }; 31 | Ok(Field::new(field.name, dtype)) 32 | } 33 | 34 | pub fn from_local_datetime_output( 35 | input_fields: &[Field], 36 | kwargs: FromLocalDatetimeKwargs, 37 | ) -> PolarsResult { 38 | let field = input_fields[0].clone(); 39 | let dtype = match field.dtype { 40 | DataType::Datetime(unit, _) => { 41 | DataType::Datetime(unit, PolarsTimeZone::opt_try_new(Some(&kwargs.to_tz))?) 42 | } 43 | _ => polars_bail!(InvalidOperation: 44 | "dtype '{}' not supported", field.dtype 45 | ), 46 | }; 47 | Ok(Field::new(field.name, dtype)) 48 | } 49 | 50 | #[polars_expr(output_type=Int32)] 51 | fn month_delta(inputs: &[Series]) -> PolarsResult { 52 | let start_dates = &inputs[0]; 53 | let end_dates = &inputs[1]; 54 | impl_month_delta(start_dates, end_dates) 55 | } 56 | 57 | #[polars_expr(output_type_func=to_local_datetime_output)] 58 | fn to_local_datetime(inputs: &[Series]) -> PolarsResult { 59 | let s1 = &inputs[0]; 60 | let ca = s1.datetime()?; 61 | let s2 = &inputs[1].str()?; 62 | Ok(elementwise_to_local_datetime(ca, s2)?.into_series()) 63 | } 64 | 65 | #[polars_expr(output_type_func_with_kwargs=from_local_datetime_output)] 66 | fn from_local_datetime(inputs: &[Series], kwargs: FromLocalDatetimeKwargs) -> PolarsResult { 67 | let s1 = &inputs[0]; 68 | let ca = s1.datetime().unwrap(); 69 | let s2 = &inputs[1].str().unwrap(); 70 | Ok(elementwise_from_local_datetime(ca, s2, &kwargs.to_tz, &kwargs.ambiguous)?.into_series()) 71 | } 72 | 73 | #[polars_expr(output_type=String)] 74 | fn format_localized(inputs: &[Series], kwargs: FormatLocalizedKwargs) -> PolarsResult { 75 | let s = &inputs[0]; 76 | let locale = kwargs.locale; 77 | let format = kwargs.format; 78 | impl_format_localized(s, &format, &locale) 79 | } 80 | 81 | #[polars_expr(output_type=Float64)] 82 | fn to_julian_date(inputs: &[Series]) -> PolarsResult { 83 | let s = &inputs[0]; 84 | impl_to_julian_date(s) 85 | } 86 | 87 | fn idx_dtype(input_fields: &[Field]) -> PolarsResult { 88 | let field = Field::new( 89 | input_fields[0].name.clone(), 90 | IDX_DTYPE 91 | ); 92 | Ok(field.clone()) 93 | } 94 | 95 | #[polars_expr(output_type_func=idx_dtype)] 96 | fn arg_previous_greater(inputs: &[Series]) -> PolarsResult { 97 | let ser = &inputs[0]; 98 | match ser.dtype() { 99 | DataType::Int64 => Ok(impl_arg_previous_greater(ser.i64().unwrap()).into_series()), 100 | DataType::Int32 => Ok(impl_arg_previous_greater(ser.i32().unwrap()).into_series()), 101 | DataType::UInt64 => Ok(impl_arg_previous_greater(ser.u64().unwrap()).into_series()), 102 | DataType::UInt32 => Ok(impl_arg_previous_greater(ser.u32().unwrap()).into_series()), 103 | DataType::Float64 => Ok(impl_arg_previous_greater(ser.f64().unwrap()).into_series()), 104 | DataType::Float32 => Ok(impl_arg_previous_greater(ser.f32().unwrap()).into_series()), 105 | dt => polars_bail!(ComputeError:"Expected numeric data type, got: {}", dt), 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /tests/test_timezone.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from datetime import datetime, timezone 4 | 5 | import polars as pl 6 | import pytest 7 | from polars.testing import ( 8 | assert_frame_equal, 9 | ) 10 | 11 | import polars_xdt as xdt 12 | 13 | 14 | @pytest.mark.parametrize( 15 | ("date", "timezone", "local_date"), 16 | [ 17 | ( 18 | datetime(2020, 10, 10, tzinfo=timezone.utc), 19 | "Europe/London", 20 | datetime(2020, 10, 10, 1, 0), 21 | ), 22 | ( 23 | datetime(2020, 10, 15, tzinfo=timezone.utc), 24 | "Africa/Kigali", 25 | datetime(2020, 10, 15, 2, 0), 26 | ), 27 | ( 28 | datetime(2020, 10, 15, tzinfo=timezone.utc), 29 | "America/New_York", 30 | datetime(2020, 10, 14, 20, 0), 31 | ), 32 | ], 33 | ) 34 | def test_convert_tz_to_local_datetime( 35 | date: datetime, timezone: str, local_date: datetime 36 | ) -> None: 37 | df = pl.DataFrame({"date": [date], "timezone": [timezone]}).with_columns( 38 | pl.col("date").dt.convert_time_zone("Europe/London") 39 | ) 40 | 41 | expected = df.with_columns(pl.lit(local_date).alias("local_dt")) 42 | 43 | result = df.lazy().with_columns( 44 | xdt.to_local_datetime("date", pl.col("timezone")).alias("local_dt") 45 | ) 46 | assert result.collect_schema() == expected.schema 47 | assert_frame_equal(result.collect(), expected) 48 | 49 | 50 | @pytest.mark.parametrize( 51 | ("local_date", "timezone", "date"), 52 | [ 53 | ( 54 | datetime(2020, 10, 10, 1, 0), 55 | "Europe/London", 56 | datetime(2020, 10, 10, tzinfo=timezone.utc), 57 | ), 58 | ( 59 | datetime(2020, 10, 15, 2, 0), 60 | "Africa/Kigali", 61 | datetime(2020, 10, 15, tzinfo=timezone.utc), 62 | ), 63 | ( 64 | datetime(2020, 10, 14, 20, 0), 65 | "America/New_York", 66 | datetime(2020, 10, 15, tzinfo=timezone.utc), 67 | ), 68 | ], 69 | ) 70 | def test_convert_tz_from_local_datetime( 71 | local_date: datetime, timezone: str, date: datetime 72 | ) -> None: 73 | df = pl.DataFrame({"local_date": [local_date], "timezone": [timezone]}) 74 | 75 | expected = df.with_columns( 76 | pl.lit(date).alias("date").dt.convert_time_zone("Europe/London") 77 | ) 78 | 79 | result = df.lazy().with_columns( 80 | xdt.from_local_datetime( 81 | "local_date", pl.col("timezone"), "Europe/London" 82 | ).alias("date") 83 | ) 84 | assert result.collect_schema() == expected.schema 85 | assert_frame_equal(result.collect(), expected) 86 | 87 | 88 | def test_convert_tz_from_local_datetime_literal() -> None: 89 | df = pl.DataFrame({"local_date": [datetime(2020, 10, 14, 20, 0)]}) 90 | 91 | expected = df.with_columns( 92 | pl.lit(datetime(2020, 10, 15, tzinfo=timezone.utc)) 93 | .alias("date") 94 | .dt.convert_time_zone("Europe/London") 95 | ) 96 | 97 | result = df.with_columns( 98 | xdt.from_local_datetime( 99 | "local_date", "America/New_York", "Europe/London" 100 | ).alias("date") 101 | ) 102 | assert_frame_equal(result, expected) 103 | 104 | 105 | def test_convert_tz_to_local_datetime_literal() -> None: 106 | df = pl.DataFrame( 107 | {"date": [datetime(2020, 10, 15, tzinfo=timezone.utc)]} 108 | ).with_columns(pl.col("date").dt.convert_time_zone("Europe/London")) 109 | 110 | expected = df.with_columns( 111 | pl.lit(datetime(2020, 10, 14, 20, 0)).alias("local_dt") 112 | ) 113 | 114 | result = df.with_columns( 115 | xdt.to_local_datetime("date", "America/New_York").alias("local_dt") 116 | ) 117 | 118 | assert_frame_equal(result, expected) 119 | 120 | 121 | def test_convert_tz_to_local_datetime_schema() -> None: 122 | df = pl.LazyFrame({"date": [datetime(2020, 10, 15, tzinfo=timezone.utc)]}) 123 | result = df.with_columns( 124 | xdt.from_local_datetime("date", "America/New_York", "Asia/Kathmandu") 125 | ) 126 | assert result.collect_schema()["date"] == pl.Datetime( 127 | "us", "Asia/Kathmandu" 128 | ) 129 | assert result.collect().schema["date"] == pl.Datetime( 130 | "us", "Asia/Kathmandu" 131 | ) 132 | -------------------------------------------------------------------------------- /tests/test_month_delta.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | import polars as pl 4 | from dateutil.relativedelta import relativedelta 5 | from hypothesis import example, given, settings 6 | from hypothesis import strategies as st 7 | from polars.testing import assert_frame_equal 8 | 9 | import polars_xdt as xdt 10 | 11 | 12 | @given( 13 | start_date=st.dates( 14 | min_value=date(1924, 1, 1), max_value=date(2024, 12, 31) 15 | ), 16 | end_date=st.dates(min_value=date(1960, 1, 1), max_value=date(2024, 12, 31)), 17 | ) 18 | @example(start_date=date(2022, 2, 28), end_date=date(2024, 2, 29)) # Leap year 19 | @example(start_date=date(2024, 1, 1), end_date=date(2024, 1, 31)) # Same month 20 | @example(start_date=date(1973, 1, 1), end_date=date(1973, 1, 1)) # Same date 21 | @example(start_date=date(2019, 12, 31), end_date=date(2020, 1, 1)) # Border 22 | @example(start_date=date(2018, 12, 1), end_date=date(2020, 1, 1)) # End of year 23 | @example(start_date=date(2022, 12, 1), end_date=date(2020, 1, 1)) # Negative 24 | @example(start_date=date(2000, 3, 29), end_date=date(2003, 1, 28)) 25 | @settings(max_examples=500) 26 | def test_month_delta_hypothesis(start_date: date, end_date: date) -> None: 27 | df = pl.DataFrame( 28 | { 29 | "start_date": [start_date], 30 | "end_date": [end_date], 31 | } 32 | ) 33 | result = df.select(result=xdt.month_delta("start_date", "end_date"))[ 34 | "result" 35 | ].item() 36 | 37 | expected = 0 38 | if start_date <= end_date: 39 | while start_date + relativedelta(months=expected + 1) <= end_date: 40 | expected += 1 41 | else: 42 | while start_date + relativedelta(months=expected - 1) >= end_date: 43 | expected -= 1 44 | assert result == expected 45 | 46 | 47 | def test_month_delta_broadcasting() -> None: 48 | df = pl.DataFrame( 49 | { 50 | "start_date": [ 51 | date(2024, 3, 1), 52 | date(2024, 3, 31), 53 | date(2022, 2, 28), 54 | date(2023, 1, 31), 55 | date(2019, 12, 31), 56 | ], 57 | }, 58 | ) 59 | result = df.with_columns( 60 | xdt.month_delta("start_date", date(2023, 2, 28)).alias("month_delta") 61 | ) 62 | expected = pl.DataFrame( 63 | { 64 | "start_date": [ 65 | date(2024, 3, 1), 66 | date(2024, 3, 31), 67 | date(2022, 2, 28), 68 | date(2023, 1, 31), 69 | date(2019, 12, 31), 70 | ], 71 | "month_delta": [-12, -13, 12, 1, 38], 72 | }, 73 | schema_overrides={"month_delta": pl.Int32}, 74 | ) 75 | assert_frame_equal(result, expected) 76 | 77 | 78 | def test_month_delta_broadcasting_all_nulls() -> None: 79 | df = pl.DataFrame( 80 | { 81 | "start_date": [ 82 | date(2024, 3, 1), 83 | date(2024, 3, 31), 84 | date(2022, 2, 28), 85 | date(2023, 1, 31), 86 | date(2019, 12, 31), 87 | ], 88 | }, 89 | ) 90 | result = df.with_columns( 91 | xdt.month_delta("start_date", pl.Series([None], dtype=pl.Date)).alias( 92 | "month_delta" 93 | ) 94 | ) 95 | expected = pl.DataFrame( 96 | { 97 | "start_date": [ 98 | date(2024, 3, 1), 99 | date(2024, 3, 31), 100 | date(2022, 2, 28), 101 | date(2023, 1, 31), 102 | date(2019, 12, 31), 103 | ], 104 | "month_delta": [None, None, None, None, None], 105 | }, 106 | schema_overrides={"month_delta": pl.Int32}, 107 | ) 108 | assert_frame_equal(result, expected) 109 | 110 | 111 | def test_month_delta_nulls() -> None: 112 | df = pl.DataFrame( 113 | { 114 | "start_date": [ 115 | date(2024, 3, 1), 116 | None, 117 | None, 118 | date(2023, 1, 31), 119 | date(2019, 12, 31), 120 | ], 121 | "end_date": [ 122 | None, 123 | date(2024, 3, 31), 124 | None, 125 | date(2023, 1, 31), 126 | date(2019, 12, 31), 127 | ], 128 | }, 129 | ) 130 | result = df.with_columns( 131 | xdt.month_delta("start_date", "end_date").alias("month_delta") 132 | )["month_delta"].to_list() 133 | expected = [None, None, None, 0, 0] 134 | assert result == expected 135 | -------------------------------------------------------------------------------- /polars_xdt/ranges.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import re 4 | from typing import TYPE_CHECKING, Literal, Union, overload 5 | 6 | import polars as pl 7 | 8 | mapping = {"Mon": 1, "Tue": 2, "Wed": 3, "Thu": 4, "Fri": 5, "Sat": 6, "Sun": 7} 9 | 10 | if TYPE_CHECKING: 11 | import sys 12 | from collections.abc import Sequence 13 | 14 | if sys.version_info >= (3, 10): 15 | from typing import TypeAlias 16 | else: 17 | from typing_extensions import TypeAlias 18 | from datetime import date, datetime, timedelta 19 | 20 | ClosedInterval: TypeAlias = Literal[ 21 | "left", "right", "both", "none" 22 | ] # ClosedWindow 23 | IntoExprColumn: TypeAlias = Union["pl.Expr", "pl.Series", str] 24 | 25 | 26 | @overload 27 | def date_range( 28 | start: date | datetime | IntoExprColumn, 29 | end: date | datetime | IntoExprColumn, 30 | interval: str | timedelta = "1d", 31 | *, 32 | closed: ClosedInterval = ..., 33 | eager: Literal[False] = ..., 34 | weekend: Sequence[str] = ..., 35 | holidays: Sequence[date] | None = ..., 36 | ) -> pl.Expr: ... 37 | 38 | 39 | @overload 40 | def date_range( 41 | start: date | IntoExprColumn, 42 | end: date | IntoExprColumn, 43 | interval: str | timedelta = "1d", 44 | *, 45 | closed: ClosedInterval = ..., 46 | eager: Literal[True], 47 | weekend: Sequence[str] = ..., 48 | holidays: Sequence[date] | None = ..., 49 | ) -> pl.Series: ... 50 | 51 | 52 | @overload 53 | def date_range( 54 | start: date | IntoExprColumn, 55 | end: date | IntoExprColumn, 56 | interval: str | timedelta = "1d", 57 | *, 58 | closed: ClosedInterval = ..., 59 | eager: bool = ..., 60 | weekend: Sequence[str] = ..., 61 | holidays: Sequence[date] | None = ..., 62 | ) -> pl.Series | pl.Expr: ... 63 | 64 | 65 | def date_range( # noqa: PLR0913 66 | start: date | IntoExprColumn, 67 | end: date | IntoExprColumn, 68 | interval: str | timedelta = "1bd", 69 | *, 70 | closed: ClosedInterval = "both", 71 | eager: bool = False, 72 | weekend: Sequence[str] = ("Sat", "Sun"), 73 | holidays: Sequence[date] | None = None, 74 | ) -> pl.Series | pl.Expr: 75 | """ 76 | Create a range of dates with a given interval and filter out weekends and holidays. 77 | 78 | Parameters 79 | ---------- 80 | start 81 | Lower bound of the date range. 82 | end 83 | Upper bound of the date range. 84 | interval 85 | Interval of the range periods, specified as a Python ``timedelta`` object 86 | or using the Polars duration string language (see "Notes" section below). 87 | 88 | To create a month-end date series, combine with :meth:`Expr.dt.month_end` (see 89 | "Examples" section below). 90 | closed : {'both', 'left', 'right', 'none'} 91 | Define which sides of the range are closed (inclusive). 92 | eager 93 | Evaluate immediately and return a ``Series``. 94 | If set to ``False`` (default), return an expression instead. 95 | weekend 96 | The days of the week that are considered weekends. Defaults to ("Sat", "Sun"). 97 | holidays 98 | The holidays to exclude from the calculation. Defaults to None. This should 99 | be a list of ``datetime.date`` s. 100 | 101 | Returns 102 | ------- 103 | Expr or Series 104 | Column of data type :class:`Date`. 105 | 106 | Examples 107 | -------- 108 | >>> from datetime import date 109 | >>> import polars as pl 110 | >>> import polars_xdt 111 | >>> pl.DataFrame( 112 | ... { 113 | ... "date": polars_xdt.date_range( 114 | ... date(2023, 1, 1), date(2023, 1, 10), "1bd", eager=True 115 | ... ), 116 | ... } 117 | ... ) 118 | shape: (7, 1) 119 | ┌────────────┐ 120 | │ date │ 121 | │ --- │ 122 | │ date │ 123 | ╞════════════╡ 124 | │ 2023-01-02 │ 125 | │ 2023-01-03 │ 126 | │ 2023-01-04 │ 127 | │ 2023-01-05 │ 128 | │ 2023-01-06 │ 129 | │ 2023-01-09 │ 130 | │ 2023-01-10 │ 131 | └────────────┘ 132 | 133 | """ 134 | if weekend == ("Sat", "Sun"): 135 | weekend_int = [6, 7] 136 | else: 137 | weekend_int = sorted({mapping[name] for name in weekend}) 138 | if holidays is None: 139 | holidays = [] 140 | 141 | if not (isinstance(interval, str) and re.match(r"^-?\d+bd$", interval)): 142 | msg = "Only intervals of the form 'nbd' (where n is an integer) are supported." 143 | raise ValueError(msg) 144 | interval = interval.replace("bd", "d") 145 | 146 | expr = pl.date_range( 147 | start, 148 | end, 149 | interval, 150 | closed=closed, 151 | eager=False, 152 | ) 153 | expr = expr.filter(~expr.dt.date().is_in(holidays)) 154 | expr = expr.filter(~expr.dt.weekday().is_in(weekend_int)) 155 | if eager: 156 | df = pl.select(expr) 157 | return df[df.columns[0]] 158 | return expr 159 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | https://www.linkedin.com/in/marcogorelli/. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /src/month_delta.rs: -------------------------------------------------------------------------------- 1 | use chrono::Datelike; 2 | use chrono::NaiveDate; 3 | use polars::prelude::*; 4 | 5 | const EPOCH_DAYS_FROM_CE: i32 = 719_163; 6 | 7 | // Copied from https://docs.pola.rs/docs/rust/dev/src/polars_time/windows/duration.rs.html#398 8 | // `add_month` is a private function. 9 | fn add_month(ts: NaiveDate, n_months: i64) -> NaiveDate { 10 | // Have to define, because it is hidden 11 | const DAYS_PER_MONTH: [[i64; 12]; 2] = [ 12 | //J F M A M J J A S O N D 13 | [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], // non-leap year 14 | [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], // leap year 15 | ]; 16 | let months = n_months; 17 | 18 | // Retrieve the current date and increment the values 19 | // based on the number of months 20 | 21 | let mut year = ts.year(); 22 | let mut month = ts.month() as i32; 23 | let mut day = ts.day(); 24 | year += (months / 12) as i32; 25 | month += (months % 12) as i32; 26 | 27 | // if the month overflowed or underflowed, adjust the year 28 | // accordingly. Because we add the modulo for the months 29 | // the year will only adjust by one 30 | if month > 12 { 31 | year += 1; 32 | month -= 12; 33 | } else if month <= 0 { 34 | year -= 1; 35 | month += 12; 36 | } 37 | 38 | // Adding this not to import copy pasta again 39 | let leap_year = year % 400 == 0 || (year % 4 == 0 && year % 100 != 0); 40 | // Normalize the day if we are past the end of the month. 41 | let last_day_of_month = DAYS_PER_MONTH[leap_year as usize][(month - 1) as usize] as u32; 42 | 43 | if day > last_day_of_month { 44 | day = last_day_of_month 45 | } 46 | 47 | NaiveDate::from_ymd_opt(year, month as u32, day).unwrap() 48 | } 49 | 50 | /// Calculates the difference in months between two dates. 51 | /// 52 | /// The difference is expressed as the number of whole months between the two dates. 53 | /// If `right` is before `left`, the return value will be negative. 54 | /// 55 | /// # Arguments 56 | /// 57 | /// * `left`: `NaiveDate` - The start date. 58 | /// * `right`: `NaiveDate` - The end date. 59 | /// 60 | /// # Returns 61 | /// 62 | /// * `i32` - The number of whole months between `left` and `right`. 63 | /// 64 | /// # Examples 65 | /// 66 | /// ``` 67 | /// let start_date = NaiveDate::from_ymd(2023, 1, 1); 68 | /// let end_date = NaiveDate::from_ymd(2023, 4, 1); 69 | /// assert_eq!(get_m_diff(start_date, end_date), 3); 70 | /// ``` 71 | fn get_m_diff(left: NaiveDate, right: NaiveDate) -> i32 { 72 | let mut n = 0; 73 | if right >= left { 74 | if right.year() + 1 > left.year() { 75 | n = (right.year() - left.year() - 1) * 12; 76 | } 77 | while add_month(left, (n + 1).into()) <= right { 78 | n += 1; 79 | } 80 | } else { 81 | if left.year() + 1 > right.year() { 82 | n = -(left.year() - right.year() - 1) * 12; 83 | } 84 | while add_month(left, (n - 1).into()) >= right { 85 | n -= 1; 86 | } 87 | } 88 | n 89 | } 90 | 91 | /// Implements the month delta operation for Polars series containing dates. 92 | /// 93 | /// This function calculates the difference in months between two series of dates. 94 | /// The operation is pairwise: it computes the month difference for each pair 95 | /// of start and end dates in the input series. 96 | /// 97 | /// # Arguments 98 | /// 99 | /// * `start_dates`: `&Series` - A series of start dates. 100 | /// * `end_dates`: `&Series` - A series of end dates. 101 | /// 102 | /// # Returns 103 | /// 104 | /// * `PolarsResult` - A new series containing the month differences as `i32` values. 105 | /// 106 | /// # Errors 107 | /// 108 | /// Returns an error if the input series are not of the `Date` type. 109 | /// 110 | /// # Examples 111 | /// 112 | /// ``` 113 | /// use polars::prelude::*; 114 | /// let date1 = NaiveDate::from_ymd(2023, 1, 1); // January 1, 2023 115 | /// let date2 = NaiveDate::from_ymd(2023, 3, 1); // March 1, 2023 116 | /// let date3 = NaiveDate::from_ymd(2023, 4, 1); // April 1, 2023 117 | /// let date4 = NaiveDate::from_ymd(2023, 6, 1); // June 1, 2023 118 | /// let start_dates = Series::new("start_dates", &[date1, date2]); 119 | /// let end_dates = Series::new("end_dates", &[date3, date4]); 120 | /// let month_deltas = impl_month_delta(&start_dates, &end_dates).unwrap(); 121 | /// ``` 122 | pub(crate) fn impl_month_delta(start_dates: &Series, end_dates: &Series) -> PolarsResult { 123 | if (start_dates.dtype() != &DataType::Date) || (end_dates.dtype() != &DataType::Date) { 124 | polars_bail!(InvalidOperation: "polars_xdt.month_delta only works on Date type. Please cast to Date first."); 125 | } 126 | let start_dates = start_dates.date()?; 127 | let end_dates = end_dates.date()?; 128 | 129 | let month_diff: Int32Chunked = match end_dates.len() { 130 | 1 => match unsafe { end_dates.phys.get_unchecked(0) } { 131 | Some(end_date_i32) => { 132 | let end_date = 133 | NaiveDate::from_num_days_from_ce_opt(EPOCH_DAYS_FROM_CE + end_date_i32) 134 | .unwrap(); 135 | start_dates 136 | .as_date_iter() 137 | .map(|s_arr| s_arr.map(|start_date| get_m_diff(start_date, end_date))) 138 | .collect() 139 | } 140 | _ => Int32Chunked::full_null(PlSmallStr::EMPTY, start_dates.len()) 141 | }, 142 | _ => start_dates 143 | .as_date_iter() 144 | .zip(end_dates.as_date_iter()) 145 | .map(|(s_arr, e_arr)| { 146 | s_arr 147 | .zip(e_arr) 148 | .map(|(start_date, end_date)| get_m_diff(start_date, end_date)) 149 | }) 150 | .collect(), 151 | }; 152 | 153 | Ok(month_diff.into_series()) 154 | } 155 | -------------------------------------------------------------------------------- /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | # This file is based on the autogenerated one by maturin v1.7.8 with: 2 | # 3 | # maturin generate-ci github 4 | # 5 | # Differences are: 6 | # - removed x86, armv7, s390x, ppc64le targets from Linux 7 | # - removed free-threaded wheels 8 | # - removed musllinux 9 | # - have separate linux-just-test and linux-min-versions-just-test jobs 10 | # - add the `RUSTFLAGS: "-Dwarnings"` env variable 11 | 12 | name: CI 13 | 14 | on: 15 | push: 16 | branches: 17 | - main 18 | - master 19 | tags: 20 | - '*' 21 | pull_request: 22 | workflow_dispatch: 23 | 24 | permissions: 25 | contents: read 26 | 27 | # Make sure CI fails on all warnings, including Clippy lints 28 | env: 29 | RUSTFLAGS: "-Dwarnings" 30 | 31 | jobs: 32 | linux-just-test: 33 | runs-on: ubuntu-latest 34 | strategy: 35 | matrix: 36 | target: [x86_64] 37 | python-version: ["3.9", "3.11", "3.13"] 38 | steps: 39 | - uses: actions/checkout@v5 40 | - uses: actions/setup-python@v6 41 | with: 42 | python-version: ${{ matrix.python-version }} 43 | 44 | - name: Set up Rust 45 | run: rustup show 46 | - uses: mozilla-actions/sccache-action@v0.0.6 47 | - run: make venv 48 | - run: make pre-commit 49 | - run: make install 50 | - run: make test 51 | 52 | linux-min-versions-just-test: 53 | runs-on: ubuntu-latest 54 | strategy: 55 | matrix: 56 | target: [x86_64] 57 | python-version: ["3.9"] 58 | steps: 59 | - uses: actions/checkout@v5 60 | - uses: actions/setup-python@v6 61 | with: 62 | python-version: ${{ matrix.python-version }} 63 | 64 | - name: Set up Rust 65 | run: rustup show 66 | - uses: mozilla-actions/sccache-action@v0.0.6 67 | - run: make venv 68 | - run: .venv/bin/python -m pip install polars==1.5.0 # min version 69 | - run: make install 70 | - run: make test 71 | 72 | linux: 73 | runs-on: ${{ matrix.platform.runner }} 74 | strategy: 75 | matrix: 76 | platform: 77 | - runner: ubuntu-22.04 78 | target: x86_64 79 | - runner: ubuntu-22.04 80 | target: aarch64 81 | steps: 82 | - uses: actions/checkout@v5 83 | - uses: actions/setup-python@v6 84 | with: 85 | python-version: 3.x 86 | - name: Build wheels 87 | uses: PyO3/maturin-action@v1 88 | with: 89 | target: ${{ matrix.platform.target }} 90 | args: --release --out dist 91 | sccache: 'true' 92 | manylinux: auto 93 | - name: Upload wheels 94 | uses: actions/upload-artifact@v4 95 | with: 96 | name: wheels-linux-${{ matrix.platform.target }} 97 | path: dist 98 | 99 | windows: 100 | runs-on: ${{ matrix.platform.runner }} 101 | strategy: 102 | matrix: 103 | platform: 104 | - runner: windows-latest 105 | target: x64 106 | steps: 107 | - uses: actions/checkout@v5 108 | - uses: actions/setup-python@v6 109 | with: 110 | python-version: 3.x 111 | architecture: ${{ matrix.platform.target }} 112 | - name: Build wheels 113 | uses: PyO3/maturin-action@v1 114 | with: 115 | target: ${{ matrix.platform.target }} 116 | args: --release --out dist 117 | sccache: 'true' 118 | - name: Upload wheels 119 | uses: actions/upload-artifact@v4 120 | with: 121 | name: wheels-windows-${{ matrix.platform.target }} 122 | path: dist 123 | 124 | macos: 125 | runs-on: ${{ matrix.platform.runner }} 126 | strategy: 127 | matrix: 128 | platform: 129 | - runner: macos-13 130 | target: x86_64 131 | - runner: macos-14 132 | target: aarch64 133 | steps: 134 | - uses: actions/checkout@v5 135 | - uses: actions/setup-python@v6 136 | with: 137 | python-version: 3.x 138 | - name: Build wheels 139 | uses: PyO3/maturin-action@v1 140 | with: 141 | target: ${{ matrix.platform.target }} 142 | args: --release --out dist 143 | sccache: 'true' 144 | - name: Upload wheels 145 | uses: actions/upload-artifact@v4 146 | with: 147 | name: wheels-macos-${{ matrix.platform.target }} 148 | path: dist 149 | 150 | sdist: 151 | runs-on: ubuntu-latest 152 | steps: 153 | - uses: actions/checkout@v5 154 | - name: Build sdist 155 | uses: PyO3/maturin-action@v1 156 | with: 157 | command: sdist 158 | args: --out dist 159 | - name: Upload sdist 160 | uses: actions/upload-artifact@v4 161 | with: 162 | name: wheels-sdist 163 | path: dist 164 | 165 | release: 166 | name: Release 167 | runs-on: ubuntu-latest 168 | if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }} 169 | needs: [linux, windows, macos, sdist] 170 | environment: pypi 171 | permissions: 172 | # Use to sign the release artifacts 173 | id-token: write 174 | # Used to upload release artifacts 175 | contents: write 176 | # Used to generate artifact attestation 177 | attestations: write 178 | steps: 179 | - uses: actions/download-artifact@v5 180 | - name: Generate artifact attestation 181 | uses: actions/attest-build-provenance@v3 182 | with: 183 | subject-path: 'wheels-*/*' 184 | - name: Publish to PyPI 185 | if: ${{ startsWith(github.ref, 'refs/tags/') }} 186 | uses: PyO3/maturin-action@v1 187 | env: 188 | MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }} 189 | with: 190 | command: upload 191 | args: --non-interactive --skip-existing wheels-*/* 192 | 193 | -------------------------------------------------------------------------------- /src/timezone.rs: -------------------------------------------------------------------------------- 1 | use arity::try_binary_elementwise; 2 | use chrono::{LocalResult, NaiveDateTime, TimeZone}; 3 | use polars::prelude::*; 4 | use polars_arrow::legacy::time_zone::Tz; 5 | use pyo3_polars::export::polars_core::datatypes::time_zone::parse_time_zone; 6 | use pyo3_polars::export::polars_core::datatypes::TimeZone as PolarsTimeZone; 7 | use pyo3_polars::export::polars_core::utils::arrow::legacy::kernels::Ambiguous; 8 | use pyo3_polars::export::polars_core::utils::arrow::temporal_conversions::{ 9 | timestamp_ms_to_datetime, timestamp_ns_to_datetime, timestamp_us_to_datetime, 10 | }; 11 | use std::str::FromStr; 12 | 13 | fn naive_utc_to_naive_local_in_new_time_zone( 14 | from_tz: &Tz, 15 | to_tz: &Tz, 16 | ndt: NaiveDateTime, 17 | ) -> NaiveDateTime { 18 | // ndt is the UTC datetime corresponding to the datetime in from_tz timezone 19 | from_tz 20 | .from_utc_datetime(&ndt) 21 | .with_timezone(to_tz) 22 | .naive_local() 23 | } 24 | 25 | fn naive_local_to_naive_utc_in_new_time_zone( 26 | from_tz: &Tz, 27 | to_tz: &Tz, 28 | ndt: NaiveDateTime, 29 | ambiguous: &Ambiguous, 30 | ) -> PolarsResult { 31 | match from_tz.from_local_datetime(&ndt) { 32 | LocalResult::Single(dt) => Ok(dt.with_timezone(to_tz).naive_utc()), 33 | LocalResult::Ambiguous(dt_earliest, dt_latest) => match ambiguous { 34 | Ambiguous::Earliest => Ok(dt_earliest.with_timezone(to_tz).naive_utc()), 35 | Ambiguous::Latest => Ok(dt_latest.with_timezone(to_tz).naive_utc()), 36 | Ambiguous::Raise => { 37 | polars_bail!(ComputeError: "datetime '{}' is ambiguous in time zone '{}'. Please use `ambiguous` to tell how it should be localized.", ndt, to_tz) 38 | } 39 | Ambiguous::Null => { 40 | unimplemented!("Ambiguous::Null is not yet supported"); 41 | } 42 | }, 43 | LocalResult::None => polars_bail!(ComputeError: 44 | "datetime '{}' is non-existent in time zone '{}'. Non-existent datetimes are not yet supported", 45 | ndt, to_tz 46 | ), 47 | } 48 | } 49 | 50 | pub fn elementwise_to_local_datetime( 51 | datetime: &Logical, 52 | tz: &StringChunked, 53 | ) -> PolarsResult { 54 | let binding = PlSmallStr::from("UTC"); 55 | let from_time_zone = datetime.time_zone().as_deref().unwrap_or(&binding); 56 | let from_tz = parse_time_zone(from_time_zone)?; 57 | 58 | let timestamp_to_datetime: fn(i64) -> NaiveDateTime = match datetime.time_unit() { 59 | TimeUnit::Milliseconds => timestamp_ms_to_datetime, 60 | TimeUnit::Microseconds => timestamp_us_to_datetime, 61 | TimeUnit::Nanoseconds => timestamp_ns_to_datetime, 62 | }; 63 | let datetime_to_timestamp: fn(NaiveDateTime) -> i64 = match datetime.time_unit() { 64 | TimeUnit::Milliseconds => datetime_to_timestamp_ms, 65 | TimeUnit::Microseconds => datetime_to_timestamp_us, 66 | TimeUnit::Nanoseconds => datetime_to_timestamp_ns, 67 | }; 68 | let out: Result, PolarsError> = match tz.len() { 69 | 1 => match unsafe { tz.get_unchecked(0) } { 70 | Some(convert_tz) => { 71 | let to_tz = parse_time_zone(convert_tz)?; 72 | Ok(datetime.phys.apply(|timestamp_opt| { 73 | timestamp_opt.map(|ts| { 74 | let ndt = timestamp_to_datetime(ts); 75 | datetime_to_timestamp(naive_utc_to_naive_local_in_new_time_zone( 76 | &from_tz, &to_tz, ndt, 77 | )) 78 | }) 79 | })) 80 | } 81 | _ => Ok(Int64Chunked::full_null(PlSmallStr::EMPTY, datetime.len())), 82 | }, 83 | _ => try_binary_elementwise(&datetime.phys, tz, |timestamp_opt, convert_tz_opt| { 84 | match (timestamp_opt, convert_tz_opt) { 85 | (Some(timestamp), Some(convert_tz)) => { 86 | let ndt = timestamp_to_datetime(timestamp); 87 | let to_tz = parse_time_zone(convert_tz)?; 88 | Ok(Some(datetime_to_timestamp( 89 | naive_utc_to_naive_local_in_new_time_zone(&from_tz, &to_tz, ndt), 90 | ))) 91 | } 92 | _ => Ok(None), 93 | } 94 | }), 95 | }; 96 | let out = out?.into_datetime(datetime.time_unit(), None); 97 | Ok(out) 98 | } 99 | 100 | pub fn elementwise_from_local_datetime( 101 | datetime: &Logical, 102 | from_tz: &StringChunked, 103 | out_tz: &str, 104 | ambiguous: &str, 105 | ) -> PolarsResult { 106 | let to_tz = parse_time_zone(out_tz)?; 107 | let ambig = Ambiguous::from_str(ambiguous)?; 108 | let timestamp_to_datetime: fn(i64) -> NaiveDateTime = match datetime.time_unit() { 109 | TimeUnit::Milliseconds => timestamp_ms_to_datetime, 110 | TimeUnit::Microseconds => timestamp_us_to_datetime, 111 | TimeUnit::Nanoseconds => timestamp_ns_to_datetime, 112 | }; 113 | let datetime_to_timestamp: fn(NaiveDateTime) -> i64 = match datetime.time_unit() { 114 | TimeUnit::Milliseconds => datetime_to_timestamp_ms, 115 | TimeUnit::Microseconds => datetime_to_timestamp_us, 116 | TimeUnit::Nanoseconds => datetime_to_timestamp_ns, 117 | }; 118 | let out = match from_tz.len() { 119 | 1 => match unsafe { from_tz.get_unchecked(0) } { 120 | Some(from_tz) => { 121 | let from_tz = parse_time_zone(from_tz)?; 122 | datetime.phys.try_apply_nonnull_values_generic(|timestamp| { 123 | let ndt = timestamp_to_datetime(timestamp); 124 | Ok::(datetime_to_timestamp( 125 | naive_local_to_naive_utc_in_new_time_zone(&from_tz, &to_tz, ndt, &ambig)?, 126 | )) 127 | }) 128 | } 129 | _ => Ok(Int64Chunked::full_null(PlSmallStr::EMPTY, datetime.len())), 130 | }, 131 | _ => try_binary_elementwise(&datetime.phys, from_tz, |timestamp_opt, from_tz_opt| { 132 | match (timestamp_opt, from_tz_opt) { 133 | (Some(timestamp), Some(from_tz)) => { 134 | let ndt = timestamp_to_datetime(timestamp); 135 | let from_tz = parse_time_zone(from_tz)?; 136 | Ok(Some(datetime_to_timestamp( 137 | naive_local_to_naive_utc_in_new_time_zone(&from_tz, &to_tz, ndt, &ambig)?, 138 | ))) 139 | } 140 | _ => Ok(None), 141 | } 142 | }), 143 | }; 144 | let out = out?.into_datetime( 145 | datetime.time_unit(), 146 | PolarsTimeZone::opt_try_new(Some(out_tz))?, 147 | ); 148 | Ok(out) 149 | } 150 | -------------------------------------------------------------------------------- /polars_xdt/functions.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import sys 4 | from datetime import date 5 | from pathlib import Path 6 | from typing import TYPE_CHECKING, Literal 7 | 8 | import polars as pl 9 | from polars.plugins import register_plugin_function 10 | 11 | from polars_xdt.utils import parse_into_expr 12 | 13 | if sys.version_info >= (3, 10): 14 | from typing import TypeAlias 15 | else: 16 | from typing_extensions import TypeAlias 17 | 18 | if TYPE_CHECKING: 19 | from collections.abc import Sequence 20 | 21 | from polars import Expr 22 | 23 | from polars_xdt.typing import IntoExprColumn 24 | 25 | Ambiguous: TypeAlias = Literal["earliest", "latest", "raise", "null"] 26 | 27 | RollStrategy: TypeAlias = Literal["raise", "forward", "backward"] 28 | 29 | 30 | PLUGIN_PATH = Path(__file__).parent 31 | 32 | mapping = {"Mon": 1, "Tue": 2, "Wed": 3, "Thu": 4, "Fri": 5, "Sat": 6, "Sun": 7} 33 | reverse_mapping = {value: key for key, value in mapping.items()} 34 | 35 | 36 | def get_weekmask(weekend: Sequence[str]) -> list[bool]: 37 | if weekend == ("Sat", "Sun"): 38 | weekmask = [True, True, True, True, True, False, False] 39 | else: 40 | weekmask = [reverse_mapping[i] not in weekend for i in range(1, 8)] 41 | if sum(weekmask) == 0: 42 | msg = f"At least one day of the week must be a business day. Got weekend={weekend}" 43 | raise ValueError(msg) 44 | return weekmask 45 | 46 | 47 | def is_workday( 48 | expr: IntoExprColumn, 49 | *, 50 | weekend: Sequence[str] = ("Sat", "Sun"), 51 | holidays: Sequence[date] | None = None, 52 | ) -> pl.Expr: 53 | """ 54 | Determine whether a day is a workday. 55 | 56 | Parameters 57 | ---------- 58 | expr 59 | Input expression. 60 | weekend 61 | The days of the week that are considered weekends. Defaults to ("Sat", "Sun"). 62 | holidays 63 | The holidays to exclude from the calculation. Defaults to None. This should 64 | be a list of ``datetime.date`` s. 65 | 66 | Returns 67 | ------- 68 | polars.Expr 69 | 70 | Examples 71 | -------- 72 | >>> from datetime import date 73 | >>> import polars as pl 74 | >>> import polars_xdt as xdt 75 | >>> df = pl.DataFrame( 76 | ... { 77 | ... "date": [ 78 | ... date(2023, 1, 4), 79 | ... date(2023, 5, 1), 80 | ... date(2023, 9, 9), 81 | ... ], 82 | ... } 83 | ... ) 84 | >>> df.with_columns(is_workday=xdt.is_workday("date")) 85 | shape: (3, 2) 86 | ┌────────────┬────────────┐ 87 | │ date ┆ is_workday │ 88 | │ --- ┆ --- │ 89 | │ date ┆ bool │ 90 | ╞════════════╪════════════╡ 91 | │ 2023-01-04 ┆ true │ 92 | │ 2023-05-01 ┆ true │ 93 | │ 2023-09-09 ┆ false │ 94 | └────────────┴────────────┘ 95 | 96 | """ 97 | expr = parse_into_expr(expr) 98 | weekend_int = [mapping[x] for x in weekend] 99 | if holidays is not None: 100 | return ~( 101 | expr.dt.date().is_in(holidays) 102 | | expr.dt.weekday().is_in(weekend_int) 103 | ) 104 | return ~expr.dt.weekday().is_in(weekend_int) 105 | 106 | 107 | def from_local_datetime( 108 | expr: IntoExprColumn, 109 | from_tz: str | Expr, 110 | to_tz: str, 111 | ambiguous: Ambiguous = "raise", 112 | ) -> pl.Expr: 113 | """ 114 | Convert from local datetime in given time zone to new timezone. 115 | 116 | Parameters 117 | ---------- 118 | expr 119 | Expression to convert. 120 | from_tz 121 | Current timezone of each datetime 122 | to_tz 123 | Timezone to convert to 124 | ambiguous 125 | Determine how to deal with ambiguous datetimes: 126 | 127 | - `'raise'` (default): raise 128 | - `'earliest'`: use the earliest datetime 129 | - `'latest'`: use the latest datetime 130 | 131 | Returns 132 | ------- 133 | Expr 134 | Expression of data type :class:`DateTime`. 135 | 136 | Examples 137 | -------- 138 | You can go from a localized datetime back to expressing the datetimes 139 | in a single timezone with `from_local_datetime`. 140 | 141 | >>> from datetime import datetime 142 | >>> import polars_xdt as xdt 143 | >>> df = pl.DataFrame( 144 | ... { 145 | ... "local_dt": [ 146 | ... datetime(2020, 10, 10, 1), 147 | ... datetime(2020, 10, 10, 2), 148 | ... datetime(2020, 10, 9, 20), 149 | ... ], 150 | ... "timezone": [ 151 | ... "Europe/London", 152 | ... "Africa/Kigali", 153 | ... "America/New_York", 154 | ... ], 155 | ... } 156 | ... ) 157 | >>> df.with_columns( 158 | ... xdt.from_local_datetime( 159 | ... "local_dt", pl.col("timezone"), "UTC" 160 | ... ).alias("date") 161 | ... ) 162 | shape: (3, 3) 163 | ┌─────────────────────┬──────────────────┬─────────────────────────┐ 164 | │ local_dt ┆ timezone ┆ date │ 165 | │ --- ┆ --- ┆ --- │ 166 | │ datetime[μs] ┆ str ┆ datetime[μs, UTC] │ 167 | ╞═════════════════════╪══════════════════╪═════════════════════════╡ 168 | │ 2020-10-10 01:00:00 ┆ Europe/London ┆ 2020-10-10 00:00:00 UTC │ 169 | │ 2020-10-10 02:00:00 ┆ Africa/Kigali ┆ 2020-10-10 00:00:00 UTC │ 170 | │ 2020-10-09 20:00:00 ┆ America/New_York ┆ 2020-10-10 00:00:00 UTC │ 171 | └─────────────────────┴──────────────────┴─────────────────────────┘ 172 | 173 | """ 174 | expr = parse_into_expr(expr) 175 | from_tz = parse_into_expr(from_tz, str_as_lit=True) 176 | return register_plugin_function( 177 | plugin_path=PLUGIN_PATH, 178 | function_name="from_local_datetime", 179 | is_elementwise=True, 180 | args=[expr, from_tz], 181 | kwargs={ 182 | "to_tz": to_tz, 183 | "ambiguous": ambiguous, 184 | }, 185 | ) 186 | 187 | 188 | def to_local_datetime( 189 | expr: IntoExprColumn, 190 | time_zone: str | Expr, 191 | ) -> pl.Expr: 192 | """ 193 | Convert to local datetime in given time zone. 194 | 195 | Parameters 196 | ---------- 197 | expr 198 | Expression to convert. 199 | time_zone 200 | Time zone to convert to. 201 | 202 | Returns 203 | ------- 204 | Expr 205 | Expression of data type :class:`DateTime`. 206 | 207 | Examples 208 | -------- 209 | You can use `to_local_datetime` to figure out how a tz-aware datetime 210 | will be expressed as a local datetime. 211 | 212 | >>> from datetime import datetime 213 | >>> import polars_xdt as xdt 214 | >>> df = pl.DataFrame( 215 | ... { 216 | ... "date_col": [datetime(2020, 10, 10)] * 3, 217 | ... "timezone": [ 218 | ... "Europe/London", 219 | ... "Africa/Kigali", 220 | ... "America/New_York", 221 | ... ], 222 | ... } 223 | ... ).with_columns(pl.col("date_col").dt.replace_time_zone("UTC")) 224 | >>> df.with_columns( 225 | ... xdt.to_local_datetime("date_col", pl.col("timezone")).alias( 226 | ... "local_dt" 227 | ... ) 228 | ... ) 229 | shape: (3, 3) 230 | ┌─────────────────────────┬──────────────────┬─────────────────────┐ 231 | │ date_col ┆ timezone ┆ local_dt │ 232 | │ --- ┆ --- ┆ --- │ 233 | │ datetime[μs, UTC] ┆ str ┆ datetime[μs] │ 234 | ╞═════════════════════════╪══════════════════╪═════════════════════╡ 235 | │ 2020-10-10 00:00:00 UTC ┆ Europe/London ┆ 2020-10-10 01:00:00 │ 236 | │ 2020-10-10 00:00:00 UTC ┆ Africa/Kigali ┆ 2020-10-10 02:00:00 │ 237 | │ 2020-10-10 00:00:00 UTC ┆ America/New_York ┆ 2020-10-09 20:00:00 │ 238 | └─────────────────────────┴──────────────────┴─────────────────────┘ 239 | 240 | """ 241 | expr = parse_into_expr(expr) 242 | time_zone = parse_into_expr(time_zone, str_as_lit=True) 243 | return register_plugin_function( 244 | plugin_path=PLUGIN_PATH, 245 | function_name="to_local_datetime", 246 | is_elementwise=True, 247 | args=[expr, time_zone], 248 | ) 249 | 250 | 251 | def format_localized( 252 | expr: IntoExprColumn, 253 | format: str, # noqa: A002 254 | locale: str = "uk_UA", 255 | ) -> pl.Expr: 256 | """ 257 | Convert to local datetime in given time zone. 258 | 259 | Parameters 260 | ---------- 261 | expr 262 | Expression to format. 263 | format 264 | Format string, see https://docs.rs/chrono/latest/chrono/format/strftime/index.html 265 | for what's available. 266 | locale 267 | Locale to use for formatting. Defaults to "uk_UA", because that's what the OP 268 | requested https://github.com/pola-rs/polars/issues/12341. 269 | 270 | Returns 271 | ------- 272 | Expr 273 | Expression of data type :class:`Utf8`. 274 | 275 | Examples 276 | -------- 277 | >>> from datetime import datetime 278 | >>> import polars_xdt as xdt 279 | >>> df = pl.DataFrame( 280 | ... { 281 | ... "date_col": [datetime(2024, 8, 24), datetime(2024, 10, 1)], 282 | ... } 283 | ... ) 284 | >>> df.with_columns( 285 | ... result=xdt.format_localized( 286 | ... "date_col", format="%A, %d %B %Y", locale="uk_UA" 287 | ... ) 288 | ... ) 289 | shape: (2, 2) 290 | ┌─────────────────────┬──────────────────────────┐ 291 | │ date_col ┆ result │ 292 | │ --- ┆ --- │ 293 | │ datetime[μs] ┆ str │ 294 | ╞═════════════════════╪══════════════════════════╡ 295 | │ 2024-08-24 00:00:00 ┆ субота, 24 серпня 2024 │ 296 | │ 2024-10-01 00:00:00 ┆ вівторок, 01 жовтня 2024 │ 297 | └─────────────────────┴──────────────────────────┘ 298 | 299 | """ 300 | expr = parse_into_expr(expr) 301 | return register_plugin_function( 302 | plugin_path=PLUGIN_PATH, 303 | function_name="format_localized", 304 | is_elementwise=True, 305 | args=[expr], 306 | kwargs={"format": format, "locale": locale}, 307 | ) 308 | 309 | 310 | def to_julian_date(expr: str | pl.Expr) -> pl.Expr: 311 | """ 312 | Return the Julian date corresponding to given datetimes. 313 | 314 | Examples 315 | -------- 316 | >>> from datetime import datetime 317 | >>> import polars_xdt as xdt 318 | >>> df = pl.DataFrame( 319 | ... { 320 | ... "date_col": [ 321 | ... datetime(2013, 1, 1, 0, 30), 322 | ... datetime(2024, 1, 7, 13, 18, 51), 323 | ... ], 324 | ... } 325 | ... ) 326 | >>> with pl.Config(float_precision=10) as cfg: 327 | ... df.with_columns(julian_date=xdt.to_julian_date("date_col")) 328 | shape: (2, 2) 329 | ┌─────────────────────┬────────────────────┐ 330 | │ date_col ┆ julian_date │ 331 | │ --- ┆ --- │ 332 | │ datetime[μs] ┆ f64 │ 333 | ╞═════════════════════╪════════════════════╡ 334 | │ 2013-01-01 00:30:00 ┆ 2456293.5208333335 │ 335 | │ 2024-01-07 13:18:51 ┆ 2460317.0547569445 │ 336 | └─────────────────────┴────────────────────┘ 337 | 338 | """ 339 | expr = parse_into_expr(expr) 340 | return register_plugin_function( 341 | plugin_path=PLUGIN_PATH, 342 | function_name="to_julian_date", 343 | is_elementwise=True, 344 | args=[expr], 345 | ) 346 | 347 | 348 | def ceil( 349 | expr: IntoExprColumn, 350 | every: str | pl.Expr, 351 | ) -> pl.Expr: 352 | """ 353 | Find "ceiling" of datetime. 354 | 355 | Parameters 356 | ---------- 357 | expr 358 | Expression to take "ceiling" of. 359 | every 360 | Duration string, created with the 361 | the following string language: 362 | 363 | - 1ns (1 nanosecond) 364 | - 1us (1 microsecond) 365 | - 1ms (1 millisecond) 366 | - 1s (1 second) 367 | - 1m (1 minute) 368 | - 1h (1 hour) 369 | - 1d (1 calendar day) 370 | - 1w (1 calendar week) 371 | - 1mo (1 calendar month) 372 | - 1q (1 calendar quarter) 373 | - 1y (1 calendar year) 374 | 375 | These strings can be combined: 376 | 377 | - 3d12h4m25s # 3 days, 12 hours, 4 minutes, and 25 seconds 378 | 379 | By "calendar day", we mean the corresponding time on the next day (which may 380 | not be 24 hours, due to daylight savings). Similarly for "calendar week", 381 | "calendar month", "calendar quarter", and "calendar year". 382 | 383 | Returns 384 | ------- 385 | Expr 386 | Expression of the same type. 387 | 388 | Examples 389 | -------- 390 | >>> from datetime import datetime 391 | >>> import polars_xdt as xdt 392 | >>> df = pl.DataFrame( 393 | ... { 394 | ... "date_col": [datetime(2024, 8, 24), datetime(2024, 10, 1)], 395 | ... } 396 | ... ) 397 | >>> df.with_columns(result=xdt.ceil("date_col", "1mo")) 398 | shape: (2, 2) 399 | ┌─────────────────────┬─────────────────────┐ 400 | │ date_col ┆ result │ 401 | │ --- ┆ --- │ 402 | │ datetime[μs] ┆ datetime[μs] │ 403 | ╞═════════════════════╪═════════════════════╡ 404 | │ 2024-08-24 00:00:00 ┆ 2024-09-01 00:00:00 │ 405 | │ 2024-10-01 00:00:00 ┆ 2024-10-01 00:00:00 │ 406 | └─────────────────────┴─────────────────────┘ 407 | 408 | """ 409 | expr = parse_into_expr(expr) 410 | truncated = expr.dt.truncate(every) 411 | return ( 412 | pl.when(expr == truncated) 413 | .then(expr) 414 | .otherwise(truncated.dt.offset_by(every)) 415 | ) 416 | 417 | 418 | def day_name(expr: str | pl.Expr, locale: str | None = None) -> pl.Expr: 419 | """ 420 | Return day name, in specified locale (if specified). 421 | 422 | Returns 423 | ------- 424 | Expr 425 | Expression of data type :class:`Utf8`. 426 | 427 | See Also 428 | -------- 429 | format_localized : format according to locale. 430 | 431 | Examples 432 | -------- 433 | >>> from datetime import datetime 434 | >>> import polars_xdt as xdt 435 | >>> df = pl.DataFrame( 436 | ... { 437 | ... "ts": [datetime(2020, 10, 25), datetime(2020, 10, 26)], 438 | ... } 439 | ... ) 440 | >>> df.with_columns( 441 | ... english_day_name=xdt.day_name("ts"), 442 | ... french_day_name=xdt.day_name("ts", locale="fr_FR"), 443 | ... ukrainian_day_name=xdt.day_name("ts", locale="uk_UA"), 444 | ... ) 445 | shape: (2, 4) 446 | ┌─────────────────────┬──────────────────┬─────────────────┬────────────────────┐ 447 | │ ts ┆ english_day_name ┆ french_day_name ┆ ukrainian_day_name │ 448 | │ --- ┆ --- ┆ --- ┆ --- │ 449 | │ datetime[μs] ┆ str ┆ str ┆ str │ 450 | ╞═════════════════════╪══════════════════╪═════════════════╪════════════════════╡ 451 | │ 2020-10-25 00:00:00 ┆ Sunday ┆ dimanche ┆ неділя │ 452 | │ 2020-10-26 00:00:00 ┆ Monday ┆ lundi ┆ понеділок │ 453 | └─────────────────────┴──────────────────┴─────────────────┴────────────────────┘ 454 | 455 | """ 456 | expr = parse_into_expr(expr) 457 | if locale is None: 458 | result = expr.dt.to_string("%A") 459 | else: 460 | result = format_localized(expr, "%A", locale=locale) # type: ignore[attr-defined] 461 | return result 462 | 463 | 464 | def month_name(expr: str | pl.Expr, locale: str | None = None) -> pl.Expr: 465 | """ 466 | Return month name, in specified locale (if specified). 467 | 468 | Returns 469 | ------- 470 | Expr 471 | Expression of data type :class:`Utf8`. 472 | 473 | See Also 474 | -------- 475 | format_localized : format according to locale. 476 | 477 | Examples 478 | -------- 479 | >>> from datetime import datetime 480 | >>> import polars_xdt as xdt 481 | >>> df = pl.DataFrame( 482 | ... { 483 | ... "ts": [datetime(2020, 10, 25), datetime(2020, 11, 26)], 484 | ... } 485 | ... ) 486 | >>> df.with_columns( 487 | ... english_month_name=xdt.month_name("ts"), 488 | ... french_month_name=xdt.month_name("ts", locale="fr_FR"), 489 | ... ukrainian_month_name=xdt.month_name("ts", locale="uk_UA"), 490 | ... ) 491 | shape: (2, 4) 492 | ┌─────────────────────┬────────────────────┬───────────────────┬──────────────────────┐ 493 | │ ts ┆ english_month_name ┆ french_month_name ┆ ukrainian_month_name │ 494 | │ --- ┆ --- ┆ --- ┆ --- │ 495 | │ datetime[μs] ┆ str ┆ str ┆ str │ 496 | ╞═════════════════════╪════════════════════╪═══════════════════╪══════════════════════╡ 497 | │ 2020-10-25 00:00:00 ┆ October ┆ octobre ┆ жовтня │ 498 | │ 2020-11-26 00:00:00 ┆ November ┆ novembre ┆ листопада │ 499 | └─────────────────────┴────────────────────┴───────────────────┴──────────────────────┘ 500 | 501 | """ 502 | expr = parse_into_expr(expr) 503 | if locale is None: 504 | result = expr.dt.to_string("%B") 505 | else: 506 | result = format_localized(expr, "%B", locale=locale) 507 | return result 508 | 509 | 510 | def month_delta( 511 | start_dates: IntoExprColumn, 512 | end_dates: IntoExprColumn | date, 513 | ) -> pl.Expr: 514 | """ 515 | Calculate the number of months between two Series. 516 | 517 | Parameters 518 | ---------- 519 | start_dates 520 | A Series object containing the start dates. 521 | end_dates 522 | A Series object containing the end dates. 523 | 524 | Returns 525 | ------- 526 | polars.Expr 527 | 528 | Examples 529 | -------- 530 | >>> from datetime import date 531 | >>> import polars as pl 532 | >>> import polars_xdt as xdt 533 | >>> df = pl.DataFrame( 534 | ... { 535 | ... "start_date": [ 536 | ... date(2024, 3, 1), 537 | ... date(2024, 3, 31), 538 | ... date(2022, 2, 28), 539 | ... date(2023, 1, 31), 540 | ... date(2019, 12, 31), 541 | ... ], 542 | ... "end_date": [ 543 | ... date(2023, 2, 28), 544 | ... date(2023, 2, 28), 545 | ... date(2023, 2, 28), 546 | ... date(2023, 1, 31), 547 | ... date(2023, 1, 1), 548 | ... ], 549 | ... }, 550 | ... ) 551 | >>> df.with_columns( 552 | ... xdt.month_delta("start_date", "end_date").alias("month_delta") 553 | ... ) 554 | shape: (5, 3) 555 | ┌────────────┬────────────┬─────────────┐ 556 | │ start_date ┆ end_date ┆ month_delta │ 557 | │ --- ┆ --- ┆ --- │ 558 | │ date ┆ date ┆ i32 │ 559 | ╞════════════╪════════════╪═════════════╡ 560 | │ 2024-03-01 ┆ 2023-02-28 ┆ -12 │ 561 | │ 2024-03-31 ┆ 2023-02-28 ┆ -13 │ 562 | │ 2022-02-28 ┆ 2023-02-28 ┆ 12 │ 563 | │ 2023-01-31 ┆ 2023-01-31 ┆ 0 │ 564 | │ 2019-12-31 ┆ 2023-01-01 ┆ 36 │ 565 | └────────────┴────────────┴─────────────┘ 566 | 567 | """ 568 | start_dates = parse_into_expr(start_dates) 569 | if not isinstance(end_dates, date): 570 | end_dates = parse_into_expr(end_dates) 571 | 572 | return register_plugin_function( 573 | plugin_path=PLUGIN_PATH, 574 | function_name="month_delta", 575 | is_elementwise=True, 576 | args=[start_dates, end_dates], 577 | ) 578 | 579 | 580 | def arg_previous_greater(expr: IntoExprColumn) -> pl.Expr: 581 | """ 582 | Find the row count of the previous value greater than the current one. 583 | 584 | Parameters 585 | ---------- 586 | expr 587 | Expression. 588 | 589 | Returns 590 | ------- 591 | Expr 592 | UInt64 or UInt32 type, depending on the platform. 593 | 594 | Examples 595 | -------- 596 | >>> import polars as pl 597 | >>> import polars_xdt as xdt 598 | >>> df = pl.DataFrame({"value": [1, 9, 6, 7, 3]}) 599 | >>> df.with_columns(result=xdt.arg_previous_greater("value")) 600 | shape: (5, 2) 601 | ┌───────┬────────┐ 602 | │ value ┆ result │ 603 | │ --- ┆ --- │ 604 | │ i64 ┆ u32 │ 605 | ╞═══════╪════════╡ 606 | │ 1 ┆ null │ 607 | │ 9 ┆ 1 │ 608 | │ 6 ┆ 1 │ 609 | │ 7 ┆ 1 │ 610 | │ 3 ┆ 3 │ 611 | └───────┴────────┘ 612 | 613 | This can be useful when working with time series. For example, 614 | if you a dataset like this: 615 | 616 | >>> df = pl.DataFrame( 617 | ... { 618 | ... "date": [ 619 | ... "2024-02-01", 620 | ... "2024-02-02", 621 | ... "2024-02-03", 622 | ... "2024-02-04", 623 | ... "2024-02-05", 624 | ... "2024-02-06", 625 | ... "2024-02-07", 626 | ... "2024-02-08", 627 | ... "2024-02-09", 628 | ... "2024-02-10", 629 | ... ], 630 | ... "group": ["A", "A", "A", "A", "A", "B", "B", "B", "B", "B"], 631 | ... "value": [1, 9, None, 7, 3, 2, 4, 5, 1, 9], 632 | ... } 633 | ... ) 634 | >>> df = df.with_columns(pl.col("date").str.to_date()) 635 | 636 | and want find out, for each day and each item, how many days it's 637 | been since `'value'` was higher than it currently is, you could do 638 | 639 | >>> df.with_columns( 640 | ... result=( 641 | ... ( 642 | ... pl.col("date") 643 | ... - pl.col("date") 644 | ... .gather(xdt.arg_previous_greater("value")) 645 | ... .over("group") 646 | ... ).dt.total_days() 647 | ... ), 648 | ... ) 649 | shape: (10, 4) 650 | ┌────────────┬───────┬───────┬────────┐ 651 | │ date ┆ group ┆ value ┆ result │ 652 | │ --- ┆ --- ┆ --- ┆ --- │ 653 | │ date ┆ str ┆ i64 ┆ i64 │ 654 | ╞════════════╪═══════╪═══════╪════════╡ 655 | │ 2024-02-01 ┆ A ┆ 1 ┆ null │ 656 | │ 2024-02-02 ┆ A ┆ 9 ┆ 0 │ 657 | │ 2024-02-03 ┆ A ┆ null ┆ null │ 658 | │ 2024-02-04 ┆ A ┆ 7 ┆ 2 │ 659 | │ 2024-02-05 ┆ A ┆ 3 ┆ 1 │ 660 | │ 2024-02-06 ┆ B ┆ 2 ┆ null │ 661 | │ 2024-02-07 ┆ B ┆ 4 ┆ 0 │ 662 | │ 2024-02-08 ┆ B ┆ 5 ┆ 0 │ 663 | │ 2024-02-09 ┆ B ┆ 1 ┆ 1 │ 664 | │ 2024-02-10 ┆ B ┆ 9 ┆ 0 │ 665 | └────────────┴───────┴───────┴────────┘ 666 | 667 | """ 668 | expr = parse_into_expr(expr) 669 | return register_plugin_function( 670 | plugin_path=PLUGIN_PATH, 671 | function_name="arg_previous_greater", 672 | is_elementwise=False, 673 | args=[expr], 674 | ) 675 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.22.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "adler2" 22 | version = "2.0.1" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" 25 | 26 | [[package]] 27 | name = "ahash" 28 | version = "0.8.11" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" 31 | dependencies = [ 32 | "cfg-if", 33 | "getrandom 0.2.15", 34 | "once_cell", 35 | "version_check", 36 | "zerocopy", 37 | ] 38 | 39 | [[package]] 40 | name = "aho-corasick" 41 | version = "1.1.3" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 44 | dependencies = [ 45 | "memchr", 46 | ] 47 | 48 | [[package]] 49 | name = "allocator-api2" 50 | version = "0.2.18" 51 | source = "registry+https://github.com/rust-lang/crates.io-index" 52 | checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" 53 | 54 | [[package]] 55 | name = "android_system_properties" 56 | version = "0.1.5" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 59 | dependencies = [ 60 | "libc", 61 | ] 62 | 63 | [[package]] 64 | name = "argminmax" 65 | version = "0.6.3" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | checksum = "70f13d10a41ac8d2ec79ee34178d61e6f47a29c2edfe7ef1721c7383b0359e65" 68 | dependencies = [ 69 | "num-traits", 70 | ] 71 | 72 | [[package]] 73 | name = "array-init-cursor" 74 | version = "0.2.0" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | checksum = "bf7d0a018de4f6aa429b9d33d69edf69072b1c5b1cb8d3e4a5f7ef898fc3eb76" 77 | 78 | [[package]] 79 | name = "arrayref" 80 | version = "0.3.9" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" 83 | 84 | [[package]] 85 | name = "arrayvec" 86 | version = "0.7.6" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" 89 | 90 | [[package]] 91 | name = "async-channel" 92 | version = "2.5.0" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" 95 | dependencies = [ 96 | "concurrent-queue", 97 | "event-listener-strategy", 98 | "futures-core", 99 | "pin-project-lite", 100 | ] 101 | 102 | [[package]] 103 | name = "async-stream" 104 | version = "0.3.6" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" 107 | dependencies = [ 108 | "async-stream-impl", 109 | "futures-core", 110 | "pin-project-lite", 111 | ] 112 | 113 | [[package]] 114 | name = "async-stream-impl" 115 | version = "0.3.6" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" 118 | dependencies = [ 119 | "proc-macro2", 120 | "quote", 121 | "syn", 122 | ] 123 | 124 | [[package]] 125 | name = "async-trait" 126 | version = "0.1.83" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" 129 | dependencies = [ 130 | "proc-macro2", 131 | "quote", 132 | "syn", 133 | ] 134 | 135 | [[package]] 136 | name = "atoi_simd" 137 | version = "0.16.0" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "4790f9e8961209112beb783d85449b508673cf4a6a419c8449b210743ac4dbe9" 140 | 141 | [[package]] 142 | name = "atomic-waker" 143 | version = "1.1.2" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 146 | 147 | [[package]] 148 | name = "autocfg" 149 | version = "1.3.0" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 152 | 153 | [[package]] 154 | name = "backtrace" 155 | version = "0.3.73" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" 158 | dependencies = [ 159 | "addr2line", 160 | "cc", 161 | "cfg-if", 162 | "libc", 163 | "miniz_oxide 0.7.4", 164 | "object", 165 | "rustc-demangle", 166 | ] 167 | 168 | [[package]] 169 | name = "base64" 170 | version = "0.22.1" 171 | source = "registry+https://github.com/rust-lang/crates.io-index" 172 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 173 | 174 | [[package]] 175 | name = "bincode" 176 | version = "2.0.1" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" 179 | dependencies = [ 180 | "bincode_derive", 181 | "serde", 182 | "unty", 183 | ] 184 | 185 | [[package]] 186 | name = "bincode_derive" 187 | version = "2.0.1" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" 190 | dependencies = [ 191 | "virtue", 192 | ] 193 | 194 | [[package]] 195 | name = "bitflags" 196 | version = "2.5.0" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" 199 | dependencies = [ 200 | "serde", 201 | ] 202 | 203 | [[package]] 204 | name = "blake3" 205 | version = "1.8.2" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" 208 | dependencies = [ 209 | "arrayref", 210 | "arrayvec", 211 | "cc", 212 | "cfg-if", 213 | "constant_time_eq", 214 | ] 215 | 216 | [[package]] 217 | name = "block-buffer" 218 | version = "0.10.4" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 221 | dependencies = [ 222 | "generic-array", 223 | ] 224 | 225 | [[package]] 226 | name = "boxcar" 227 | version = "0.2.13" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "26c4925bc979b677330a8c7fe7a8c94af2dbb4a2d37b4a20a80d884400f46baa" 230 | 231 | [[package]] 232 | name = "bumpalo" 233 | version = "3.16.0" 234 | source = "registry+https://github.com/rust-lang/crates.io-index" 235 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 236 | 237 | [[package]] 238 | name = "bytemuck" 239 | version = "1.22.0" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" 242 | dependencies = [ 243 | "bytemuck_derive", 244 | ] 245 | 246 | [[package]] 247 | name = "bytemuck_derive" 248 | version = "1.7.0" 249 | source = "registry+https://github.com/rust-lang/crates.io-index" 250 | checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" 251 | dependencies = [ 252 | "proc-macro2", 253 | "quote", 254 | "syn", 255 | ] 256 | 257 | [[package]] 258 | name = "byteorder" 259 | version = "1.5.0" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 262 | 263 | [[package]] 264 | name = "bytes" 265 | version = "1.10.1" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" 268 | dependencies = [ 269 | "serde", 270 | ] 271 | 272 | [[package]] 273 | name = "castaway" 274 | version = "0.2.3" 275 | source = "registry+https://github.com/rust-lang/crates.io-index" 276 | checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5" 277 | dependencies = [ 278 | "rustversion", 279 | ] 280 | 281 | [[package]] 282 | name = "cc" 283 | version = "1.2.30" 284 | source = "registry+https://github.com/rust-lang/crates.io-index" 285 | checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" 286 | dependencies = [ 287 | "jobserver", 288 | "libc", 289 | "shlex", 290 | ] 291 | 292 | [[package]] 293 | name = "cfg-if" 294 | version = "1.0.0" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 297 | 298 | [[package]] 299 | name = "cfg_aliases" 300 | version = "0.2.1" 301 | source = "registry+https://github.com/rust-lang/crates.io-index" 302 | checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" 303 | 304 | [[package]] 305 | name = "chrono" 306 | version = "0.4.42" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" 309 | dependencies = [ 310 | "iana-time-zone", 311 | "num-traits", 312 | "pure-rust-locales", 313 | "serde", 314 | "windows-link", 315 | ] 316 | 317 | [[package]] 318 | name = "chrono-tz" 319 | version = "0.10.4" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "a6139a8597ed92cf816dfb33f5dd6cf0bb93a6adc938f11039f371bc5bcd26c3" 322 | dependencies = [ 323 | "chrono", 324 | "phf", 325 | ] 326 | 327 | [[package]] 328 | name = "comfy-table" 329 | version = "7.1.1" 330 | source = "registry+https://github.com/rust-lang/crates.io-index" 331 | checksum = "b34115915337defe99b2aff5c2ce6771e5fbc4079f4b506301f5cf394c8452f7" 332 | dependencies = [ 333 | "crossterm", 334 | "strum", 335 | "strum_macros 0.26.4", 336 | "unicode-width", 337 | ] 338 | 339 | [[package]] 340 | name = "compact_str" 341 | version = "0.9.0" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a" 344 | dependencies = [ 345 | "castaway", 346 | "cfg-if", 347 | "itoa", 348 | "rustversion", 349 | "ryu", 350 | "serde", 351 | "static_assertions", 352 | ] 353 | 354 | [[package]] 355 | name = "concurrent-queue" 356 | version = "2.5.0" 357 | source = "registry+https://github.com/rust-lang/crates.io-index" 358 | checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" 359 | dependencies = [ 360 | "crossbeam-utils", 361 | ] 362 | 363 | [[package]] 364 | name = "constant_time_eq" 365 | version = "0.3.1" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" 368 | 369 | [[package]] 370 | name = "core-foundation" 371 | version = "0.9.4" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 374 | dependencies = [ 375 | "core-foundation-sys", 376 | "libc", 377 | ] 378 | 379 | [[package]] 380 | name = "core-foundation-sys" 381 | version = "0.8.7" 382 | source = "registry+https://github.com/rust-lang/crates.io-index" 383 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 384 | 385 | [[package]] 386 | name = "cpufeatures" 387 | version = "0.2.17" 388 | source = "registry+https://github.com/rust-lang/crates.io-index" 389 | checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" 390 | dependencies = [ 391 | "libc", 392 | ] 393 | 394 | [[package]] 395 | name = "crc32fast" 396 | version = "1.5.0" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" 399 | dependencies = [ 400 | "cfg-if", 401 | ] 402 | 403 | [[package]] 404 | name = "crossbeam-channel" 405 | version = "0.5.15" 406 | source = "registry+https://github.com/rust-lang/crates.io-index" 407 | checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" 408 | dependencies = [ 409 | "crossbeam-utils", 410 | ] 411 | 412 | [[package]] 413 | name = "crossbeam-deque" 414 | version = "0.8.5" 415 | source = "registry+https://github.com/rust-lang/crates.io-index" 416 | checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" 417 | dependencies = [ 418 | "crossbeam-epoch", 419 | "crossbeam-utils", 420 | ] 421 | 422 | [[package]] 423 | name = "crossbeam-epoch" 424 | version = "0.9.18" 425 | source = "registry+https://github.com/rust-lang/crates.io-index" 426 | checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" 427 | dependencies = [ 428 | "crossbeam-utils", 429 | ] 430 | 431 | [[package]] 432 | name = "crossbeam-queue" 433 | version = "0.3.11" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" 436 | dependencies = [ 437 | "crossbeam-utils", 438 | ] 439 | 440 | [[package]] 441 | name = "crossbeam-utils" 442 | version = "0.8.20" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" 445 | 446 | [[package]] 447 | name = "crossterm" 448 | version = "0.27.0" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" 451 | dependencies = [ 452 | "bitflags", 453 | "crossterm_winapi", 454 | "libc", 455 | "parking_lot", 456 | "winapi", 457 | ] 458 | 459 | [[package]] 460 | name = "crossterm_winapi" 461 | version = "0.9.1" 462 | source = "registry+https://github.com/rust-lang/crates.io-index" 463 | checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" 464 | dependencies = [ 465 | "winapi", 466 | ] 467 | 468 | [[package]] 469 | name = "crypto-common" 470 | version = "0.1.6" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 473 | dependencies = [ 474 | "generic-array", 475 | "typenum", 476 | ] 477 | 478 | [[package]] 479 | name = "digest" 480 | version = "0.10.7" 481 | source = "registry+https://github.com/rust-lang/crates.io-index" 482 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 483 | dependencies = [ 484 | "block-buffer", 485 | "crypto-common", 486 | ] 487 | 488 | [[package]] 489 | name = "displaydoc" 490 | version = "0.2.5" 491 | source = "registry+https://github.com/rust-lang/crates.io-index" 492 | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 493 | dependencies = [ 494 | "proc-macro2", 495 | "quote", 496 | "syn", 497 | ] 498 | 499 | [[package]] 500 | name = "dyn-clone" 501 | version = "1.0.17" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" 504 | 505 | [[package]] 506 | name = "either" 507 | version = "1.15.0" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" 510 | dependencies = [ 511 | "serde", 512 | ] 513 | 514 | [[package]] 515 | name = "equivalent" 516 | version = "1.0.1" 517 | source = "registry+https://github.com/rust-lang/crates.io-index" 518 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 519 | 520 | [[package]] 521 | name = "errno" 522 | version = "0.3.13" 523 | source = "registry+https://github.com/rust-lang/crates.io-index" 524 | checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" 525 | dependencies = [ 526 | "libc", 527 | "windows-sys 0.59.0", 528 | ] 529 | 530 | [[package]] 531 | name = "ethnum" 532 | version = "1.5.0" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "b90ca2580b73ab6a1f724b76ca11ab632df820fd6040c336200d2c1df7b3c82c" 535 | 536 | [[package]] 537 | name = "event-listener" 538 | version = "5.4.0" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" 541 | dependencies = [ 542 | "concurrent-queue", 543 | "parking", 544 | "pin-project-lite", 545 | ] 546 | 547 | [[package]] 548 | name = "event-listener-strategy" 549 | version = "0.5.4" 550 | source = "registry+https://github.com/rust-lang/crates.io-index" 551 | checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" 552 | dependencies = [ 553 | "event-listener", 554 | "pin-project-lite", 555 | ] 556 | 557 | [[package]] 558 | name = "fallible-streaming-iterator" 559 | version = "0.1.9" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" 562 | 563 | [[package]] 564 | name = "fast-float2" 565 | version = "0.2.3" 566 | source = "registry+https://github.com/rust-lang/crates.io-index" 567 | checksum = "f8eb564c5c7423d25c886fb561d1e4ee69f72354d16918afa32c08811f6b6a55" 568 | 569 | [[package]] 570 | name = "flate2" 571 | version = "1.1.2" 572 | source = "registry+https://github.com/rust-lang/crates.io-index" 573 | checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" 574 | dependencies = [ 575 | "crc32fast", 576 | "miniz_oxide 0.8.9", 577 | ] 578 | 579 | [[package]] 580 | name = "float-cmp" 581 | version = "0.10.0" 582 | source = "registry+https://github.com/rust-lang/crates.io-index" 583 | checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8" 584 | dependencies = [ 585 | "num-traits", 586 | ] 587 | 588 | [[package]] 589 | name = "fnv" 590 | version = "1.0.7" 591 | source = "registry+https://github.com/rust-lang/crates.io-index" 592 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 593 | 594 | [[package]] 595 | name = "foldhash" 596 | version = "0.1.5" 597 | source = "registry+https://github.com/rust-lang/crates.io-index" 598 | checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" 599 | 600 | [[package]] 601 | name = "foldhash" 602 | version = "0.2.0" 603 | source = "registry+https://github.com/rust-lang/crates.io-index" 604 | checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" 605 | 606 | [[package]] 607 | name = "form_urlencoded" 608 | version = "1.2.1" 609 | source = "registry+https://github.com/rust-lang/crates.io-index" 610 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 611 | dependencies = [ 612 | "percent-encoding", 613 | ] 614 | 615 | [[package]] 616 | name = "fs4" 617 | version = "0.13.1" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "8640e34b88f7652208ce9e88b1a37a2ae95227d84abec377ccd3c5cfeb141ed4" 620 | dependencies = [ 621 | "rustix", 622 | "windows-sys 0.59.0", 623 | ] 624 | 625 | [[package]] 626 | name = "futures" 627 | version = "0.3.31" 628 | source = "registry+https://github.com/rust-lang/crates.io-index" 629 | checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" 630 | dependencies = [ 631 | "futures-channel", 632 | "futures-core", 633 | "futures-executor", 634 | "futures-io", 635 | "futures-sink", 636 | "futures-task", 637 | "futures-util", 638 | ] 639 | 640 | [[package]] 641 | name = "futures-channel" 642 | version = "0.3.31" 643 | source = "registry+https://github.com/rust-lang/crates.io-index" 644 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 645 | dependencies = [ 646 | "futures-core", 647 | "futures-sink", 648 | ] 649 | 650 | [[package]] 651 | name = "futures-core" 652 | version = "0.3.31" 653 | source = "registry+https://github.com/rust-lang/crates.io-index" 654 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 655 | 656 | [[package]] 657 | name = "futures-executor" 658 | version = "0.3.31" 659 | source = "registry+https://github.com/rust-lang/crates.io-index" 660 | checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" 661 | dependencies = [ 662 | "futures-core", 663 | "futures-task", 664 | "futures-util", 665 | ] 666 | 667 | [[package]] 668 | name = "futures-io" 669 | version = "0.3.31" 670 | source = "registry+https://github.com/rust-lang/crates.io-index" 671 | checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" 672 | 673 | [[package]] 674 | name = "futures-macro" 675 | version = "0.3.31" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 678 | dependencies = [ 679 | "proc-macro2", 680 | "quote", 681 | "syn", 682 | ] 683 | 684 | [[package]] 685 | name = "futures-sink" 686 | version = "0.3.31" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 689 | 690 | [[package]] 691 | name = "futures-task" 692 | version = "0.3.31" 693 | source = "registry+https://github.com/rust-lang/crates.io-index" 694 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 695 | 696 | [[package]] 697 | name = "futures-util" 698 | version = "0.3.31" 699 | source = "registry+https://github.com/rust-lang/crates.io-index" 700 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 701 | dependencies = [ 702 | "futures-channel", 703 | "futures-core", 704 | "futures-io", 705 | "futures-macro", 706 | "futures-sink", 707 | "futures-task", 708 | "memchr", 709 | "pin-project-lite", 710 | "pin-utils", 711 | "slab", 712 | ] 713 | 714 | [[package]] 715 | name = "generic-array" 716 | version = "0.14.9" 717 | source = "registry+https://github.com/rust-lang/crates.io-index" 718 | checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" 719 | dependencies = [ 720 | "typenum", 721 | "version_check", 722 | ] 723 | 724 | [[package]] 725 | name = "getrandom" 726 | version = "0.2.15" 727 | source = "registry+https://github.com/rust-lang/crates.io-index" 728 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 729 | dependencies = [ 730 | "cfg-if", 731 | "js-sys", 732 | "libc", 733 | "wasi 0.11.0+wasi-snapshot-preview1", 734 | "wasm-bindgen", 735 | ] 736 | 737 | [[package]] 738 | name = "getrandom" 739 | version = "0.3.3" 740 | source = "registry+https://github.com/rust-lang/crates.io-index" 741 | checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" 742 | dependencies = [ 743 | "cfg-if", 744 | "js-sys", 745 | "libc", 746 | "r-efi", 747 | "wasi 0.14.2+wasi-0.2.4", 748 | "wasm-bindgen", 749 | ] 750 | 751 | [[package]] 752 | name = "gimli" 753 | version = "0.29.0" 754 | source = "registry+https://github.com/rust-lang/crates.io-index" 755 | checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" 756 | 757 | [[package]] 758 | name = "glob" 759 | version = "0.3.1" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" 762 | 763 | [[package]] 764 | name = "h2" 765 | version = "0.4.11" 766 | source = "registry+https://github.com/rust-lang/crates.io-index" 767 | checksum = "17da50a276f1e01e0ba6c029e47b7100754904ee8a278f886546e98575380785" 768 | dependencies = [ 769 | "atomic-waker", 770 | "bytes", 771 | "fnv", 772 | "futures-core", 773 | "futures-sink", 774 | "http", 775 | "indexmap", 776 | "slab", 777 | "tokio", 778 | "tokio-util", 779 | "tracing", 780 | ] 781 | 782 | [[package]] 783 | name = "halfbrown" 784 | version = "0.4.0" 785 | source = "registry+https://github.com/rust-lang/crates.io-index" 786 | checksum = "0c7ed2f2edad8a14c8186b847909a41fbb9c3eafa44f88bd891114ed5019da09" 787 | dependencies = [ 788 | "hashbrown 0.16.1", 789 | "serde", 790 | ] 791 | 792 | [[package]] 793 | name = "hashbrown" 794 | version = "0.15.2" 795 | source = "registry+https://github.com/rust-lang/crates.io-index" 796 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 797 | dependencies = [ 798 | "allocator-api2", 799 | "equivalent", 800 | "foldhash 0.1.5", 801 | ] 802 | 803 | [[package]] 804 | name = "hashbrown" 805 | version = "0.16.1" 806 | source = "registry+https://github.com/rust-lang/crates.io-index" 807 | checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" 808 | dependencies = [ 809 | "allocator-api2", 810 | "equivalent", 811 | "foldhash 0.2.0", 812 | "rayon", 813 | "serde", 814 | "serde_core", 815 | ] 816 | 817 | [[package]] 818 | name = "heck" 819 | version = "0.5.0" 820 | source = "registry+https://github.com/rust-lang/crates.io-index" 821 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 822 | 823 | [[package]] 824 | name = "hex" 825 | version = "0.4.3" 826 | source = "registry+https://github.com/rust-lang/crates.io-index" 827 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 828 | 829 | [[package]] 830 | name = "home" 831 | version = "0.5.9" 832 | source = "registry+https://github.com/rust-lang/crates.io-index" 833 | checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" 834 | dependencies = [ 835 | "windows-sys 0.52.0", 836 | ] 837 | 838 | [[package]] 839 | name = "http" 840 | version = "1.3.1" 841 | source = "registry+https://github.com/rust-lang/crates.io-index" 842 | checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" 843 | dependencies = [ 844 | "bytes", 845 | "fnv", 846 | "itoa", 847 | ] 848 | 849 | [[package]] 850 | name = "http-body" 851 | version = "1.0.1" 852 | source = "registry+https://github.com/rust-lang/crates.io-index" 853 | checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 854 | dependencies = [ 855 | "bytes", 856 | "http", 857 | ] 858 | 859 | [[package]] 860 | name = "http-body-util" 861 | version = "0.1.3" 862 | source = "registry+https://github.com/rust-lang/crates.io-index" 863 | checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" 864 | dependencies = [ 865 | "bytes", 866 | "futures-core", 867 | "http", 868 | "http-body", 869 | "pin-project-lite", 870 | ] 871 | 872 | [[package]] 873 | name = "httparse" 874 | version = "1.10.1" 875 | source = "registry+https://github.com/rust-lang/crates.io-index" 876 | checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" 877 | 878 | [[package]] 879 | name = "humantime" 880 | version = "2.2.0" 881 | source = "registry+https://github.com/rust-lang/crates.io-index" 882 | checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" 883 | 884 | [[package]] 885 | name = "hyper" 886 | version = "1.6.0" 887 | source = "registry+https://github.com/rust-lang/crates.io-index" 888 | checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" 889 | dependencies = [ 890 | "bytes", 891 | "futures-channel", 892 | "futures-util", 893 | "h2", 894 | "http", 895 | "http-body", 896 | "httparse", 897 | "itoa", 898 | "pin-project-lite", 899 | "smallvec", 900 | "tokio", 901 | "want", 902 | ] 903 | 904 | [[package]] 905 | name = "hyper-rustls" 906 | version = "0.27.7" 907 | source = "registry+https://github.com/rust-lang/crates.io-index" 908 | checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" 909 | dependencies = [ 910 | "http", 911 | "hyper", 912 | "hyper-util", 913 | "rustls", 914 | "rustls-native-certs", 915 | "rustls-pki-types", 916 | "tokio", 917 | "tokio-rustls", 918 | "tower-service", 919 | ] 920 | 921 | [[package]] 922 | name = "hyper-util" 923 | version = "0.1.16" 924 | source = "registry+https://github.com/rust-lang/crates.io-index" 925 | checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" 926 | dependencies = [ 927 | "base64", 928 | "bytes", 929 | "futures-channel", 930 | "futures-core", 931 | "futures-util", 932 | "http", 933 | "http-body", 934 | "hyper", 935 | "ipnet", 936 | "libc", 937 | "percent-encoding", 938 | "pin-project-lite", 939 | "socket2 0.6.0", 940 | "tokio", 941 | "tower-service", 942 | "tracing", 943 | ] 944 | 945 | [[package]] 946 | name = "iana-time-zone" 947 | version = "0.1.60" 948 | source = "registry+https://github.com/rust-lang/crates.io-index" 949 | checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" 950 | dependencies = [ 951 | "android_system_properties", 952 | "core-foundation-sys", 953 | "iana-time-zone-haiku", 954 | "js-sys", 955 | "wasm-bindgen", 956 | "windows-core", 957 | ] 958 | 959 | [[package]] 960 | name = "iana-time-zone-haiku" 961 | version = "0.1.2" 962 | source = "registry+https://github.com/rust-lang/crates.io-index" 963 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 964 | dependencies = [ 965 | "cc", 966 | ] 967 | 968 | [[package]] 969 | name = "icu_collections" 970 | version = "2.0.0" 971 | source = "registry+https://github.com/rust-lang/crates.io-index" 972 | checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" 973 | dependencies = [ 974 | "displaydoc", 975 | "potential_utf", 976 | "yoke", 977 | "zerofrom", 978 | "zerovec", 979 | ] 980 | 981 | [[package]] 982 | name = "icu_locale_core" 983 | version = "2.0.0" 984 | source = "registry+https://github.com/rust-lang/crates.io-index" 985 | checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" 986 | dependencies = [ 987 | "displaydoc", 988 | "litemap", 989 | "tinystr", 990 | "writeable", 991 | "zerovec", 992 | ] 993 | 994 | [[package]] 995 | name = "icu_normalizer" 996 | version = "2.0.0" 997 | source = "registry+https://github.com/rust-lang/crates.io-index" 998 | checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" 999 | dependencies = [ 1000 | "displaydoc", 1001 | "icu_collections", 1002 | "icu_normalizer_data", 1003 | "icu_properties", 1004 | "icu_provider", 1005 | "smallvec", 1006 | "zerovec", 1007 | ] 1008 | 1009 | [[package]] 1010 | name = "icu_normalizer_data" 1011 | version = "2.0.0" 1012 | source = "registry+https://github.com/rust-lang/crates.io-index" 1013 | checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" 1014 | 1015 | [[package]] 1016 | name = "icu_properties" 1017 | version = "2.0.1" 1018 | source = "registry+https://github.com/rust-lang/crates.io-index" 1019 | checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" 1020 | dependencies = [ 1021 | "displaydoc", 1022 | "icu_collections", 1023 | "icu_locale_core", 1024 | "icu_properties_data", 1025 | "icu_provider", 1026 | "potential_utf", 1027 | "zerotrie", 1028 | "zerovec", 1029 | ] 1030 | 1031 | [[package]] 1032 | name = "icu_properties_data" 1033 | version = "2.0.1" 1034 | source = "registry+https://github.com/rust-lang/crates.io-index" 1035 | checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" 1036 | 1037 | [[package]] 1038 | name = "icu_provider" 1039 | version = "2.0.0" 1040 | source = "registry+https://github.com/rust-lang/crates.io-index" 1041 | checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" 1042 | dependencies = [ 1043 | "displaydoc", 1044 | "icu_locale_core", 1045 | "stable_deref_trait", 1046 | "tinystr", 1047 | "writeable", 1048 | "yoke", 1049 | "zerofrom", 1050 | "zerotrie", 1051 | "zerovec", 1052 | ] 1053 | 1054 | [[package]] 1055 | name = "idna" 1056 | version = "1.0.3" 1057 | source = "registry+https://github.com/rust-lang/crates.io-index" 1058 | checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" 1059 | dependencies = [ 1060 | "idna_adapter", 1061 | "smallvec", 1062 | "utf8_iter", 1063 | ] 1064 | 1065 | [[package]] 1066 | name = "idna_adapter" 1067 | version = "1.2.1" 1068 | source = "registry+https://github.com/rust-lang/crates.io-index" 1069 | checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" 1070 | dependencies = [ 1071 | "icu_normalizer", 1072 | "icu_properties", 1073 | ] 1074 | 1075 | [[package]] 1076 | name = "indexmap" 1077 | version = "2.12.1" 1078 | source = "registry+https://github.com/rust-lang/crates.io-index" 1079 | checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" 1080 | dependencies = [ 1081 | "equivalent", 1082 | "hashbrown 0.16.1", 1083 | "serde", 1084 | "serde_core", 1085 | ] 1086 | 1087 | [[package]] 1088 | name = "indoc" 1089 | version = "2.0.5" 1090 | source = "registry+https://github.com/rust-lang/crates.io-index" 1091 | checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" 1092 | 1093 | [[package]] 1094 | name = "io-uring" 1095 | version = "0.7.9" 1096 | source = "registry+https://github.com/rust-lang/crates.io-index" 1097 | checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4" 1098 | dependencies = [ 1099 | "bitflags", 1100 | "cfg-if", 1101 | "libc", 1102 | ] 1103 | 1104 | [[package]] 1105 | name = "ipnet" 1106 | version = "2.11.0" 1107 | source = "registry+https://github.com/rust-lang/crates.io-index" 1108 | checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" 1109 | 1110 | [[package]] 1111 | name = "iri-string" 1112 | version = "0.7.8" 1113 | source = "registry+https://github.com/rust-lang/crates.io-index" 1114 | checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" 1115 | dependencies = [ 1116 | "memchr", 1117 | "serde", 1118 | ] 1119 | 1120 | [[package]] 1121 | name = "iter-read" 1122 | version = "0.3.1" 1123 | source = "registry+https://github.com/rust-lang/crates.io-index" 1124 | checksum = "c397ca3ea05ad509c4ec451fea28b4771236a376ca1c69fd5143aae0cf8f93c4" 1125 | 1126 | [[package]] 1127 | name = "itertools" 1128 | version = "0.14.0" 1129 | source = "registry+https://github.com/rust-lang/crates.io-index" 1130 | checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" 1131 | dependencies = [ 1132 | "either", 1133 | ] 1134 | 1135 | [[package]] 1136 | name = "itoa" 1137 | version = "1.0.11" 1138 | source = "registry+https://github.com/rust-lang/crates.io-index" 1139 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 1140 | 1141 | [[package]] 1142 | name = "jobserver" 1143 | version = "0.1.31" 1144 | source = "registry+https://github.com/rust-lang/crates.io-index" 1145 | checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" 1146 | dependencies = [ 1147 | "libc", 1148 | ] 1149 | 1150 | [[package]] 1151 | name = "js-sys" 1152 | version = "0.3.77" 1153 | source = "registry+https://github.com/rust-lang/crates.io-index" 1154 | checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" 1155 | dependencies = [ 1156 | "once_cell", 1157 | "wasm-bindgen", 1158 | ] 1159 | 1160 | [[package]] 1161 | name = "libc" 1162 | version = "0.2.174" 1163 | source = "registry+https://github.com/rust-lang/crates.io-index" 1164 | checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" 1165 | 1166 | [[package]] 1167 | name = "libm" 1168 | version = "0.2.8" 1169 | source = "registry+https://github.com/rust-lang/crates.io-index" 1170 | checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" 1171 | 1172 | [[package]] 1173 | name = "linux-raw-sys" 1174 | version = "0.9.4" 1175 | source = "registry+https://github.com/rust-lang/crates.io-index" 1176 | checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" 1177 | 1178 | [[package]] 1179 | name = "litemap" 1180 | version = "0.8.0" 1181 | source = "registry+https://github.com/rust-lang/crates.io-index" 1182 | checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" 1183 | 1184 | [[package]] 1185 | name = "lock_api" 1186 | version = "0.4.12" 1187 | source = "registry+https://github.com/rust-lang/crates.io-index" 1188 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 1189 | dependencies = [ 1190 | "autocfg", 1191 | "scopeguard", 1192 | ] 1193 | 1194 | [[package]] 1195 | name = "log" 1196 | version = "0.4.21" 1197 | source = "registry+https://github.com/rust-lang/crates.io-index" 1198 | checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" 1199 | 1200 | [[package]] 1201 | name = "lru-slab" 1202 | version = "0.1.2" 1203 | source = "registry+https://github.com/rust-lang/crates.io-index" 1204 | checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" 1205 | 1206 | [[package]] 1207 | name = "lz4" 1208 | version = "1.25.0" 1209 | source = "registry+https://github.com/rust-lang/crates.io-index" 1210 | checksum = "d6eab492fe7f8651add23237ea56dbf11b3c4ff762ab83d40a47f11433421f91" 1211 | dependencies = [ 1212 | "libc", 1213 | "lz4-sys", 1214 | ] 1215 | 1216 | [[package]] 1217 | name = "lz4-sys" 1218 | version = "1.9.5" 1219 | source = "registry+https://github.com/rust-lang/crates.io-index" 1220 | checksum = "e9764018d143cc854c9f17f0b907de70f14393b1f502da6375dce70f00514eb3" 1221 | dependencies = [ 1222 | "cc", 1223 | "libc", 1224 | ] 1225 | 1226 | [[package]] 1227 | name = "memchr" 1228 | version = "2.7.4" 1229 | source = "registry+https://github.com/rust-lang/crates.io-index" 1230 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 1231 | 1232 | [[package]] 1233 | name = "memmap2" 1234 | version = "0.9.5" 1235 | source = "registry+https://github.com/rust-lang/crates.io-index" 1236 | checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" 1237 | dependencies = [ 1238 | "libc", 1239 | ] 1240 | 1241 | [[package]] 1242 | name = "memoffset" 1243 | version = "0.9.1" 1244 | source = "registry+https://github.com/rust-lang/crates.io-index" 1245 | checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" 1246 | dependencies = [ 1247 | "autocfg", 1248 | ] 1249 | 1250 | [[package]] 1251 | name = "miniz_oxide" 1252 | version = "0.7.4" 1253 | source = "registry+https://github.com/rust-lang/crates.io-index" 1254 | checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" 1255 | dependencies = [ 1256 | "adler", 1257 | ] 1258 | 1259 | [[package]] 1260 | name = "miniz_oxide" 1261 | version = "0.8.9" 1262 | source = "registry+https://github.com/rust-lang/crates.io-index" 1263 | checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" 1264 | dependencies = [ 1265 | "adler2", 1266 | ] 1267 | 1268 | [[package]] 1269 | name = "mio" 1270 | version = "1.0.3" 1271 | source = "registry+https://github.com/rust-lang/crates.io-index" 1272 | checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" 1273 | dependencies = [ 1274 | "libc", 1275 | "wasi 0.11.0+wasi-snapshot-preview1", 1276 | "windows-sys 0.52.0", 1277 | ] 1278 | 1279 | [[package]] 1280 | name = "now" 1281 | version = "0.1.3" 1282 | source = "registry+https://github.com/rust-lang/crates.io-index" 1283 | checksum = "6d89e9874397a1f0a52fc1f197a8effd9735223cb2390e9dcc83ac6cd02923d0" 1284 | dependencies = [ 1285 | "chrono", 1286 | ] 1287 | 1288 | [[package]] 1289 | name = "num-bigint" 1290 | version = "0.4.5" 1291 | source = "registry+https://github.com/rust-lang/crates.io-index" 1292 | checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" 1293 | dependencies = [ 1294 | "num-integer", 1295 | "num-traits", 1296 | ] 1297 | 1298 | [[package]] 1299 | name = "num-integer" 1300 | version = "0.1.46" 1301 | source = "registry+https://github.com/rust-lang/crates.io-index" 1302 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 1303 | dependencies = [ 1304 | "num-traits", 1305 | ] 1306 | 1307 | [[package]] 1308 | name = "num-traits" 1309 | version = "0.2.19" 1310 | source = "registry+https://github.com/rust-lang/crates.io-index" 1311 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 1312 | dependencies = [ 1313 | "autocfg", 1314 | "libm", 1315 | ] 1316 | 1317 | [[package]] 1318 | name = "object" 1319 | version = "0.36.5" 1320 | source = "registry+https://github.com/rust-lang/crates.io-index" 1321 | checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" 1322 | dependencies = [ 1323 | "memchr", 1324 | ] 1325 | 1326 | [[package]] 1327 | name = "object_store" 1328 | version = "0.12.3" 1329 | source = "registry+https://github.com/rust-lang/crates.io-index" 1330 | checksum = "efc4f07659e11cd45a341cd24d71e683e3be65d9ff1f8150061678fe60437496" 1331 | dependencies = [ 1332 | "async-trait", 1333 | "base64", 1334 | "bytes", 1335 | "chrono", 1336 | "form_urlencoded", 1337 | "futures", 1338 | "http", 1339 | "http-body-util", 1340 | "humantime", 1341 | "hyper", 1342 | "itertools", 1343 | "parking_lot", 1344 | "percent-encoding", 1345 | "quick-xml", 1346 | "rand", 1347 | "reqwest", 1348 | "ring", 1349 | "serde", 1350 | "serde_json", 1351 | "serde_urlencoded", 1352 | "thiserror 2.0.5", 1353 | "tokio", 1354 | "tracing", 1355 | "url", 1356 | "walkdir", 1357 | "wasm-bindgen-futures", 1358 | "web-time", 1359 | ] 1360 | 1361 | [[package]] 1362 | name = "once_cell" 1363 | version = "1.21.3" 1364 | source = "registry+https://github.com/rust-lang/crates.io-index" 1365 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 1366 | 1367 | [[package]] 1368 | name = "openssl-probe" 1369 | version = "0.1.6" 1370 | source = "registry+https://github.com/rust-lang/crates.io-index" 1371 | checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" 1372 | 1373 | [[package]] 1374 | name = "parking" 1375 | version = "2.2.1" 1376 | source = "registry+https://github.com/rust-lang/crates.io-index" 1377 | checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" 1378 | 1379 | [[package]] 1380 | name = "parking_lot" 1381 | version = "0.12.3" 1382 | source = "registry+https://github.com/rust-lang/crates.io-index" 1383 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 1384 | dependencies = [ 1385 | "lock_api", 1386 | "parking_lot_core", 1387 | ] 1388 | 1389 | [[package]] 1390 | name = "parking_lot_core" 1391 | version = "0.9.10" 1392 | source = "registry+https://github.com/rust-lang/crates.io-index" 1393 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 1394 | dependencies = [ 1395 | "cfg-if", 1396 | "libc", 1397 | "redox_syscall", 1398 | "smallvec", 1399 | "windows-targets", 1400 | ] 1401 | 1402 | [[package]] 1403 | name = "paste" 1404 | version = "1.0.15" 1405 | source = "registry+https://github.com/rust-lang/crates.io-index" 1406 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 1407 | 1408 | [[package]] 1409 | name = "percent-encoding" 1410 | version = "2.3.1" 1411 | source = "registry+https://github.com/rust-lang/crates.io-index" 1412 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 1413 | 1414 | [[package]] 1415 | name = "phf" 1416 | version = "0.12.1" 1417 | source = "registry+https://github.com/rust-lang/crates.io-index" 1418 | checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7" 1419 | dependencies = [ 1420 | "phf_shared", 1421 | ] 1422 | 1423 | [[package]] 1424 | name = "phf_shared" 1425 | version = "0.12.1" 1426 | source = "registry+https://github.com/rust-lang/crates.io-index" 1427 | checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981" 1428 | dependencies = [ 1429 | "siphasher", 1430 | ] 1431 | 1432 | [[package]] 1433 | name = "pin-project-lite" 1434 | version = "0.2.15" 1435 | source = "registry+https://github.com/rust-lang/crates.io-index" 1436 | checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" 1437 | 1438 | [[package]] 1439 | name = "pin-utils" 1440 | version = "0.1.0" 1441 | source = "registry+https://github.com/rust-lang/crates.io-index" 1442 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1443 | 1444 | [[package]] 1445 | name = "pkg-config" 1446 | version = "0.3.30" 1447 | source = "registry+https://github.com/rust-lang/crates.io-index" 1448 | checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" 1449 | 1450 | [[package]] 1451 | name = "planus" 1452 | version = "1.1.1" 1453 | source = "registry+https://github.com/rust-lang/crates.io-index" 1454 | checksum = "3daf8e3d4b712abe1d690838f6e29fb76b76ea19589c4afa39ec30e12f62af71" 1455 | dependencies = [ 1456 | "array-init-cursor", 1457 | "hashbrown 0.15.2", 1458 | ] 1459 | 1460 | [[package]] 1461 | name = "polars" 1462 | version = "0.52.0" 1463 | source = "registry+https://github.com/rust-lang/crates.io-index" 1464 | checksum = "6bc9ea901050c1bb8747ee411bc7fbb390f3b399931e7484719512965132a248" 1465 | dependencies = [ 1466 | "getrandom 0.2.15", 1467 | "getrandom 0.3.3", 1468 | "polars-arrow", 1469 | "polars-compute", 1470 | "polars-core", 1471 | "polars-error", 1472 | "polars-io", 1473 | "polars-lazy", 1474 | "polars-ops", 1475 | "polars-parquet", 1476 | "polars-plan", 1477 | "polars-sql", 1478 | "polars-time", 1479 | "polars-utils", 1480 | "version_check", 1481 | ] 1482 | 1483 | [[package]] 1484 | name = "polars-arrow" 1485 | version = "0.52.0" 1486 | source = "registry+https://github.com/rust-lang/crates.io-index" 1487 | checksum = "33d3fe43f8702cf7899ff3d516c2e5f7dc84ee6f6a3007e1a831a0ff87940704" 1488 | dependencies = [ 1489 | "atoi_simd", 1490 | "bitflags", 1491 | "bytemuck", 1492 | "chrono", 1493 | "chrono-tz", 1494 | "dyn-clone", 1495 | "either", 1496 | "ethnum", 1497 | "getrandom 0.2.15", 1498 | "getrandom 0.3.3", 1499 | "hashbrown 0.16.1", 1500 | "itoa", 1501 | "lz4", 1502 | "num-traits", 1503 | "polars-arrow-format", 1504 | "polars-error", 1505 | "polars-schema", 1506 | "polars-utils", 1507 | "serde", 1508 | "simdutf8", 1509 | "streaming-iterator", 1510 | "strum_macros 0.27.2", 1511 | "version_check", 1512 | "zstd", 1513 | ] 1514 | 1515 | [[package]] 1516 | name = "polars-arrow-format" 1517 | version = "0.2.0" 1518 | source = "registry+https://github.com/rust-lang/crates.io-index" 1519 | checksum = "863c04c514be005eced7db7053e20d49f7e7a58048a282fa52dfea1fd5434e78" 1520 | dependencies = [ 1521 | "planus", 1522 | "serde", 1523 | ] 1524 | 1525 | [[package]] 1526 | name = "polars-compute" 1527 | version = "0.52.0" 1528 | source = "registry+https://github.com/rust-lang/crates.io-index" 1529 | checksum = "d29cc7497378dee3a002f117e0b4e16b7cbe6c8ed3da16a0229c89294af7c3bf" 1530 | dependencies = [ 1531 | "atoi_simd", 1532 | "bytemuck", 1533 | "chrono", 1534 | "either", 1535 | "fast-float2", 1536 | "hashbrown 0.16.1", 1537 | "itoa", 1538 | "num-traits", 1539 | "polars-arrow", 1540 | "polars-error", 1541 | "polars-utils", 1542 | "rand", 1543 | "ryu", 1544 | "serde", 1545 | "strength_reduce", 1546 | "strum_macros 0.27.2", 1547 | "version_check", 1548 | ] 1549 | 1550 | [[package]] 1551 | name = "polars-core" 1552 | version = "0.52.0" 1553 | source = "registry+https://github.com/rust-lang/crates.io-index" 1554 | checksum = "48409b7440cb1a4aa84953fe3a4189dfbfb300a3298266a92a37363476641e40" 1555 | dependencies = [ 1556 | "bitflags", 1557 | "boxcar", 1558 | "bytemuck", 1559 | "chrono", 1560 | "chrono-tz", 1561 | "comfy-table", 1562 | "either", 1563 | "hashbrown 0.16.1", 1564 | "indexmap", 1565 | "itoa", 1566 | "num-traits", 1567 | "polars-arrow", 1568 | "polars-compute", 1569 | "polars-dtype", 1570 | "polars-error", 1571 | "polars-row", 1572 | "polars-schema", 1573 | "polars-utils", 1574 | "rand", 1575 | "rand_distr", 1576 | "rayon", 1577 | "regex", 1578 | "serde", 1579 | "serde_json", 1580 | "strum_macros 0.27.2", 1581 | "uuid", 1582 | "version_check", 1583 | "xxhash-rust", 1584 | ] 1585 | 1586 | [[package]] 1587 | name = "polars-dtype" 1588 | version = "0.52.0" 1589 | source = "registry+https://github.com/rust-lang/crates.io-index" 1590 | checksum = "7007e9e8b7b657cbd339b65246af7e87f5756ee9a860119b9424ddffd2aaf133" 1591 | dependencies = [ 1592 | "boxcar", 1593 | "hashbrown 0.16.1", 1594 | "polars-arrow", 1595 | "polars-error", 1596 | "polars-utils", 1597 | "serde", 1598 | "uuid", 1599 | ] 1600 | 1601 | [[package]] 1602 | name = "polars-error" 1603 | version = "0.52.0" 1604 | source = "registry+https://github.com/rust-lang/crates.io-index" 1605 | checksum = "f9a6be22566c89f6405f553bfdb7c8a6cb20ec51b35f3172de9a25fa3e252d85" 1606 | dependencies = [ 1607 | "object_store", 1608 | "parking_lot", 1609 | "polars-arrow-format", 1610 | "pyo3", 1611 | "regex", 1612 | "signal-hook", 1613 | "simdutf8", 1614 | ] 1615 | 1616 | [[package]] 1617 | name = "polars-expr" 1618 | version = "0.52.0" 1619 | source = "registry+https://github.com/rust-lang/crates.io-index" 1620 | checksum = "6199a50d3e1afd0674fb009e340cbfb0010682b2387187a36328c00f3f2ca87b" 1621 | dependencies = [ 1622 | "bitflags", 1623 | "hashbrown 0.16.1", 1624 | "num-traits", 1625 | "polars-arrow", 1626 | "polars-compute", 1627 | "polars-core", 1628 | "polars-io", 1629 | "polars-ops", 1630 | "polars-plan", 1631 | "polars-row", 1632 | "polars-time", 1633 | "polars-utils", 1634 | "rand", 1635 | "rayon", 1636 | "recursive", 1637 | "regex", 1638 | "version_check", 1639 | ] 1640 | 1641 | [[package]] 1642 | name = "polars-ffi" 1643 | version = "0.52.0" 1644 | source = "registry+https://github.com/rust-lang/crates.io-index" 1645 | checksum = "e57ae94d00719556ce242d265f77720287d0c02b78e204aaeee8885db59c7a58" 1646 | dependencies = [ 1647 | "polars-arrow", 1648 | "polars-core", 1649 | ] 1650 | 1651 | [[package]] 1652 | name = "polars-io" 1653 | version = "0.52.0" 1654 | source = "registry+https://github.com/rust-lang/crates.io-index" 1655 | checksum = "be3714acdff87170141880a07f5d9233490d3bd5531c41898f6969d440feee11" 1656 | dependencies = [ 1657 | "async-trait", 1658 | "atoi_simd", 1659 | "blake3", 1660 | "bytes", 1661 | "chrono", 1662 | "chrono-tz", 1663 | "fast-float2", 1664 | "fs4", 1665 | "futures", 1666 | "glob", 1667 | "hashbrown 0.16.1", 1668 | "home", 1669 | "itoa", 1670 | "memchr", 1671 | "memmap2", 1672 | "num-traits", 1673 | "object_store", 1674 | "percent-encoding", 1675 | "polars-arrow", 1676 | "polars-compute", 1677 | "polars-core", 1678 | "polars-error", 1679 | "polars-json", 1680 | "polars-parquet", 1681 | "polars-schema", 1682 | "polars-time", 1683 | "polars-utils", 1684 | "rayon", 1685 | "regex", 1686 | "reqwest", 1687 | "ryu", 1688 | "serde", 1689 | "serde_json", 1690 | "simdutf8", 1691 | "tokio", 1692 | ] 1693 | 1694 | [[package]] 1695 | name = "polars-json" 1696 | version = "0.52.0" 1697 | source = "registry+https://github.com/rust-lang/crates.io-index" 1698 | checksum = "3dd2126daebf58da564fc5840cd55eb8eb2479d24dfced0a1aea2178a9b33b12" 1699 | dependencies = [ 1700 | "chrono", 1701 | "chrono-tz", 1702 | "fallible-streaming-iterator", 1703 | "hashbrown 0.16.1", 1704 | "indexmap", 1705 | "itoa", 1706 | "num-traits", 1707 | "polars-arrow", 1708 | "polars-compute", 1709 | "polars-error", 1710 | "polars-utils", 1711 | "ryu", 1712 | "simd-json", 1713 | "streaming-iterator", 1714 | ] 1715 | 1716 | [[package]] 1717 | name = "polars-lazy" 1718 | version = "0.52.0" 1719 | source = "registry+https://github.com/rust-lang/crates.io-index" 1720 | checksum = "ea136c360d03aafe56e0233495e30044ce43639b8b0360a4a38e840233f048a1" 1721 | dependencies = [ 1722 | "bitflags", 1723 | "chrono", 1724 | "either", 1725 | "memchr", 1726 | "polars-arrow", 1727 | "polars-compute", 1728 | "polars-core", 1729 | "polars-expr", 1730 | "polars-io", 1731 | "polars-mem-engine", 1732 | "polars-ops", 1733 | "polars-plan", 1734 | "polars-stream", 1735 | "polars-time", 1736 | "polars-utils", 1737 | "rayon", 1738 | "version_check", 1739 | ] 1740 | 1741 | [[package]] 1742 | name = "polars-mem-engine" 1743 | version = "0.52.0" 1744 | source = "registry+https://github.com/rust-lang/crates.io-index" 1745 | checksum = "0f6e455ceb6e5aee7ed7d5c8944104e66992173e03a9c42f9670226318672249" 1746 | dependencies = [ 1747 | "memmap2", 1748 | "polars-arrow", 1749 | "polars-core", 1750 | "polars-error", 1751 | "polars-expr", 1752 | "polars-io", 1753 | "polars-ops", 1754 | "polars-plan", 1755 | "polars-time", 1756 | "polars-utils", 1757 | "rayon", 1758 | "recursive", 1759 | ] 1760 | 1761 | [[package]] 1762 | name = "polars-ops" 1763 | version = "0.52.0" 1764 | source = "registry+https://github.com/rust-lang/crates.io-index" 1765 | checksum = "7b59c80a019ef0e6f09b4416d2647076a52839305c9eb11919e8298ec667f853" 1766 | dependencies = [ 1767 | "argminmax", 1768 | "base64", 1769 | "bytemuck", 1770 | "chrono", 1771 | "chrono-tz", 1772 | "either", 1773 | "hashbrown 0.16.1", 1774 | "hex", 1775 | "indexmap", 1776 | "libm", 1777 | "memchr", 1778 | "num-traits", 1779 | "polars-arrow", 1780 | "polars-compute", 1781 | "polars-core", 1782 | "polars-error", 1783 | "polars-schema", 1784 | "polars-utils", 1785 | "rayon", 1786 | "regex", 1787 | "regex-syntax", 1788 | "serde", 1789 | "strum_macros 0.27.2", 1790 | "unicode-normalization", 1791 | "unicode-reverse", 1792 | "version_check", 1793 | ] 1794 | 1795 | [[package]] 1796 | name = "polars-parquet" 1797 | version = "0.52.0" 1798 | source = "registry+https://github.com/rust-lang/crates.io-index" 1799 | checksum = "93c2439d127c59e6bfc9d698419bdb45210068a6f501d44e6096429ad72c2eaa" 1800 | dependencies = [ 1801 | "async-stream", 1802 | "base64", 1803 | "bytemuck", 1804 | "ethnum", 1805 | "futures", 1806 | "hashbrown 0.16.1", 1807 | "num-traits", 1808 | "polars-arrow", 1809 | "polars-compute", 1810 | "polars-error", 1811 | "polars-parquet-format", 1812 | "polars-utils", 1813 | "serde", 1814 | "simdutf8", 1815 | "streaming-decompression", 1816 | ] 1817 | 1818 | [[package]] 1819 | name = "polars-parquet-format" 1820 | version = "0.1.0" 1821 | source = "registry+https://github.com/rust-lang/crates.io-index" 1822 | checksum = "c025243dcfe8dbc57e94d9f82eb3bef10b565ab180d5b99bed87fd8aea319ce1" 1823 | dependencies = [ 1824 | "async-trait", 1825 | "futures", 1826 | ] 1827 | 1828 | [[package]] 1829 | name = "polars-plan" 1830 | version = "0.52.0" 1831 | source = "registry+https://github.com/rust-lang/crates.io-index" 1832 | checksum = "65b4619f5c7e9b91f18611c9ed82ebeee4b10052160825c1316ecf4dbd4d97e6" 1833 | dependencies = [ 1834 | "bitflags", 1835 | "bytemuck", 1836 | "bytes", 1837 | "chrono", 1838 | "chrono-tz", 1839 | "either", 1840 | "hashbrown 0.16.1", 1841 | "memmap2", 1842 | "num-traits", 1843 | "percent-encoding", 1844 | "polars-arrow", 1845 | "polars-compute", 1846 | "polars-core", 1847 | "polars-error", 1848 | "polars-ffi", 1849 | "polars-io", 1850 | "polars-ops", 1851 | "polars-time", 1852 | "polars-utils", 1853 | "pyo3", 1854 | "rayon", 1855 | "recursive", 1856 | "regex", 1857 | "serde", 1858 | "sha2", 1859 | "slotmap", 1860 | "strum_macros 0.27.2", 1861 | "version_check", 1862 | ] 1863 | 1864 | [[package]] 1865 | name = "polars-row" 1866 | version = "0.52.0" 1867 | source = "registry+https://github.com/rust-lang/crates.io-index" 1868 | checksum = "a18d232f25b83032e280a279a1f40beb8a6f8fc43907b13dc07b1c56f3b11eea" 1869 | dependencies = [ 1870 | "bitflags", 1871 | "bytemuck", 1872 | "polars-arrow", 1873 | "polars-compute", 1874 | "polars-dtype", 1875 | "polars-error", 1876 | "polars-utils", 1877 | ] 1878 | 1879 | [[package]] 1880 | name = "polars-schema" 1881 | version = "0.52.0" 1882 | source = "registry+https://github.com/rust-lang/crates.io-index" 1883 | checksum = "f73e21d429ae1c23f442b0220ccfe773a9734a44e997b5062a741842909d9441" 1884 | dependencies = [ 1885 | "indexmap", 1886 | "polars-error", 1887 | "polars-utils", 1888 | "serde", 1889 | "version_check", 1890 | ] 1891 | 1892 | [[package]] 1893 | name = "polars-sql" 1894 | version = "0.52.0" 1895 | source = "registry+https://github.com/rust-lang/crates.io-index" 1896 | checksum = "3e67ac1cbb0c972a57af3be12f19aa9803898863fe95c33cdd39df05f5738a75" 1897 | dependencies = [ 1898 | "bitflags", 1899 | "hex", 1900 | "polars-core", 1901 | "polars-error", 1902 | "polars-lazy", 1903 | "polars-ops", 1904 | "polars-plan", 1905 | "polars-time", 1906 | "polars-utils", 1907 | "rand", 1908 | "regex", 1909 | "serde", 1910 | "sqlparser", 1911 | ] 1912 | 1913 | [[package]] 1914 | name = "polars-stream" 1915 | version = "0.52.0" 1916 | source = "registry+https://github.com/rust-lang/crates.io-index" 1917 | checksum = "2ff19612074640a9d65e5928b7223db76ffee63e55b276f1e466d06719eb7362" 1918 | dependencies = [ 1919 | "async-channel", 1920 | "async-trait", 1921 | "atomic-waker", 1922 | "bitflags", 1923 | "chrono-tz", 1924 | "crossbeam-channel", 1925 | "crossbeam-deque", 1926 | "crossbeam-queue", 1927 | "crossbeam-utils", 1928 | "futures", 1929 | "memmap2", 1930 | "parking_lot", 1931 | "percent-encoding", 1932 | "pin-project-lite", 1933 | "polars-arrow", 1934 | "polars-compute", 1935 | "polars-core", 1936 | "polars-error", 1937 | "polars-expr", 1938 | "polars-io", 1939 | "polars-mem-engine", 1940 | "polars-ops", 1941 | "polars-parquet", 1942 | "polars-plan", 1943 | "polars-time", 1944 | "polars-utils", 1945 | "rand", 1946 | "rayon", 1947 | "recursive", 1948 | "slotmap", 1949 | "tokio", 1950 | "version_check", 1951 | ] 1952 | 1953 | [[package]] 1954 | name = "polars-time" 1955 | version = "0.52.0" 1956 | source = "registry+https://github.com/rust-lang/crates.io-index" 1957 | checksum = "ddce7a9f81d5f47d981bcee4a8db004f9596bb51f0f4d9d93667a1a00d88166c" 1958 | dependencies = [ 1959 | "atoi_simd", 1960 | "bytemuck", 1961 | "chrono", 1962 | "chrono-tz", 1963 | "now", 1964 | "num-traits", 1965 | "polars-arrow", 1966 | "polars-compute", 1967 | "polars-core", 1968 | "polars-error", 1969 | "polars-ops", 1970 | "polars-utils", 1971 | "rayon", 1972 | "regex", 1973 | "serde", 1974 | "strum_macros 0.27.2", 1975 | ] 1976 | 1977 | [[package]] 1978 | name = "polars-utils" 1979 | version = "0.52.0" 1980 | source = "registry+https://github.com/rust-lang/crates.io-index" 1981 | checksum = "667c1bc2d2313f934d711f6e3b58d8d9f80351d14ea60af936a26b7dfb06e309" 1982 | dependencies = [ 1983 | "bincode", 1984 | "bytemuck", 1985 | "bytes", 1986 | "compact_str", 1987 | "either", 1988 | "flate2", 1989 | "foldhash 0.2.0", 1990 | "hashbrown 0.16.1", 1991 | "indexmap", 1992 | "libc", 1993 | "memmap2", 1994 | "num-traits", 1995 | "polars-error", 1996 | "pyo3", 1997 | "rand", 1998 | "raw-cpuid", 1999 | "rayon", 2000 | "regex", 2001 | "rmp-serde", 2002 | "serde", 2003 | "serde_json", 2004 | "serde_stacker", 2005 | "slotmap", 2006 | "stacker", 2007 | "uuid", 2008 | "version_check", 2009 | ] 2010 | 2011 | [[package]] 2012 | name = "polars_xdt" 2013 | version = "0.17.1" 2014 | dependencies = [ 2015 | "chrono", 2016 | "chrono-tz", 2017 | "polars", 2018 | "polars-arrow", 2019 | "polars-ops", 2020 | "pyo3", 2021 | "pyo3-polars", 2022 | "serde", 2023 | ] 2024 | 2025 | [[package]] 2026 | name = "portable-atomic" 2027 | version = "1.6.0" 2028 | source = "registry+https://github.com/rust-lang/crates.io-index" 2029 | checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" 2030 | 2031 | [[package]] 2032 | name = "potential_utf" 2033 | version = "0.1.2" 2034 | source = "registry+https://github.com/rust-lang/crates.io-index" 2035 | checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" 2036 | dependencies = [ 2037 | "zerovec", 2038 | ] 2039 | 2040 | [[package]] 2041 | name = "ppv-lite86" 2042 | version = "0.2.17" 2043 | source = "registry+https://github.com/rust-lang/crates.io-index" 2044 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 2045 | 2046 | [[package]] 2047 | name = "proc-macro2" 2048 | version = "1.0.92" 2049 | source = "registry+https://github.com/rust-lang/crates.io-index" 2050 | checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" 2051 | dependencies = [ 2052 | "unicode-ident", 2053 | ] 2054 | 2055 | [[package]] 2056 | name = "psm" 2057 | version = "0.1.21" 2058 | source = "registry+https://github.com/rust-lang/crates.io-index" 2059 | checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" 2060 | dependencies = [ 2061 | "cc", 2062 | ] 2063 | 2064 | [[package]] 2065 | name = "pure-rust-locales" 2066 | version = "0.8.1" 2067 | source = "registry+https://github.com/rust-lang/crates.io-index" 2068 | checksum = "1190fd18ae6ce9e137184f207593877e70f39b015040156b1e05081cdfe3733a" 2069 | 2070 | [[package]] 2071 | name = "pyo3" 2072 | version = "0.26.0" 2073 | source = "registry+https://github.com/rust-lang/crates.io-index" 2074 | checksum = "7ba0117f4212101ee6544044dae45abe1083d30ce7b29c4b5cbdfa2354e07383" 2075 | dependencies = [ 2076 | "indoc", 2077 | "libc", 2078 | "memoffset", 2079 | "once_cell", 2080 | "portable-atomic", 2081 | "pyo3-build-config", 2082 | "pyo3-ffi", 2083 | "pyo3-macros", 2084 | "unindent", 2085 | ] 2086 | 2087 | [[package]] 2088 | name = "pyo3-build-config" 2089 | version = "0.26.0" 2090 | source = "registry+https://github.com/rust-lang/crates.io-index" 2091 | checksum = "4fc6ddaf24947d12a9aa31ac65431fb1b851b8f4365426e182901eabfb87df5f" 2092 | dependencies = [ 2093 | "target-lexicon", 2094 | ] 2095 | 2096 | [[package]] 2097 | name = "pyo3-ffi" 2098 | version = "0.26.0" 2099 | source = "registry+https://github.com/rust-lang/crates.io-index" 2100 | checksum = "025474d3928738efb38ac36d4744a74a400c901c7596199e20e45d98eb194105" 2101 | dependencies = [ 2102 | "libc", 2103 | "pyo3-build-config", 2104 | ] 2105 | 2106 | [[package]] 2107 | name = "pyo3-macros" 2108 | version = "0.26.0" 2109 | source = "registry+https://github.com/rust-lang/crates.io-index" 2110 | checksum = "2e64eb489f22fe1c95911b77c44cc41e7c19f3082fc81cce90f657cdc42ffded" 2111 | dependencies = [ 2112 | "proc-macro2", 2113 | "pyo3-macros-backend", 2114 | "quote", 2115 | "syn", 2116 | ] 2117 | 2118 | [[package]] 2119 | name = "pyo3-macros-backend" 2120 | version = "0.26.0" 2121 | source = "registry+https://github.com/rust-lang/crates.io-index" 2122 | checksum = "100246c0ecf400b475341b8455a9213344569af29a3c841d29270e53102e0fcf" 2123 | dependencies = [ 2124 | "heck", 2125 | "proc-macro2", 2126 | "pyo3-build-config", 2127 | "quote", 2128 | "syn", 2129 | ] 2130 | 2131 | [[package]] 2132 | name = "pyo3-polars" 2133 | version = "0.25.0" 2134 | source = "registry+https://github.com/rust-lang/crates.io-index" 2135 | checksum = "94a1e9d697dd76f39b269a5c2f2904469092c0ef6452f47caaf20879891a6a62" 2136 | dependencies = [ 2137 | "libc", 2138 | "once_cell", 2139 | "polars", 2140 | "polars-arrow", 2141 | "polars-core", 2142 | "polars-error", 2143 | "polars-ffi", 2144 | "polars-plan", 2145 | "pyo3", 2146 | "pyo3-polars-derive", 2147 | "serde", 2148 | "serde-pickle", 2149 | "thiserror 1.0.61", 2150 | ] 2151 | 2152 | [[package]] 2153 | name = "pyo3-polars-derive" 2154 | version = "0.19.0" 2155 | source = "registry+https://github.com/rust-lang/crates.io-index" 2156 | checksum = "1f5ac697f68e98220c506a933d83398a2687d279de42713b1a0b8e0b4b88cead" 2157 | dependencies = [ 2158 | "polars-arrow", 2159 | "polars-core", 2160 | "polars-ffi", 2161 | "polars-plan", 2162 | "proc-macro2", 2163 | "quote", 2164 | "syn", 2165 | ] 2166 | 2167 | [[package]] 2168 | name = "quick-xml" 2169 | version = "0.38.0" 2170 | source = "registry+https://github.com/rust-lang/crates.io-index" 2171 | checksum = "8927b0664f5c5a98265138b7e3f90aa19a6b21353182469ace36d4ac527b7b1b" 2172 | dependencies = [ 2173 | "memchr", 2174 | "serde", 2175 | ] 2176 | 2177 | [[package]] 2178 | name = "quinn" 2179 | version = "0.11.8" 2180 | source = "registry+https://github.com/rust-lang/crates.io-index" 2181 | checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" 2182 | dependencies = [ 2183 | "bytes", 2184 | "cfg_aliases", 2185 | "pin-project-lite", 2186 | "quinn-proto", 2187 | "quinn-udp", 2188 | "rustc-hash", 2189 | "rustls", 2190 | "socket2 0.5.8", 2191 | "thiserror 2.0.5", 2192 | "tokio", 2193 | "tracing", 2194 | "web-time", 2195 | ] 2196 | 2197 | [[package]] 2198 | name = "quinn-proto" 2199 | version = "0.11.12" 2200 | source = "registry+https://github.com/rust-lang/crates.io-index" 2201 | checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" 2202 | dependencies = [ 2203 | "bytes", 2204 | "getrandom 0.3.3", 2205 | "lru-slab", 2206 | "rand", 2207 | "ring", 2208 | "rustc-hash", 2209 | "rustls", 2210 | "rustls-pki-types", 2211 | "slab", 2212 | "thiserror 2.0.5", 2213 | "tinyvec", 2214 | "tracing", 2215 | "web-time", 2216 | ] 2217 | 2218 | [[package]] 2219 | name = "quinn-udp" 2220 | version = "0.5.13" 2221 | source = "registry+https://github.com/rust-lang/crates.io-index" 2222 | checksum = "fcebb1209ee276352ef14ff8732e24cc2b02bbac986cd74a4c81bcb2f9881970" 2223 | dependencies = [ 2224 | "cfg_aliases", 2225 | "libc", 2226 | "once_cell", 2227 | "socket2 0.5.8", 2228 | "tracing", 2229 | "windows-sys 0.59.0", 2230 | ] 2231 | 2232 | [[package]] 2233 | name = "quote" 2234 | version = "1.0.36" 2235 | source = "registry+https://github.com/rust-lang/crates.io-index" 2236 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 2237 | dependencies = [ 2238 | "proc-macro2", 2239 | ] 2240 | 2241 | [[package]] 2242 | name = "r-efi" 2243 | version = "5.3.0" 2244 | source = "registry+https://github.com/rust-lang/crates.io-index" 2245 | checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" 2246 | 2247 | [[package]] 2248 | name = "rand" 2249 | version = "0.9.2" 2250 | source = "registry+https://github.com/rust-lang/crates.io-index" 2251 | checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" 2252 | dependencies = [ 2253 | "rand_chacha", 2254 | "rand_core", 2255 | ] 2256 | 2257 | [[package]] 2258 | name = "rand_chacha" 2259 | version = "0.9.0" 2260 | source = "registry+https://github.com/rust-lang/crates.io-index" 2261 | checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" 2262 | dependencies = [ 2263 | "ppv-lite86", 2264 | "rand_core", 2265 | ] 2266 | 2267 | [[package]] 2268 | name = "rand_core" 2269 | version = "0.9.3" 2270 | source = "registry+https://github.com/rust-lang/crates.io-index" 2271 | checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" 2272 | dependencies = [ 2273 | "getrandom 0.3.3", 2274 | ] 2275 | 2276 | [[package]] 2277 | name = "rand_distr" 2278 | version = "0.5.1" 2279 | source = "registry+https://github.com/rust-lang/crates.io-index" 2280 | checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463" 2281 | dependencies = [ 2282 | "num-traits", 2283 | "rand", 2284 | ] 2285 | 2286 | [[package]] 2287 | name = "raw-cpuid" 2288 | version = "11.0.2" 2289 | source = "registry+https://github.com/rust-lang/crates.io-index" 2290 | checksum = "e29830cbb1290e404f24c73af91c5d8d631ce7e128691e9477556b540cd01ecd" 2291 | dependencies = [ 2292 | "bitflags", 2293 | ] 2294 | 2295 | [[package]] 2296 | name = "rayon" 2297 | version = "1.10.0" 2298 | source = "registry+https://github.com/rust-lang/crates.io-index" 2299 | checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" 2300 | dependencies = [ 2301 | "either", 2302 | "rayon-core", 2303 | ] 2304 | 2305 | [[package]] 2306 | name = "rayon-core" 2307 | version = "1.12.1" 2308 | source = "registry+https://github.com/rust-lang/crates.io-index" 2309 | checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" 2310 | dependencies = [ 2311 | "crossbeam-deque", 2312 | "crossbeam-utils", 2313 | ] 2314 | 2315 | [[package]] 2316 | name = "recursive" 2317 | version = "0.1.1" 2318 | source = "registry+https://github.com/rust-lang/crates.io-index" 2319 | checksum = "0786a43debb760f491b1bc0269fe5e84155353c67482b9e60d0cfb596054b43e" 2320 | dependencies = [ 2321 | "recursive-proc-macro-impl", 2322 | "stacker", 2323 | ] 2324 | 2325 | [[package]] 2326 | name = "recursive-proc-macro-impl" 2327 | version = "0.1.1" 2328 | source = "registry+https://github.com/rust-lang/crates.io-index" 2329 | checksum = "76009fbe0614077fc1a2ce255e3a1881a2e3a3527097d5dc6d8212c585e7e38b" 2330 | dependencies = [ 2331 | "quote", 2332 | "syn", 2333 | ] 2334 | 2335 | [[package]] 2336 | name = "redox_syscall" 2337 | version = "0.5.2" 2338 | source = "registry+https://github.com/rust-lang/crates.io-index" 2339 | checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" 2340 | dependencies = [ 2341 | "bitflags", 2342 | ] 2343 | 2344 | [[package]] 2345 | name = "ref-cast" 2346 | version = "1.0.23" 2347 | source = "registry+https://github.com/rust-lang/crates.io-index" 2348 | checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" 2349 | dependencies = [ 2350 | "ref-cast-impl", 2351 | ] 2352 | 2353 | [[package]] 2354 | name = "ref-cast-impl" 2355 | version = "1.0.23" 2356 | source = "registry+https://github.com/rust-lang/crates.io-index" 2357 | checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" 2358 | dependencies = [ 2359 | "proc-macro2", 2360 | "quote", 2361 | "syn", 2362 | ] 2363 | 2364 | [[package]] 2365 | name = "regex" 2366 | version = "1.10.5" 2367 | source = "registry+https://github.com/rust-lang/crates.io-index" 2368 | checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" 2369 | dependencies = [ 2370 | "aho-corasick", 2371 | "memchr", 2372 | "regex-automata", 2373 | "regex-syntax", 2374 | ] 2375 | 2376 | [[package]] 2377 | name = "regex-automata" 2378 | version = "0.4.7" 2379 | source = "registry+https://github.com/rust-lang/crates.io-index" 2380 | checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" 2381 | dependencies = [ 2382 | "aho-corasick", 2383 | "memchr", 2384 | "regex-syntax", 2385 | ] 2386 | 2387 | [[package]] 2388 | name = "regex-syntax" 2389 | version = "0.8.5" 2390 | source = "registry+https://github.com/rust-lang/crates.io-index" 2391 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 2392 | 2393 | [[package]] 2394 | name = "reqwest" 2395 | version = "0.12.22" 2396 | source = "registry+https://github.com/rust-lang/crates.io-index" 2397 | checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531" 2398 | dependencies = [ 2399 | "base64", 2400 | "bytes", 2401 | "futures-core", 2402 | "futures-util", 2403 | "h2", 2404 | "http", 2405 | "http-body", 2406 | "http-body-util", 2407 | "hyper", 2408 | "hyper-rustls", 2409 | "hyper-util", 2410 | "js-sys", 2411 | "log", 2412 | "percent-encoding", 2413 | "pin-project-lite", 2414 | "quinn", 2415 | "rustls", 2416 | "rustls-native-certs", 2417 | "rustls-pki-types", 2418 | "serde", 2419 | "serde_json", 2420 | "serde_urlencoded", 2421 | "sync_wrapper", 2422 | "tokio", 2423 | "tokio-rustls", 2424 | "tokio-util", 2425 | "tower", 2426 | "tower-http", 2427 | "tower-service", 2428 | "url", 2429 | "wasm-bindgen", 2430 | "wasm-bindgen-futures", 2431 | "wasm-streams", 2432 | "web-sys", 2433 | ] 2434 | 2435 | [[package]] 2436 | name = "ring" 2437 | version = "0.17.14" 2438 | source = "registry+https://github.com/rust-lang/crates.io-index" 2439 | checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" 2440 | dependencies = [ 2441 | "cc", 2442 | "cfg-if", 2443 | "getrandom 0.2.15", 2444 | "libc", 2445 | "untrusted", 2446 | "windows-sys 0.52.0", 2447 | ] 2448 | 2449 | [[package]] 2450 | name = "rmp" 2451 | version = "0.8.14" 2452 | source = "registry+https://github.com/rust-lang/crates.io-index" 2453 | checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" 2454 | dependencies = [ 2455 | "byteorder", 2456 | "num-traits", 2457 | "paste", 2458 | ] 2459 | 2460 | [[package]] 2461 | name = "rmp-serde" 2462 | version = "1.3.0" 2463 | source = "registry+https://github.com/rust-lang/crates.io-index" 2464 | checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" 2465 | dependencies = [ 2466 | "byteorder", 2467 | "rmp", 2468 | "serde", 2469 | ] 2470 | 2471 | [[package]] 2472 | name = "rustc-demangle" 2473 | version = "0.1.24" 2474 | source = "registry+https://github.com/rust-lang/crates.io-index" 2475 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 2476 | 2477 | [[package]] 2478 | name = "rustc-hash" 2479 | version = "2.1.1" 2480 | source = "registry+https://github.com/rust-lang/crates.io-index" 2481 | checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" 2482 | 2483 | [[package]] 2484 | name = "rustix" 2485 | version = "1.0.8" 2486 | source = "registry+https://github.com/rust-lang/crates.io-index" 2487 | checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" 2488 | dependencies = [ 2489 | "bitflags", 2490 | "errno", 2491 | "libc", 2492 | "linux-raw-sys", 2493 | "windows-sys 0.59.0", 2494 | ] 2495 | 2496 | [[package]] 2497 | name = "rustls" 2498 | version = "0.23.29" 2499 | source = "registry+https://github.com/rust-lang/crates.io-index" 2500 | checksum = "2491382039b29b9b11ff08b76ff6c97cf287671dbb74f0be44bda389fffe9bd1" 2501 | dependencies = [ 2502 | "once_cell", 2503 | "ring", 2504 | "rustls-pki-types", 2505 | "rustls-webpki", 2506 | "subtle", 2507 | "zeroize", 2508 | ] 2509 | 2510 | [[package]] 2511 | name = "rustls-native-certs" 2512 | version = "0.8.0" 2513 | source = "registry+https://github.com/rust-lang/crates.io-index" 2514 | checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" 2515 | dependencies = [ 2516 | "openssl-probe", 2517 | "rustls-pemfile", 2518 | "rustls-pki-types", 2519 | "schannel", 2520 | "security-framework", 2521 | ] 2522 | 2523 | [[package]] 2524 | name = "rustls-pemfile" 2525 | version = "2.2.0" 2526 | source = "registry+https://github.com/rust-lang/crates.io-index" 2527 | checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" 2528 | dependencies = [ 2529 | "rustls-pki-types", 2530 | ] 2531 | 2532 | [[package]] 2533 | name = "rustls-pki-types" 2534 | version = "1.12.0" 2535 | source = "registry+https://github.com/rust-lang/crates.io-index" 2536 | checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" 2537 | dependencies = [ 2538 | "web-time", 2539 | "zeroize", 2540 | ] 2541 | 2542 | [[package]] 2543 | name = "rustls-webpki" 2544 | version = "0.103.4" 2545 | source = "registry+https://github.com/rust-lang/crates.io-index" 2546 | checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" 2547 | dependencies = [ 2548 | "ring", 2549 | "rustls-pki-types", 2550 | "untrusted", 2551 | ] 2552 | 2553 | [[package]] 2554 | name = "rustversion" 2555 | version = "1.0.17" 2556 | source = "registry+https://github.com/rust-lang/crates.io-index" 2557 | checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" 2558 | 2559 | [[package]] 2560 | name = "ryu" 2561 | version = "1.0.18" 2562 | source = "registry+https://github.com/rust-lang/crates.io-index" 2563 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 2564 | 2565 | [[package]] 2566 | name = "same-file" 2567 | version = "1.0.6" 2568 | source = "registry+https://github.com/rust-lang/crates.io-index" 2569 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 2570 | dependencies = [ 2571 | "winapi-util", 2572 | ] 2573 | 2574 | [[package]] 2575 | name = "schannel" 2576 | version = "0.1.27" 2577 | source = "registry+https://github.com/rust-lang/crates.io-index" 2578 | checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" 2579 | dependencies = [ 2580 | "windows-sys 0.59.0", 2581 | ] 2582 | 2583 | [[package]] 2584 | name = "scopeguard" 2585 | version = "1.2.0" 2586 | source = "registry+https://github.com/rust-lang/crates.io-index" 2587 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 2588 | 2589 | [[package]] 2590 | name = "security-framework" 2591 | version = "2.11.0" 2592 | source = "registry+https://github.com/rust-lang/crates.io-index" 2593 | checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" 2594 | dependencies = [ 2595 | "bitflags", 2596 | "core-foundation", 2597 | "core-foundation-sys", 2598 | "libc", 2599 | "security-framework-sys", 2600 | ] 2601 | 2602 | [[package]] 2603 | name = "security-framework-sys" 2604 | version = "2.14.0" 2605 | source = "registry+https://github.com/rust-lang/crates.io-index" 2606 | checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" 2607 | dependencies = [ 2608 | "core-foundation-sys", 2609 | "libc", 2610 | ] 2611 | 2612 | [[package]] 2613 | name = "serde" 2614 | version = "1.0.228" 2615 | source = "registry+https://github.com/rust-lang/crates.io-index" 2616 | checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" 2617 | dependencies = [ 2618 | "serde_core", 2619 | "serde_derive", 2620 | ] 2621 | 2622 | [[package]] 2623 | name = "serde-pickle" 2624 | version = "1.1.1" 2625 | source = "registry+https://github.com/rust-lang/crates.io-index" 2626 | checksum = "c762ad136a26407c6a80825813600ceeab5e613660d93d79a41f0ec877171e71" 2627 | dependencies = [ 2628 | "byteorder", 2629 | "iter-read", 2630 | "num-bigint", 2631 | "num-traits", 2632 | "serde", 2633 | ] 2634 | 2635 | [[package]] 2636 | name = "serde_core" 2637 | version = "1.0.228" 2638 | source = "registry+https://github.com/rust-lang/crates.io-index" 2639 | checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" 2640 | dependencies = [ 2641 | "serde_derive", 2642 | ] 2643 | 2644 | [[package]] 2645 | name = "serde_derive" 2646 | version = "1.0.228" 2647 | source = "registry+https://github.com/rust-lang/crates.io-index" 2648 | checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" 2649 | dependencies = [ 2650 | "proc-macro2", 2651 | "quote", 2652 | "syn", 2653 | ] 2654 | 2655 | [[package]] 2656 | name = "serde_json" 2657 | version = "1.0.117" 2658 | source = "registry+https://github.com/rust-lang/crates.io-index" 2659 | checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" 2660 | dependencies = [ 2661 | "itoa", 2662 | "ryu", 2663 | "serde", 2664 | ] 2665 | 2666 | [[package]] 2667 | name = "serde_stacker" 2668 | version = "0.1.14" 2669 | source = "registry+https://github.com/rust-lang/crates.io-index" 2670 | checksum = "d4936375d50c4be7eff22293a9344f8e46f323ed2b3c243e52f89138d9bb0f4a" 2671 | dependencies = [ 2672 | "serde", 2673 | "serde_core", 2674 | "stacker", 2675 | ] 2676 | 2677 | [[package]] 2678 | name = "serde_urlencoded" 2679 | version = "0.7.1" 2680 | source = "registry+https://github.com/rust-lang/crates.io-index" 2681 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 2682 | dependencies = [ 2683 | "form_urlencoded", 2684 | "itoa", 2685 | "ryu", 2686 | "serde", 2687 | ] 2688 | 2689 | [[package]] 2690 | name = "sha2" 2691 | version = "0.10.9" 2692 | source = "registry+https://github.com/rust-lang/crates.io-index" 2693 | checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" 2694 | dependencies = [ 2695 | "cfg-if", 2696 | "cpufeatures", 2697 | "digest", 2698 | ] 2699 | 2700 | [[package]] 2701 | name = "shlex" 2702 | version = "1.3.0" 2703 | source = "registry+https://github.com/rust-lang/crates.io-index" 2704 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 2705 | 2706 | [[package]] 2707 | name = "signal-hook" 2708 | version = "0.3.18" 2709 | source = "registry+https://github.com/rust-lang/crates.io-index" 2710 | checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" 2711 | dependencies = [ 2712 | "libc", 2713 | "signal-hook-registry", 2714 | ] 2715 | 2716 | [[package]] 2717 | name = "signal-hook-registry" 2718 | version = "1.4.5" 2719 | source = "registry+https://github.com/rust-lang/crates.io-index" 2720 | checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" 2721 | dependencies = [ 2722 | "libc", 2723 | ] 2724 | 2725 | [[package]] 2726 | name = "simd-json" 2727 | version = "0.17.0" 2728 | source = "registry+https://github.com/rust-lang/crates.io-index" 2729 | checksum = "4255126f310d2ba20048db6321c81ab376f6a6735608bf11f0785c41f01f64e3" 2730 | dependencies = [ 2731 | "ahash", 2732 | "halfbrown", 2733 | "once_cell", 2734 | "ref-cast", 2735 | "serde", 2736 | "serde_json", 2737 | "simdutf8", 2738 | "value-trait", 2739 | ] 2740 | 2741 | [[package]] 2742 | name = "simdutf8" 2743 | version = "0.1.4" 2744 | source = "registry+https://github.com/rust-lang/crates.io-index" 2745 | checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" 2746 | 2747 | [[package]] 2748 | name = "siphasher" 2749 | version = "1.0.1" 2750 | source = "registry+https://github.com/rust-lang/crates.io-index" 2751 | checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" 2752 | 2753 | [[package]] 2754 | name = "slab" 2755 | version = "0.4.9" 2756 | source = "registry+https://github.com/rust-lang/crates.io-index" 2757 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 2758 | dependencies = [ 2759 | "autocfg", 2760 | ] 2761 | 2762 | [[package]] 2763 | name = "slotmap" 2764 | version = "1.0.7" 2765 | source = "registry+https://github.com/rust-lang/crates.io-index" 2766 | checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" 2767 | dependencies = [ 2768 | "serde", 2769 | "version_check", 2770 | ] 2771 | 2772 | [[package]] 2773 | name = "smallvec" 2774 | version = "1.13.2" 2775 | source = "registry+https://github.com/rust-lang/crates.io-index" 2776 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 2777 | 2778 | [[package]] 2779 | name = "socket2" 2780 | version = "0.5.8" 2781 | source = "registry+https://github.com/rust-lang/crates.io-index" 2782 | checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" 2783 | dependencies = [ 2784 | "libc", 2785 | "windows-sys 0.52.0", 2786 | ] 2787 | 2788 | [[package]] 2789 | name = "socket2" 2790 | version = "0.6.0" 2791 | source = "registry+https://github.com/rust-lang/crates.io-index" 2792 | checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" 2793 | dependencies = [ 2794 | "libc", 2795 | "windows-sys 0.59.0", 2796 | ] 2797 | 2798 | [[package]] 2799 | name = "sqlparser" 2800 | version = "0.53.0" 2801 | source = "registry+https://github.com/rust-lang/crates.io-index" 2802 | checksum = "05a528114c392209b3264855ad491fcce534b94a38771b0a0b97a79379275ce8" 2803 | dependencies = [ 2804 | "log", 2805 | ] 2806 | 2807 | [[package]] 2808 | name = "stable_deref_trait" 2809 | version = "1.2.0" 2810 | source = "registry+https://github.com/rust-lang/crates.io-index" 2811 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 2812 | 2813 | [[package]] 2814 | name = "stacker" 2815 | version = "0.1.15" 2816 | source = "registry+https://github.com/rust-lang/crates.io-index" 2817 | checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce" 2818 | dependencies = [ 2819 | "cc", 2820 | "cfg-if", 2821 | "libc", 2822 | "psm", 2823 | "winapi", 2824 | ] 2825 | 2826 | [[package]] 2827 | name = "static_assertions" 2828 | version = "1.1.0" 2829 | source = "registry+https://github.com/rust-lang/crates.io-index" 2830 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 2831 | 2832 | [[package]] 2833 | name = "streaming-decompression" 2834 | version = "0.1.2" 2835 | source = "registry+https://github.com/rust-lang/crates.io-index" 2836 | checksum = "bf6cc3b19bfb128a8ad11026086e31d3ce9ad23f8ea37354b31383a187c44cf3" 2837 | dependencies = [ 2838 | "fallible-streaming-iterator", 2839 | ] 2840 | 2841 | [[package]] 2842 | name = "streaming-iterator" 2843 | version = "0.1.9" 2844 | source = "registry+https://github.com/rust-lang/crates.io-index" 2845 | checksum = "2b2231b7c3057d5e4ad0156fb3dc807d900806020c5ffa3ee6ff2c8c76fb8520" 2846 | 2847 | [[package]] 2848 | name = "strength_reduce" 2849 | version = "0.2.4" 2850 | source = "registry+https://github.com/rust-lang/crates.io-index" 2851 | checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" 2852 | 2853 | [[package]] 2854 | name = "strum" 2855 | version = "0.26.2" 2856 | source = "registry+https://github.com/rust-lang/crates.io-index" 2857 | checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" 2858 | 2859 | [[package]] 2860 | name = "strum_macros" 2861 | version = "0.26.4" 2862 | source = "registry+https://github.com/rust-lang/crates.io-index" 2863 | checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" 2864 | dependencies = [ 2865 | "heck", 2866 | "proc-macro2", 2867 | "quote", 2868 | "rustversion", 2869 | "syn", 2870 | ] 2871 | 2872 | [[package]] 2873 | name = "strum_macros" 2874 | version = "0.27.2" 2875 | source = "registry+https://github.com/rust-lang/crates.io-index" 2876 | checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" 2877 | dependencies = [ 2878 | "heck", 2879 | "proc-macro2", 2880 | "quote", 2881 | "syn", 2882 | ] 2883 | 2884 | [[package]] 2885 | name = "subtle" 2886 | version = "2.6.1" 2887 | source = "registry+https://github.com/rust-lang/crates.io-index" 2888 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 2889 | 2890 | [[package]] 2891 | name = "syn" 2892 | version = "2.0.90" 2893 | source = "registry+https://github.com/rust-lang/crates.io-index" 2894 | checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" 2895 | dependencies = [ 2896 | "proc-macro2", 2897 | "quote", 2898 | "unicode-ident", 2899 | ] 2900 | 2901 | [[package]] 2902 | name = "sync_wrapper" 2903 | version = "1.0.2" 2904 | source = "registry+https://github.com/rust-lang/crates.io-index" 2905 | checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" 2906 | dependencies = [ 2907 | "futures-core", 2908 | ] 2909 | 2910 | [[package]] 2911 | name = "synstructure" 2912 | version = "0.13.2" 2913 | source = "registry+https://github.com/rust-lang/crates.io-index" 2914 | checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" 2915 | dependencies = [ 2916 | "proc-macro2", 2917 | "quote", 2918 | "syn", 2919 | ] 2920 | 2921 | [[package]] 2922 | name = "target-lexicon" 2923 | version = "0.13.2" 2924 | source = "registry+https://github.com/rust-lang/crates.io-index" 2925 | checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" 2926 | 2927 | [[package]] 2928 | name = "thiserror" 2929 | version = "1.0.61" 2930 | source = "registry+https://github.com/rust-lang/crates.io-index" 2931 | checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" 2932 | dependencies = [ 2933 | "thiserror-impl 1.0.61", 2934 | ] 2935 | 2936 | [[package]] 2937 | name = "thiserror" 2938 | version = "2.0.5" 2939 | source = "registry+https://github.com/rust-lang/crates.io-index" 2940 | checksum = "643caef17e3128658ff44d85923ef2d28af81bb71e0d67bbfe1d76f19a73e053" 2941 | dependencies = [ 2942 | "thiserror-impl 2.0.5", 2943 | ] 2944 | 2945 | [[package]] 2946 | name = "thiserror-impl" 2947 | version = "1.0.61" 2948 | source = "registry+https://github.com/rust-lang/crates.io-index" 2949 | checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" 2950 | dependencies = [ 2951 | "proc-macro2", 2952 | "quote", 2953 | "syn", 2954 | ] 2955 | 2956 | [[package]] 2957 | name = "thiserror-impl" 2958 | version = "2.0.5" 2959 | source = "registry+https://github.com/rust-lang/crates.io-index" 2960 | checksum = "995d0bbc9995d1f19d28b7215a9352b0fc3cd3a2d2ec95c2cadc485cdedbcdde" 2961 | dependencies = [ 2962 | "proc-macro2", 2963 | "quote", 2964 | "syn", 2965 | ] 2966 | 2967 | [[package]] 2968 | name = "tinystr" 2969 | version = "0.8.1" 2970 | source = "registry+https://github.com/rust-lang/crates.io-index" 2971 | checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" 2972 | dependencies = [ 2973 | "displaydoc", 2974 | "zerovec", 2975 | ] 2976 | 2977 | [[package]] 2978 | name = "tinyvec" 2979 | version = "1.8.0" 2980 | source = "registry+https://github.com/rust-lang/crates.io-index" 2981 | checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" 2982 | dependencies = [ 2983 | "tinyvec_macros", 2984 | ] 2985 | 2986 | [[package]] 2987 | name = "tinyvec_macros" 2988 | version = "0.1.1" 2989 | source = "registry+https://github.com/rust-lang/crates.io-index" 2990 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 2991 | 2992 | [[package]] 2993 | name = "tokio" 2994 | version = "1.46.1" 2995 | source = "registry+https://github.com/rust-lang/crates.io-index" 2996 | checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17" 2997 | dependencies = [ 2998 | "backtrace", 2999 | "bytes", 3000 | "io-uring", 3001 | "libc", 3002 | "mio", 3003 | "pin-project-lite", 3004 | "slab", 3005 | "socket2 0.5.8", 3006 | "tokio-macros", 3007 | "windows-sys 0.52.0", 3008 | ] 3009 | 3010 | [[package]] 3011 | name = "tokio-macros" 3012 | version = "2.5.0" 3013 | source = "registry+https://github.com/rust-lang/crates.io-index" 3014 | checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" 3015 | dependencies = [ 3016 | "proc-macro2", 3017 | "quote", 3018 | "syn", 3019 | ] 3020 | 3021 | [[package]] 3022 | name = "tokio-rustls" 3023 | version = "0.26.2" 3024 | source = "registry+https://github.com/rust-lang/crates.io-index" 3025 | checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" 3026 | dependencies = [ 3027 | "rustls", 3028 | "tokio", 3029 | ] 3030 | 3031 | [[package]] 3032 | name = "tokio-util" 3033 | version = "0.7.13" 3034 | source = "registry+https://github.com/rust-lang/crates.io-index" 3035 | checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" 3036 | dependencies = [ 3037 | "bytes", 3038 | "futures-core", 3039 | "futures-sink", 3040 | "pin-project-lite", 3041 | "tokio", 3042 | ] 3043 | 3044 | [[package]] 3045 | name = "tower" 3046 | version = "0.5.2" 3047 | source = "registry+https://github.com/rust-lang/crates.io-index" 3048 | checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" 3049 | dependencies = [ 3050 | "futures-core", 3051 | "futures-util", 3052 | "pin-project-lite", 3053 | "sync_wrapper", 3054 | "tokio", 3055 | "tower-layer", 3056 | "tower-service", 3057 | ] 3058 | 3059 | [[package]] 3060 | name = "tower-http" 3061 | version = "0.6.6" 3062 | source = "registry+https://github.com/rust-lang/crates.io-index" 3063 | checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" 3064 | dependencies = [ 3065 | "bitflags", 3066 | "bytes", 3067 | "futures-util", 3068 | "http", 3069 | "http-body", 3070 | "iri-string", 3071 | "pin-project-lite", 3072 | "tower", 3073 | "tower-layer", 3074 | "tower-service", 3075 | ] 3076 | 3077 | [[package]] 3078 | name = "tower-layer" 3079 | version = "0.3.3" 3080 | source = "registry+https://github.com/rust-lang/crates.io-index" 3081 | checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" 3082 | 3083 | [[package]] 3084 | name = "tower-service" 3085 | version = "0.3.3" 3086 | source = "registry+https://github.com/rust-lang/crates.io-index" 3087 | checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 3088 | 3089 | [[package]] 3090 | name = "tracing" 3091 | version = "0.1.41" 3092 | source = "registry+https://github.com/rust-lang/crates.io-index" 3093 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 3094 | dependencies = [ 3095 | "pin-project-lite", 3096 | "tracing-attributes", 3097 | "tracing-core", 3098 | ] 3099 | 3100 | [[package]] 3101 | name = "tracing-attributes" 3102 | version = "0.1.30" 3103 | source = "registry+https://github.com/rust-lang/crates.io-index" 3104 | checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" 3105 | dependencies = [ 3106 | "proc-macro2", 3107 | "quote", 3108 | "syn", 3109 | ] 3110 | 3111 | [[package]] 3112 | name = "tracing-core" 3113 | version = "0.1.34" 3114 | source = "registry+https://github.com/rust-lang/crates.io-index" 3115 | checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" 3116 | dependencies = [ 3117 | "once_cell", 3118 | ] 3119 | 3120 | [[package]] 3121 | name = "try-lock" 3122 | version = "0.2.5" 3123 | source = "registry+https://github.com/rust-lang/crates.io-index" 3124 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 3125 | 3126 | [[package]] 3127 | name = "typenum" 3128 | version = "1.19.0" 3129 | source = "registry+https://github.com/rust-lang/crates.io-index" 3130 | checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" 3131 | 3132 | [[package]] 3133 | name = "unicode-ident" 3134 | version = "1.0.12" 3135 | source = "registry+https://github.com/rust-lang/crates.io-index" 3136 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 3137 | 3138 | [[package]] 3139 | name = "unicode-normalization" 3140 | version = "0.1.24" 3141 | source = "registry+https://github.com/rust-lang/crates.io-index" 3142 | checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" 3143 | dependencies = [ 3144 | "tinyvec", 3145 | ] 3146 | 3147 | [[package]] 3148 | name = "unicode-reverse" 3149 | version = "1.0.9" 3150 | source = "registry+https://github.com/rust-lang/crates.io-index" 3151 | checksum = "4b6f4888ebc23094adfb574fdca9fdc891826287a6397d2cd28802ffd6f20c76" 3152 | dependencies = [ 3153 | "unicode-segmentation", 3154 | ] 3155 | 3156 | [[package]] 3157 | name = "unicode-segmentation" 3158 | version = "1.11.0" 3159 | source = "registry+https://github.com/rust-lang/crates.io-index" 3160 | checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" 3161 | 3162 | [[package]] 3163 | name = "unicode-width" 3164 | version = "0.1.13" 3165 | source = "registry+https://github.com/rust-lang/crates.io-index" 3166 | checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" 3167 | 3168 | [[package]] 3169 | name = "unindent" 3170 | version = "0.2.3" 3171 | source = "registry+https://github.com/rust-lang/crates.io-index" 3172 | checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce" 3173 | 3174 | [[package]] 3175 | name = "untrusted" 3176 | version = "0.9.0" 3177 | source = "registry+https://github.com/rust-lang/crates.io-index" 3178 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 3179 | 3180 | [[package]] 3181 | name = "unty" 3182 | version = "0.0.4" 3183 | source = "registry+https://github.com/rust-lang/crates.io-index" 3184 | checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" 3185 | 3186 | [[package]] 3187 | name = "url" 3188 | version = "2.5.4" 3189 | source = "registry+https://github.com/rust-lang/crates.io-index" 3190 | checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" 3191 | dependencies = [ 3192 | "form_urlencoded", 3193 | "idna", 3194 | "percent-encoding", 3195 | ] 3196 | 3197 | [[package]] 3198 | name = "utf8_iter" 3199 | version = "1.0.4" 3200 | source = "registry+https://github.com/rust-lang/crates.io-index" 3201 | checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 3202 | 3203 | [[package]] 3204 | name = "uuid" 3205 | version = "1.17.0" 3206 | source = "registry+https://github.com/rust-lang/crates.io-index" 3207 | checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" 3208 | dependencies = [ 3209 | "getrandom 0.3.3", 3210 | "js-sys", 3211 | "serde", 3212 | "wasm-bindgen", 3213 | ] 3214 | 3215 | [[package]] 3216 | name = "value-trait" 3217 | version = "0.12.1" 3218 | source = "registry+https://github.com/rust-lang/crates.io-index" 3219 | checksum = "8e80f0c733af0720a501b3905d22e2f97662d8eacfe082a75ed7ffb5ab08cb59" 3220 | dependencies = [ 3221 | "float-cmp", 3222 | "halfbrown", 3223 | "itoa", 3224 | "ryu", 3225 | ] 3226 | 3227 | [[package]] 3228 | name = "version_check" 3229 | version = "0.9.4" 3230 | source = "registry+https://github.com/rust-lang/crates.io-index" 3231 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 3232 | 3233 | [[package]] 3234 | name = "virtue" 3235 | version = "0.0.18" 3236 | source = "registry+https://github.com/rust-lang/crates.io-index" 3237 | checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" 3238 | 3239 | [[package]] 3240 | name = "walkdir" 3241 | version = "2.5.0" 3242 | source = "registry+https://github.com/rust-lang/crates.io-index" 3243 | checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" 3244 | dependencies = [ 3245 | "same-file", 3246 | "winapi-util", 3247 | ] 3248 | 3249 | [[package]] 3250 | name = "want" 3251 | version = "0.3.1" 3252 | source = "registry+https://github.com/rust-lang/crates.io-index" 3253 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 3254 | dependencies = [ 3255 | "try-lock", 3256 | ] 3257 | 3258 | [[package]] 3259 | name = "wasi" 3260 | version = "0.11.0+wasi-snapshot-preview1" 3261 | source = "registry+https://github.com/rust-lang/crates.io-index" 3262 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 3263 | 3264 | [[package]] 3265 | name = "wasi" 3266 | version = "0.14.2+wasi-0.2.4" 3267 | source = "registry+https://github.com/rust-lang/crates.io-index" 3268 | checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" 3269 | dependencies = [ 3270 | "wit-bindgen-rt", 3271 | ] 3272 | 3273 | [[package]] 3274 | name = "wasm-bindgen" 3275 | version = "0.2.100" 3276 | source = "registry+https://github.com/rust-lang/crates.io-index" 3277 | checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" 3278 | dependencies = [ 3279 | "cfg-if", 3280 | "once_cell", 3281 | "rustversion", 3282 | "wasm-bindgen-macro", 3283 | ] 3284 | 3285 | [[package]] 3286 | name = "wasm-bindgen-backend" 3287 | version = "0.2.100" 3288 | source = "registry+https://github.com/rust-lang/crates.io-index" 3289 | checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" 3290 | dependencies = [ 3291 | "bumpalo", 3292 | "log", 3293 | "proc-macro2", 3294 | "quote", 3295 | "syn", 3296 | "wasm-bindgen-shared", 3297 | ] 3298 | 3299 | [[package]] 3300 | name = "wasm-bindgen-futures" 3301 | version = "0.4.50" 3302 | source = "registry+https://github.com/rust-lang/crates.io-index" 3303 | checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" 3304 | dependencies = [ 3305 | "cfg-if", 3306 | "js-sys", 3307 | "once_cell", 3308 | "wasm-bindgen", 3309 | "web-sys", 3310 | ] 3311 | 3312 | [[package]] 3313 | name = "wasm-bindgen-macro" 3314 | version = "0.2.100" 3315 | source = "registry+https://github.com/rust-lang/crates.io-index" 3316 | checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" 3317 | dependencies = [ 3318 | "quote", 3319 | "wasm-bindgen-macro-support", 3320 | ] 3321 | 3322 | [[package]] 3323 | name = "wasm-bindgen-macro-support" 3324 | version = "0.2.100" 3325 | source = "registry+https://github.com/rust-lang/crates.io-index" 3326 | checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" 3327 | dependencies = [ 3328 | "proc-macro2", 3329 | "quote", 3330 | "syn", 3331 | "wasm-bindgen-backend", 3332 | "wasm-bindgen-shared", 3333 | ] 3334 | 3335 | [[package]] 3336 | name = "wasm-bindgen-shared" 3337 | version = "0.2.100" 3338 | source = "registry+https://github.com/rust-lang/crates.io-index" 3339 | checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" 3340 | dependencies = [ 3341 | "unicode-ident", 3342 | ] 3343 | 3344 | [[package]] 3345 | name = "wasm-streams" 3346 | version = "0.4.2" 3347 | source = "registry+https://github.com/rust-lang/crates.io-index" 3348 | checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" 3349 | dependencies = [ 3350 | "futures-util", 3351 | "js-sys", 3352 | "wasm-bindgen", 3353 | "wasm-bindgen-futures", 3354 | "web-sys", 3355 | ] 3356 | 3357 | [[package]] 3358 | name = "web-sys" 3359 | version = "0.3.77" 3360 | source = "registry+https://github.com/rust-lang/crates.io-index" 3361 | checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" 3362 | dependencies = [ 3363 | "js-sys", 3364 | "wasm-bindgen", 3365 | ] 3366 | 3367 | [[package]] 3368 | name = "web-time" 3369 | version = "1.1.0" 3370 | source = "registry+https://github.com/rust-lang/crates.io-index" 3371 | checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" 3372 | dependencies = [ 3373 | "js-sys", 3374 | "wasm-bindgen", 3375 | ] 3376 | 3377 | [[package]] 3378 | name = "winapi" 3379 | version = "0.3.9" 3380 | source = "registry+https://github.com/rust-lang/crates.io-index" 3381 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 3382 | dependencies = [ 3383 | "winapi-i686-pc-windows-gnu", 3384 | "winapi-x86_64-pc-windows-gnu", 3385 | ] 3386 | 3387 | [[package]] 3388 | name = "winapi-i686-pc-windows-gnu" 3389 | version = "0.4.0" 3390 | source = "registry+https://github.com/rust-lang/crates.io-index" 3391 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 3392 | 3393 | [[package]] 3394 | name = "winapi-util" 3395 | version = "0.1.9" 3396 | source = "registry+https://github.com/rust-lang/crates.io-index" 3397 | checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" 3398 | dependencies = [ 3399 | "windows-sys 0.59.0", 3400 | ] 3401 | 3402 | [[package]] 3403 | name = "winapi-x86_64-pc-windows-gnu" 3404 | version = "0.4.0" 3405 | source = "registry+https://github.com/rust-lang/crates.io-index" 3406 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 3407 | 3408 | [[package]] 3409 | name = "windows-core" 3410 | version = "0.52.0" 3411 | source = "registry+https://github.com/rust-lang/crates.io-index" 3412 | checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" 3413 | dependencies = [ 3414 | "windows-targets", 3415 | ] 3416 | 3417 | [[package]] 3418 | name = "windows-link" 3419 | version = "0.2.1" 3420 | source = "registry+https://github.com/rust-lang/crates.io-index" 3421 | checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" 3422 | 3423 | [[package]] 3424 | name = "windows-sys" 3425 | version = "0.52.0" 3426 | source = "registry+https://github.com/rust-lang/crates.io-index" 3427 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 3428 | dependencies = [ 3429 | "windows-targets", 3430 | ] 3431 | 3432 | [[package]] 3433 | name = "windows-sys" 3434 | version = "0.59.0" 3435 | source = "registry+https://github.com/rust-lang/crates.io-index" 3436 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 3437 | dependencies = [ 3438 | "windows-targets", 3439 | ] 3440 | 3441 | [[package]] 3442 | name = "windows-targets" 3443 | version = "0.52.6" 3444 | source = "registry+https://github.com/rust-lang/crates.io-index" 3445 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 3446 | dependencies = [ 3447 | "windows_aarch64_gnullvm", 3448 | "windows_aarch64_msvc", 3449 | "windows_i686_gnu", 3450 | "windows_i686_gnullvm", 3451 | "windows_i686_msvc", 3452 | "windows_x86_64_gnu", 3453 | "windows_x86_64_gnullvm", 3454 | "windows_x86_64_msvc", 3455 | ] 3456 | 3457 | [[package]] 3458 | name = "windows_aarch64_gnullvm" 3459 | version = "0.52.6" 3460 | source = "registry+https://github.com/rust-lang/crates.io-index" 3461 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 3462 | 3463 | [[package]] 3464 | name = "windows_aarch64_msvc" 3465 | version = "0.52.6" 3466 | source = "registry+https://github.com/rust-lang/crates.io-index" 3467 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 3468 | 3469 | [[package]] 3470 | name = "windows_i686_gnu" 3471 | version = "0.52.6" 3472 | source = "registry+https://github.com/rust-lang/crates.io-index" 3473 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 3474 | 3475 | [[package]] 3476 | name = "windows_i686_gnullvm" 3477 | version = "0.52.6" 3478 | source = "registry+https://github.com/rust-lang/crates.io-index" 3479 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 3480 | 3481 | [[package]] 3482 | name = "windows_i686_msvc" 3483 | version = "0.52.6" 3484 | source = "registry+https://github.com/rust-lang/crates.io-index" 3485 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 3486 | 3487 | [[package]] 3488 | name = "windows_x86_64_gnu" 3489 | version = "0.52.6" 3490 | source = "registry+https://github.com/rust-lang/crates.io-index" 3491 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 3492 | 3493 | [[package]] 3494 | name = "windows_x86_64_gnullvm" 3495 | version = "0.52.6" 3496 | source = "registry+https://github.com/rust-lang/crates.io-index" 3497 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 3498 | 3499 | [[package]] 3500 | name = "windows_x86_64_msvc" 3501 | version = "0.52.6" 3502 | source = "registry+https://github.com/rust-lang/crates.io-index" 3503 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 3504 | 3505 | [[package]] 3506 | name = "wit-bindgen-rt" 3507 | version = "0.39.0" 3508 | source = "registry+https://github.com/rust-lang/crates.io-index" 3509 | checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" 3510 | dependencies = [ 3511 | "bitflags", 3512 | ] 3513 | 3514 | [[package]] 3515 | name = "writeable" 3516 | version = "0.6.1" 3517 | source = "registry+https://github.com/rust-lang/crates.io-index" 3518 | checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" 3519 | 3520 | [[package]] 3521 | name = "xxhash-rust" 3522 | version = "0.8.10" 3523 | source = "registry+https://github.com/rust-lang/crates.io-index" 3524 | checksum = "927da81e25be1e1a2901d59b81b37dd2efd1fc9c9345a55007f09bf5a2d3ee03" 3525 | 3526 | [[package]] 3527 | name = "yoke" 3528 | version = "0.8.0" 3529 | source = "registry+https://github.com/rust-lang/crates.io-index" 3530 | checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" 3531 | dependencies = [ 3532 | "serde", 3533 | "stable_deref_trait", 3534 | "yoke-derive", 3535 | "zerofrom", 3536 | ] 3537 | 3538 | [[package]] 3539 | name = "yoke-derive" 3540 | version = "0.8.0" 3541 | source = "registry+https://github.com/rust-lang/crates.io-index" 3542 | checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" 3543 | dependencies = [ 3544 | "proc-macro2", 3545 | "quote", 3546 | "syn", 3547 | "synstructure", 3548 | ] 3549 | 3550 | [[package]] 3551 | name = "zerocopy" 3552 | version = "0.7.34" 3553 | source = "registry+https://github.com/rust-lang/crates.io-index" 3554 | checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" 3555 | dependencies = [ 3556 | "zerocopy-derive", 3557 | ] 3558 | 3559 | [[package]] 3560 | name = "zerocopy-derive" 3561 | version = "0.7.34" 3562 | source = "registry+https://github.com/rust-lang/crates.io-index" 3563 | checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" 3564 | dependencies = [ 3565 | "proc-macro2", 3566 | "quote", 3567 | "syn", 3568 | ] 3569 | 3570 | [[package]] 3571 | name = "zerofrom" 3572 | version = "0.1.6" 3573 | source = "registry+https://github.com/rust-lang/crates.io-index" 3574 | checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" 3575 | dependencies = [ 3576 | "zerofrom-derive", 3577 | ] 3578 | 3579 | [[package]] 3580 | name = "zerofrom-derive" 3581 | version = "0.1.6" 3582 | source = "registry+https://github.com/rust-lang/crates.io-index" 3583 | checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" 3584 | dependencies = [ 3585 | "proc-macro2", 3586 | "quote", 3587 | "syn", 3588 | "synstructure", 3589 | ] 3590 | 3591 | [[package]] 3592 | name = "zeroize" 3593 | version = "1.8.1" 3594 | source = "registry+https://github.com/rust-lang/crates.io-index" 3595 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 3596 | 3597 | [[package]] 3598 | name = "zerotrie" 3599 | version = "0.2.2" 3600 | source = "registry+https://github.com/rust-lang/crates.io-index" 3601 | checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" 3602 | dependencies = [ 3603 | "displaydoc", 3604 | "yoke", 3605 | "zerofrom", 3606 | ] 3607 | 3608 | [[package]] 3609 | name = "zerovec" 3610 | version = "0.11.2" 3611 | source = "registry+https://github.com/rust-lang/crates.io-index" 3612 | checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" 3613 | dependencies = [ 3614 | "yoke", 3615 | "zerofrom", 3616 | "zerovec-derive", 3617 | ] 3618 | 3619 | [[package]] 3620 | name = "zerovec-derive" 3621 | version = "0.11.1" 3622 | source = "registry+https://github.com/rust-lang/crates.io-index" 3623 | checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" 3624 | dependencies = [ 3625 | "proc-macro2", 3626 | "quote", 3627 | "syn", 3628 | ] 3629 | 3630 | [[package]] 3631 | name = "zstd" 3632 | version = "0.13.1" 3633 | source = "registry+https://github.com/rust-lang/crates.io-index" 3634 | checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a" 3635 | dependencies = [ 3636 | "zstd-safe", 3637 | ] 3638 | 3639 | [[package]] 3640 | name = "zstd-safe" 3641 | version = "7.1.0" 3642 | source = "registry+https://github.com/rust-lang/crates.io-index" 3643 | checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a" 3644 | dependencies = [ 3645 | "zstd-sys", 3646 | ] 3647 | 3648 | [[package]] 3649 | name = "zstd-sys" 3650 | version = "2.0.11+zstd.1.5.6" 3651 | source = "registry+https://github.com/rust-lang/crates.io-index" 3652 | checksum = "75652c55c0b6f3e6f12eb786fe1bc960396bf05a1eb3bf1f3691c3610ac2e6d4" 3653 | dependencies = [ 3654 | "cc", 3655 | "pkg-config", 3656 | ] 3657 | --------------------------------------------------------------------------------