From 217540fc8a4bb1fcacbefc082b6d453378da77d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Gr=C3=B8nbech?= Date: Sun, 4 Jan 2026 23:34:07 +0100 Subject: [PATCH 1/7] feat: Add ability to use datetime objects in timestamprange --- cognite/client/data_classes/shared.py | 11 ++++++----- tests/tests_unit/test_api/test_data_sets.py | 12 ++++++++---- .../test_data_classes/test_timestamp_range.py | 9 +++++++++ 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/cognite/client/data_classes/shared.py b/cognite/client/data_classes/shared.py index c3de2032a4..83761a9964 100644 --- a/cognite/client/data_classes/shared.py +++ b/cognite/client/data_classes/shared.py @@ -7,19 +7,20 @@ from cognite.client.data_classes._base import CogniteFilter, CogniteResource, UnknownCogniteResource +from datetime import datetime class TimestampRange(CogniteResource): """Range between two timestamps. Args: - max (int | None): The number of milliseconds since 00:00:00 Thursday, 1 January 1970, Coordinated Universal Time (UTC), minus leap seconds. - min (int | None): The number of milliseconds since 00:00:00 Thursday, 1 January 1970, Coordinated Universal Time (UTC), minus leap seconds. + max (int | datetime | None): The number of milliseconds since 00:00:00 Thursday, 1 January 1970, Coordinated Universal Time (UTC), minus leap seconds, or a datetime object. + min (int | datetime | None): The number of milliseconds since 00:00:00 Thursday, 1 January 1970, Coordinated Universal Time (UTC), minus leap seconds, or a datetime object. **_ (Any): No description. """ - def __init__(self, max: int | None = None, min: int | None = None, **_: Any) -> None: - self.max = max - self.min = min + def __init__(self, max: int | datetime | None = None, min: int | datetime | None = None, **_: Any) -> None: + self.max = int(max.timestamp() * 1000) if isinstance(max, datetime) else max + self.min = int(min.timestamp() * 1000) if isinstance(min, datetime) else min @classmethod def _load(cls, resource: dict[str, Any]) -> Self: diff --git a/tests/tests_unit/test_api/test_data_sets.py b/tests/tests_unit/test_api/test_data_sets.py index dd18a2c1ab..610c422dcf 100644 --- a/tests/tests_unit/test_api/test_data_sets.py +++ b/tests/tests_unit/test_api/test_data_sets.py @@ -2,6 +2,7 @@ import re from typing import TYPE_CHECKING, Any +from datetime import datetime import pytest from pytest_httpx import HTTPXMock @@ -65,10 +66,13 @@ def test_retrieve_multiple( assert isinstance(res, DataSetList) assert [example_data_set] == res.dump(camel_case=True) - def test_list_with_timestamp_range(self, cognite_client: CogniteClient, mock_ds_response: HTTPXMock) -> None: - cognite_client.data_sets.list(created_time=TimestampRange(min=20)) - assert 20 == jsgz_load(mock_ds_response.get_requests()[0].content)["filter"]["createdTime"]["min"] - assert "max" not in jsgz_load(mock_ds_response.get_requests()[0].content)["filter"]["createdTime"] + @pytest.mark.parametrize("min_time", [20, datetime.fromtimestamp(20 / 1000)]) + def test_list_with_timestamp_range( + self, cognite_client: CogniteClient, mock_ds_response: HTTPXMock, min_time: int | datetime + ) -> None: + cognite_client.data_sets.list(created_time=TimestampRange(min=min_time)) + assert 20 == jsgz_load(mock_ds_response.calls[0].request.body)["filter"]["createdTime"]["min"] + assert "max" not in jsgz_load(mock_ds_response.calls[0].request.body)["filter"]["createdTime"] def test_list_with_time_dict(self, cognite_client: CogniteClient, mock_ds_response: HTTPXMock) -> None: cognite_client.data_sets.list(last_updated_time={"max": 20}) diff --git a/tests/tests_unit/test_data_classes/test_timestamp_range.py b/tests/tests_unit/test_data_classes/test_timestamp_range.py index 907af6f5b8..19040d5e06 100644 --- a/tests/tests_unit/test_data_classes/test_timestamp_range.py +++ b/tests/tests_unit/test_data_classes/test_timestamp_range.py @@ -1,4 +1,5 @@ from __future__ import annotations +from datetime import datetime from cognite.client.data_classes import AggregateResultItem, TimestampRange @@ -27,3 +28,11 @@ def test_camels(self) -> None: ag = AggregateResultItem(child_count=23, depth=1, path=[]) assert 23 == ag.child_count assert {"childCount": 23, "depth": 1, "path": []} == ag.dump(camel_case=True) + + def test_datetime(self) -> None: + min_time = datetime.fromtimestamp(1767222000) # 2026-01-01 00:00:00 GMT+01 + max_time = datetime.fromtimestamp(1767308400) # 2026-01-02 00:00:00 GMT+01 + tsr = TimestampRange(min=min_time, max=max_time) + assert tsr.min == 1767222000000 + assert tsr.max == 1767308400000 + assert {"min": 1767222000000, "max": 1767308400000} == tsr.dump() From 078bd0a1cf641e0a7e3b77199e7914d56901c87b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Gr=C3=B8nbech?= Date: Mon, 5 Jan 2026 09:03:56 +0100 Subject: [PATCH 2/7] Fix error on Windows --- tests/tests_unit/test_api/test_data_sets.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/tests_unit/test_api/test_data_sets.py b/tests/tests_unit/test_api/test_data_sets.py index 610c422dcf..6764a0225e 100644 --- a/tests/tests_unit/test_api/test_data_sets.py +++ b/tests/tests_unit/test_api/test_data_sets.py @@ -2,7 +2,7 @@ import re from typing import TYPE_CHECKING, Any -from datetime import datetime +from datetime import datetime, timezone import pytest from pytest_httpx import HTTPXMock @@ -66,7 +66,8 @@ def test_retrieve_multiple( assert isinstance(res, DataSetList) assert [example_data_set] == res.dump(camel_case=True) - @pytest.mark.parametrize("min_time", [20, datetime.fromtimestamp(20 / 1000)]) + # NOTE: Have to set timezeon in order to avoid OSError on Windows: https://stackoverflow.com/a/65564765/5753974 + @pytest.mark.parametrize("min_time", [20, datetime.fromtimestamp(20 / 1000, timezone.utc)]) def test_list_with_timestamp_range( self, cognite_client: CogniteClient, mock_ds_response: HTTPXMock, min_time: int | datetime ) -> None: From 1a83f1662ddbeeed65a0adbcd663713793cb6e23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Gr=C3=B8nbech?= Date: Mon, 5 Jan 2026 09:36:57 +0100 Subject: [PATCH 3/7] Fix issues reported by Geminii --- cognite/client/data_classes/shared.py | 11 +++++++++++ .../test_data_classes/test_timestamp_range.py | 8 ++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/cognite/client/data_classes/shared.py b/cognite/client/data_classes/shared.py index 83761a9964..62d392f4ad 100644 --- a/cognite/client/data_classes/shared.py +++ b/cognite/client/data_classes/shared.py @@ -1,13 +1,24 @@ from __future__ import annotations +<<<<<<< HEAD from collections.abc import Collection, Sequence from typing import Any, Literal +======= +from collections.abc import Sequence +from datetime import datetime +from typing import TYPE_CHECKING, Any, Literal +>>>>>>> 1f672cf9 (Fix issues reported by Geminii) from typing_extensions import Self from cognite.client.data_classes._base import CogniteFilter, CogniteResource, UnknownCogniteResource +<<<<<<< HEAD from datetime import datetime +======= +if TYPE_CHECKING: + from cognite.client import CogniteClient +>>>>>>> 1f672cf9 (Fix issues reported by Geminii) class TimestampRange(CogniteResource): """Range between two timestamps. diff --git a/tests/tests_unit/test_data_classes/test_timestamp_range.py b/tests/tests_unit/test_data_classes/test_timestamp_range.py index 19040d5e06..ae271ea1b1 100644 --- a/tests/tests_unit/test_data_classes/test_timestamp_range.py +++ b/tests/tests_unit/test_data_classes/test_timestamp_range.py @@ -1,5 +1,5 @@ from __future__ import annotations -from datetime import datetime +from datetime import datetime, timezone from cognite.client.data_classes import AggregateResultItem, TimestampRange @@ -29,9 +29,9 @@ def test_camels(self) -> None: assert 23 == ag.child_count assert {"childCount": 23, "depth": 1, "path": []} == ag.dump(camel_case=True) - def test_datetime(self) -> None: - min_time = datetime.fromtimestamp(1767222000) # 2026-01-01 00:00:00 GMT+01 - max_time = datetime.fromtimestamp(1767308400) # 2026-01-02 00:00:00 GMT+01 + def test_datetime(self): + min_time = datetime.fromtimestamp(1767222000, timezone.utc) # 2026-01-01 00:00:00 GMT+01 + max_time = datetime.fromtimestamp(1767308400, timezone.utc) # 2026-01-02 00:00:00 GMT+01 tsr = TimestampRange(min=min_time, max=max_time) assert tsr.min == 1767222000000 assert tsr.max == 1767308400000 From e5246122bd3ceef8bbf707074bd9ff9b00d5c99b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Gr=C3=B8nbech?= Date: Tue, 6 Jan 2026 09:13:29 +0100 Subject: [PATCH 4/7] feat: Add support for time-shift strings in TimestampRange --- cognite/client/data_classes/shared.py | 17 ++++++++++++----- tests/tests_unit/test_api/test_data_sets.py | 1 - .../test_data_classes/test_timestamp_range.py | 12 +++++++++++- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/cognite/client/data_classes/shared.py b/cognite/client/data_classes/shared.py index 62d392f4ad..5c80b6b30a 100644 --- a/cognite/client/data_classes/shared.py +++ b/cognite/client/data_classes/shared.py @@ -11,7 +11,12 @@ from typing_extensions import Self +<<<<<<< HEAD from cognite.client.data_classes._base import CogniteFilter, CogniteResource, UnknownCogniteResource +======= +from cognite.client.data_classes._base import CogniteFilter, CogniteObject, Geometry, UnknownCogniteObject +from cognite.client.utils._time import timestamp_to_ms +>>>>>>> 392bd57c (feat: Add support for time-shift strings in TimestampRange) <<<<<<< HEAD from datetime import datetime @@ -24,14 +29,16 @@ class TimestampRange(CogniteResource): """Range between two timestamps. Args: - max (int | datetime | None): The number of milliseconds since 00:00:00 Thursday, 1 January 1970, Coordinated Universal Time (UTC), minus leap seconds, or a datetime object. - min (int | datetime | None): The number of milliseconds since 00:00:00 Thursday, 1 January 1970, Coordinated Universal Time (UTC), minus leap seconds, or a datetime object. + max (int | float | str | datetime | None): The number of milliseconds since 00:00:00 Thursday, 1 January 1970, Coordinated Universal Time (UTC), minus leap seconds, a string in time-shift format or a datetime object. + min (int | float | str | datetime | None): The number of milliseconds since 00:00:00 Thursday, 1 January 1970, Coordinated Universal Time (UTC), minus leap seconds, a string in time-shift format or a datetime object. **_ (Any): No description. """ - def __init__(self, max: int | datetime | None = None, min: int | datetime | None = None, **_: Any) -> None: - self.max = int(max.timestamp() * 1000) if isinstance(max, datetime) else max - self.min = int(min.timestamp() * 1000) if isinstance(min, datetime) else min + def __init__( + self, max: int | float | str | datetime | None = None, min: int | float | str | datetime | None = None, **_: Any + ) -> None: + self.max = timestamp_to_ms(max) if max is not None else None + self.min = timestamp_to_ms(min) if min is not None else None @classmethod def _load(cls, resource: dict[str, Any]) -> Self: diff --git a/tests/tests_unit/test_api/test_data_sets.py b/tests/tests_unit/test_api/test_data_sets.py index 6764a0225e..2aacfe5cc0 100644 --- a/tests/tests_unit/test_api/test_data_sets.py +++ b/tests/tests_unit/test_api/test_data_sets.py @@ -66,7 +66,6 @@ def test_retrieve_multiple( assert isinstance(res, DataSetList) assert [example_data_set] == res.dump(camel_case=True) - # NOTE: Have to set timezeon in order to avoid OSError on Windows: https://stackoverflow.com/a/65564765/5753974 @pytest.mark.parametrize("min_time", [20, datetime.fromtimestamp(20 / 1000, timezone.utc)]) def test_list_with_timestamp_range( self, cognite_client: CogniteClient, mock_ds_response: HTTPXMock, min_time: int | datetime diff --git a/tests/tests_unit/test_data_classes/test_timestamp_range.py b/tests/tests_unit/test_data_classes/test_timestamp_range.py index ae271ea1b1..85e3814b0c 100644 --- a/tests/tests_unit/test_data_classes/test_timestamp_range.py +++ b/tests/tests_unit/test_data_classes/test_timestamp_range.py @@ -1,5 +1,7 @@ from __future__ import annotations -from datetime import datetime, timezone +from datetime import datetime, timedelta, timezone + +import pytest from cognite.client.data_classes import AggregateResultItem, TimestampRange @@ -36,3 +38,11 @@ def test_datetime(self): assert tsr.min == 1767222000000 assert tsr.max == 1767308400000 assert {"min": 1767222000000, "max": 1767308400000} == tsr.dump() + + def test_time_shift_string(self): + now_time = int(datetime.now(timezone.utc).timestamp() * 1000) + day_ago_time = now_time - timedelta(days=1) // timedelta(milliseconds=1) + tsr = TimestampRange(min="1d-ago", max="now") + # NOTE: Using approx because of the small time difference between calls + assert tsr.min == pytest.approx(day_ago_time, 100) + assert tsr.max == pytest.approx(now_time, 100) From eb9ca0cfb5a6fe67b6ecf970d6c4afe55f6fd791 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Gr=C3=B8nbech?= Date: Thu, 19 Feb 2026 11:07:56 +0100 Subject: [PATCH 5/7] Rebase on v8 --- cognite/client/data_classes/shared.py | 17 +---------------- tests/tests_unit/test_api/test_data_sets.py | 6 +++--- .../test_data_classes/test_timestamp_range.py | 5 +++-- 3 files changed, 7 insertions(+), 21 deletions(-) diff --git a/cognite/client/data_classes/shared.py b/cognite/client/data_classes/shared.py index 5c80b6b30a..ca40ef07d8 100644 --- a/cognite/client/data_classes/shared.py +++ b/cognite/client/data_classes/shared.py @@ -1,29 +1,14 @@ from __future__ import annotations -<<<<<<< HEAD from collections.abc import Collection, Sequence -from typing import Any, Literal -======= -from collections.abc import Sequence from datetime import datetime -from typing import TYPE_CHECKING, Any, Literal ->>>>>>> 1f672cf9 (Fix issues reported by Geminii) +from typing import Any, Literal from typing_extensions import Self -<<<<<<< HEAD from cognite.client.data_classes._base import CogniteFilter, CogniteResource, UnknownCogniteResource -======= -from cognite.client.data_classes._base import CogniteFilter, CogniteObject, Geometry, UnknownCogniteObject from cognite.client.utils._time import timestamp_to_ms ->>>>>>> 392bd57c (feat: Add support for time-shift strings in TimestampRange) -<<<<<<< HEAD -from datetime import datetime -======= -if TYPE_CHECKING: - from cognite.client import CogniteClient ->>>>>>> 1f672cf9 (Fix issues reported by Geminii) class TimestampRange(CogniteResource): """Range between two timestamps. diff --git a/tests/tests_unit/test_api/test_data_sets.py b/tests/tests_unit/test_api/test_data_sets.py index 2aacfe5cc0..e97ea4b068 100644 --- a/tests/tests_unit/test_api/test_data_sets.py +++ b/tests/tests_unit/test_api/test_data_sets.py @@ -1,8 +1,8 @@ from __future__ import annotations import re -from typing import TYPE_CHECKING, Any from datetime import datetime, timezone +from typing import TYPE_CHECKING, Any import pytest from pytest_httpx import HTTPXMock @@ -71,8 +71,8 @@ def test_list_with_timestamp_range( self, cognite_client: CogniteClient, mock_ds_response: HTTPXMock, min_time: int | datetime ) -> None: cognite_client.data_sets.list(created_time=TimestampRange(min=min_time)) - assert 20 == jsgz_load(mock_ds_response.calls[0].request.body)["filter"]["createdTime"]["min"] - assert "max" not in jsgz_load(mock_ds_response.calls[0].request.body)["filter"]["createdTime"] + assert 20 == jsgz_load(mock_ds_response.get_requests()[0].content)["filter"]["createdTime"]["min"] + assert "max" not in jsgz_load(mock_ds_response.get_requests()[0].content)["filter"]["createdTime"] def test_list_with_time_dict(self, cognite_client: CogniteClient, mock_ds_response: HTTPXMock) -> None: cognite_client.data_sets.list(last_updated_time={"max": 20}) diff --git a/tests/tests_unit/test_data_classes/test_timestamp_range.py b/tests/tests_unit/test_data_classes/test_timestamp_range.py index 85e3814b0c..7dd03522e9 100644 --- a/tests/tests_unit/test_data_classes/test_timestamp_range.py +++ b/tests/tests_unit/test_data_classes/test_timestamp_range.py @@ -1,4 +1,5 @@ from __future__ import annotations + from datetime import datetime, timedelta, timezone import pytest @@ -31,7 +32,7 @@ def test_camels(self) -> None: assert 23 == ag.child_count assert {"childCount": 23, "depth": 1, "path": []} == ag.dump(camel_case=True) - def test_datetime(self): + def test_datetime(self) -> None: min_time = datetime.fromtimestamp(1767222000, timezone.utc) # 2026-01-01 00:00:00 GMT+01 max_time = datetime.fromtimestamp(1767308400, timezone.utc) # 2026-01-02 00:00:00 GMT+01 tsr = TimestampRange(min=min_time, max=max_time) @@ -39,7 +40,7 @@ def test_datetime(self): assert tsr.max == 1767308400000 assert {"min": 1767222000000, "max": 1767308400000} == tsr.dump() - def test_time_shift_string(self): + def test_time_shift_string(self) -> None: now_time = int(datetime.now(timezone.utc).timestamp() * 1000) day_ago_time = now_time - timedelta(days=1) // timedelta(milliseconds=1) tsr = TimestampRange(min="1d-ago", max="now") From 6e8f4fbfdc5cd59cb74deb4c47ca91ae64514001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Gr=C3=B8nbech?= Date: Fri, 20 Feb 2026 15:33:33 +0100 Subject: [PATCH 6/7] Update docstring examples --- cognite/client/_api/simulators/models_revisions.py | 4 ++-- cognite/client/_api/simulators/runs.py | 4 ++-- cognite/client/_sync_api/simulators/models_revisions.py | 6 +++--- cognite/client/_sync_api/simulators/runs.py | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cognite/client/_api/simulators/models_revisions.py b/cognite/client/_api/simulators/models_revisions.py index 5c6e3ae479..51164e8042 100644 --- a/cognite/client/_api/simulators/models_revisions.py +++ b/cognite/client/_api/simulators/models_revisions.py @@ -73,8 +73,8 @@ async def list( >>> res = client.simulators.models.revisions.list( ... model_external_ids=["model1", "model2"], ... all_versions=True, - ... created_time=TimestampRange(min=0, max=1000000), - ... last_updated_time=TimestampRange(min=0, max=1000000), + ... created_time=TimestampRange(min="1d-ago", max="now"), + ... last_updated_time=TimestampRange(min="1d-ago", max="now"), ... sort=PropertySort(order="asc", property="createdTime"), ... limit=10 ... ) diff --git a/cognite/client/_api/simulators/runs.py b/cognite/client/_api/simulators/runs.py index 57e6309616..c9086fd5ca 100644 --- a/cognite/client/_api/simulators/runs.py +++ b/cognite/client/_api/simulators/runs.py @@ -196,8 +196,8 @@ async def list( Filter runs by time ranges: >>> from cognite.client.data_classes.shared import TimestampRange >>> res = client.simulators.runs.list( - ... created_time=TimestampRange(min=0, max=1_700_000_000_000), - ... simulation_time=TimestampRange(min=0, max=1_700_000_000_000), + ... created_time=TimestampRange(min="1d-ago", max="now"), + ... simulation_time=TimestampRange(min="1d-ago", max="now"), ... ) """ diff --git a/cognite/client/_sync_api/simulators/models_revisions.py b/cognite/client/_sync_api/simulators/models_revisions.py index 09593107c8..a7d9b0c47e 100644 --- a/cognite/client/_sync_api/simulators/models_revisions.py +++ b/cognite/client/_sync_api/simulators/models_revisions.py @@ -1,6 +1,6 @@ """ =============================================================================== -1d02275dfbb16469b08dc17b88cc9d14 +13a7de2b1a61099448b86ddf1135519c This file is auto-generated from the Async API modules, - do not edit manually! =============================================================================== """ @@ -72,8 +72,8 @@ def list( >>> res = client.simulators.models.revisions.list( ... model_external_ids=["model1", "model2"], ... all_versions=True, - ... created_time=TimestampRange(min=0, max=1000000), - ... last_updated_time=TimestampRange(min=0, max=1000000), + ... created_time=TimestampRange(min="1d-ago", max="now"), + ... last_updated_time=TimestampRange(min="1d-ago", max="now"), ... sort=PropertySort(order="asc", property="createdTime"), ... limit=10 ... ) diff --git a/cognite/client/_sync_api/simulators/runs.py b/cognite/client/_sync_api/simulators/runs.py index 5f687a8491..247f5aca46 100644 --- a/cognite/client/_sync_api/simulators/runs.py +++ b/cognite/client/_sync_api/simulators/runs.py @@ -1,6 +1,6 @@ """ =============================================================================== -627f42fbdbc933e30799270aba58ef0d +8368bdd19f65023e757c7ab61239919c This file is auto-generated from the Async API modules, - do not edit manually! =============================================================================== """ @@ -184,8 +184,8 @@ def list( Filter runs by time ranges: >>> from cognite.client.data_classes.shared import TimestampRange >>> res = client.simulators.runs.list( - ... created_time=TimestampRange(min=0, max=1_700_000_000_000), - ... simulation_time=TimestampRange(min=0, max=1_700_000_000_000), + ... created_time=TimestampRange(min="1d-ago", max="now"), + ... simulation_time=TimestampRange(min="1d-ago", max="now"), ... ) """ return run_sync( From 199165bd3e2ce3d2515d5975da971aba9e2124ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Gr=C3=B8nbech?= Date: Tue, 24 Feb 2026 21:24:29 +0100 Subject: [PATCH 7/7] Fix failing Github Actions --- poetry.lock | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/poetry.lock b/poetry.lock index 27e7ba3eb9..054c2de432 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3330,14 +3330,14 @@ zstd = ["backports-zstd (>=1.0.0) ; python_version < \"3.14\""] [[package]] name = "virtualenv" -version = "20.37.0" +version = "20.39.0" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "virtualenv-20.37.0-py3-none-any.whl", hash = "sha256:5d3951c32d57232ae3569d4de4cc256c439e045135ebf43518131175d9be435d"}, - {file = "virtualenv-20.37.0.tar.gz", hash = "sha256:6f7e2064ed470aa7418874e70b6369d53b66bcd9e9fd5389763e96b6c94ccb7c"}, + {file = "virtualenv-20.39.0-py3-none-any.whl", hash = "sha256:44888bba3775990a152ea1f73f8e5f566d49f11bbd1de61d426fd7732770043e"}, + {file = "virtualenv-20.39.0.tar.gz", hash = "sha256:a15f0cebd00d50074fd336a169d53422436a12dfe15149efec7072cfe817df8b"}, ] [package.dependencies] @@ -3346,10 +3346,6 @@ filelock = {version = ">=3.24.2,<4", markers = "python_version >= \"3.10\""} platformdirs = ">=3.9.1,<5" typing-extensions = {version = ">=4.13.2", markers = "python_version < \"3.11\""} -[package.extras] -docs = ["furo (>=2023.7.26)", "pre-commit-uv (>=4.1.4)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinx-autodoc-typehints (>=3.6.2)", "sphinx-copybutton (>=0.5.2)", "sphinx-inline-tabs (>=2025.12.21.14)", "sphinxcontrib-mermaid (>=2)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8) ; platform_python_implementation == \"PyPy\" or platform_python_implementation == \"GraalVM\" or platform_python_implementation == \"CPython\" and sys_platform == \"win32\" and python_version >= \"3.13\"", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "pytest-xdist (>=3.5)", "setuptools (>=68)", "time-machine (>=2.10) ; platform_python_implementation == \"CPython\""] - [[package]] name = "wcwidth" version = "0.6.0"