time-split 1.0.3__tar.gz → 1.0.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. {time_split-1.0.3 → time_split-1.0.5}/PKG-INFO +1 -1
  2. {time_split-1.0.3 → time_split-1.0.5}/pyproject.toml +9 -9
  3. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/__init__.py +1 -5
  4. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/_backend/__init__.py +2 -1
  5. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/_backend/_limits.py +20 -1
  6. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/_frontend/_to_string.py +50 -6
  7. {time_split-1.0.3 → time_split-1.0.5}/LICENSE.md +0 -0
  8. {time_split-1.0.3 → time_split-1.0.5}/README.md +0 -0
  9. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/__main__.py +0 -0
  10. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/_backend/_datetime_index_like.py +0 -0
  11. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/_backend/_process_available.py +0 -0
  12. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/_backend/_schedule.py +0 -0
  13. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/_backend/_span.py +0 -0
  14. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/_backend/_splitter.py +0 -0
  15. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/_docstrings.py +0 -0
  16. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/_frontend/__init__.py +0 -0
  17. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/_frontend/_plot.py +0 -0
  18. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/_frontend/_progress.py +0 -0
  19. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/_frontend/_split.py +0 -0
  20. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/_frontend/_weight.py +0 -0
  21. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/_support.py +0 -0
  22. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/app/__init__.py +0 -0
  23. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/app/_create_explorer_link.py +0 -0
  24. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/app/reexport/__init__.py +0 -0
  25. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/cli.py +0 -0
  26. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/integration/__init__.py +0 -0
  27. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/integration/_log_progress.py +0 -0
  28. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/integration/base.py +0 -0
  29. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/integration/pandas/__init__.py +0 -0
  30. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/integration/pandas/_impl.py +0 -0
  31. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/integration/polars/__init__.py +0 -0
  32. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/integration/polars/_impl.py +0 -0
  33. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/integration/sklearn/__init__.py +0 -0
  34. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/integration/sklearn/_impl.py +0 -0
  35. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/py.typed +0 -0
  36. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/settings.py +0 -0
  37. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/support/__init__.py +0 -0
  38. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/support/types.py +0 -0
  39. {time_split-1.0.3 → time_split-1.0.5}/src/time_split/types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: time-split
3
- Version: 1.0.3
3
+ Version: 1.0.5
4
4
  Summary: Time-based k-fold validation splits for heterogeneous data.
5
5
  License: MIT
6
6
  License-File: LICENSE.md
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "time-split"
3
- version = "1.0.3"
3
+ version = "1.0.5"
4
4
  description = "Time-based k-fold validation splits for heterogeneous data."
5
5
  authors = [
6
6
  { name = "Richard Sundqvist", email = "richard.sundqvist@live.se" },
@@ -53,7 +53,7 @@ poetry-plugin-export = ">=1.8"
53
53
  # Extras that must be available for docs + tests go here. Doc/test-only deps go in their respective groups.
54
54
  croniter = "~6.0.0"
55
55
  pyarrow = "~22.0.0"
56
- polars = { version = "~1.34.0", extras = ["pandas"] }
56
+ polars = { version = "~1.35.2", extras = ["pandas"] }
57
57
 
58
58
  [tool.poetry.group.docs]
59
59
  [tool.poetry.group.docs.dependencies]
@@ -61,10 +61,10 @@ polars = { version = "~1.34.0", extras = ["pandas"] }
61
61
  # description: https://github.com/astropy/astropy/issues/11723
62
62
  # https://github.com/astropy/astropy/pull/12270
63
63
  sphinx = "~8.1.3" # 8.2 breaks xdoc refs in README.md; maybe https://github.com/sphinx-doc/sphinx/issues/13932?
64
- sphinx-gallery = "~0.19.0"
64
+ sphinx-gallery = "~0.20.0"
65
65
  pydata-sphinx-theme = "~0.16.1"
66
66
  myst-parser = "~4.0.1"
67
- ipython = "~9.6.0"
67
+ ipython = "~9.8.0"
68
68
 
69
69
  [tool.poetry.group.notebooks]
70
70
  optional = true
@@ -75,9 +75,9 @@ jupyterlab-execute-time = "*"
75
75
  tqdm = "*"
76
76
 
77
77
  [tool.poetry.group.test.dependencies]
78
- pytest = "~8.4.2"
78
+ pytest = "~9.0.1"
79
79
  xdoctest = "~1.3.0"
80
- coverage = "~7.11.0"
80
+ coverage = "~7.12.0"
81
81
  pytest-cov = "~7.0.0"
82
82
 
83
83
  scikit-learn = "~1.7.2"
@@ -85,10 +85,10 @@ dask = { version = "~2025.10.0", extras = ["dataframe"] }
85
85
 
86
86
  [tool.poetry.group.devops.dependencies]
87
87
  invoke = "~2.2.1"
88
- mypy = "~1.18.2"
89
- ruff = "~0.14.2"
88
+ mypy = "~1.19.0"
89
+ ruff = "~0.14.8"
90
90
 
91
- safety = "~3.6.2"
91
+ safety = "~3.7.0"
92
92
  codespell = "~2.4.1"
93
93
  bump2version = "~1.0.1"
94
94
 
@@ -1,7 +1,5 @@
1
1
  """Time-based k-fold validation splits for heterogeneous data."""
2
2
 
3
- import logging as _logging
4
-
5
3
  from ._frontend import log_split_progress, plot, split
6
4
 
7
5
  __all__ = [
@@ -11,6 +9,4 @@ __all__ = [
11
9
  "split",
12
10
  ]
13
11
 
14
- __version__ = "1.0.3"
15
-
16
- _logging.getLogger(__name__).addHandler(_logging.NullHandler())
12
+ __version__ = "1.0.5"
@@ -1,5 +1,5 @@
1
1
  from ._datetime_index_like import DatetimeIndexLike
2
- from ._limits import expand_limits
2
+ from ._limits import expand_limits, is_limits_tuple
3
3
  from ._process_available import ProcessAvailableResult, process_available
4
4
  from ._splitter import DatetimeIndexSplitter
5
5
 
@@ -8,5 +8,6 @@ __all__ = [
8
8
  "DatetimeIndexSplitter",
9
9
  "ProcessAvailableResult",
10
10
  "expand_limits",
11
+ "is_limits_tuple",
11
12
  "process_available",
12
13
  ]
@@ -1,6 +1,6 @@
1
1
  from collections.abc import Iterable
2
2
  from itertools import starmap
3
- from typing import NamedTuple
3
+ from typing import Any, NamedTuple, TypeGuard
4
4
 
5
5
  from pandas import Timedelta, Timestamp
6
6
 
@@ -17,6 +17,25 @@ class _TimedeltaTuple(NamedTuple):
17
17
  tolerance: Timedelta
18
18
 
19
19
 
20
+ def is_limits_tuple(arg: Any) -> TypeGuard[LimitsTuple]:
21
+ """Check if `arg` is a :class:`.LimitsTuple`.
22
+
23
+ Args:
24
+ arg: An argument.
25
+
26
+ Returns:
27
+ Returns ``True`` if `arg` is a :class:`.LimitsTuple`.
28
+ """
29
+ if not (isinstance(arg, tuple) and len(arg) == 2): # noqa: PLR2004
30
+ return False
31
+
32
+ start, end = arg
33
+ if not (isinstance(start, Timestamp) and isinstance(end, Timestamp)):
34
+ return False
35
+
36
+ return bool(start <= end)
37
+
38
+
20
39
  def expand_limits(
21
40
  limits: LimitsTuple,
22
41
  spec: ExpandLimits | LevelTuple | Iterable[LevelTuple] = "auto",
@@ -4,9 +4,10 @@ from typing import Any, Literal, overload
4
4
  from pandas import Timestamp
5
5
  from rics.strings import format_seconds as fmt_sec
6
6
 
7
+ from .._backend import is_limits_tuple, process_available
7
8
  from .._backend._limits import LimitsTuple
8
9
  from ..settings import log_split_progress
9
- from ..types import DatetimeSplitBounds, DatetimeTypes, ExpandLimits
10
+ from ..types import DatetimeIterable, DatetimeSplitBounds, DatetimeTypes, ExpandLimits
10
11
 
11
12
 
12
13
  @overload
@@ -163,10 +164,11 @@ class _PrettyTimestamp:
163
164
 
164
165
 
165
166
  def format_expanded_limits(
166
- original: LimitsTuple,
167
+ original: LimitsTuple | DatetimeIterable,
167
168
  *,
168
169
  expanded: LimitsTuple | None = None,
169
- expand_limits: ExpandLimits,
170
+ expand_limits: ExpandLimits = "auto",
171
+ raise_if_same: bool = False,
170
172
  ) -> str:
171
173
  """Format expanded limits.
172
174
 
@@ -174,14 +176,56 @@ def format_expanded_limits(
174
176
  original: The original data limits.
175
177
  expanded: Expanded data limits. Derived based on `original` and `expanded_limits` if ``None``.
176
178
  expand_limits: Limits expansion spec.
179
+ raise_if_same: If ``True``, raise a :exc:`ValueError` if the `original` and `expanded_limits` are not the same.
180
+ Otherwise, a different message will be returned instead.
177
181
 
178
182
  Returns:
179
183
  A string.
184
+
185
+ Raises:
186
+ ValueError: If ``raise_on_same`` is ``True`` and ``original == expanded``.
187
+
188
+ Examples:
189
+ Basic usage.
190
+
191
+ >>> limits = "2019-05-11", "2019-05-11 22:05:30"
192
+ >>> string = format_expanded_limits(limits, expand_limits="d<3h")
193
+ >>> print(string)
194
+ Available data limits have been expanded (since expand_limits='d<3h'):
195
+ start: 2019-05-11 00:00:00 -> <no change>
196
+ end: 2019-05-11 22:05:30 -> 2019-05-12 (+1h 54m 30s)
197
+
198
+ A different message is shown when the limits aren't expanded.
199
+
200
+ >>> string = format_expanded_limits(limits, expand_limits="d<1h")
201
+ >>> print(string)
202
+ Original limits ('2019-05-11', '2019-05-11 22:05:30') were not expanded (since expand_limits='d<1h').
203
+
204
+ Set ``raise_if_same=True`` to disable the second message.
205
+
206
+ See Also:
207
+ The :func:`.process_available` and :func:`.expand_limits` functions.
180
208
  """
181
209
  if expanded is None:
182
- from .._backend._limits import expand_limits as expand
183
-
184
- expanded = expand(original, spec=expand_limits)
210
+ if is_limits_tuple(original):
211
+ from .._backend._limits import expand_limits as expand
212
+
213
+ expanded = expand(original, spec=expand_limits)
214
+ else:
215
+ result = process_available(original, expand_limits=expand_limits)
216
+ original = result.limits
217
+ expanded = result.expanded_limits
218
+
219
+ if not is_limits_tuple(original):
220
+ msg = f"Bad {original=}; not a valid limits tuple."
221
+ raise TypeError(msg)
222
+
223
+ if original == expanded:
224
+ left, right = stringify(original[0]), stringify(original[1])
225
+ msg = f"Original limits {(left, right)} were not expanded (since {expand_limits=})."
226
+ if raise_if_same:
227
+ raise ValueError(msg)
228
+ return msg
185
229
 
186
230
  return (
187
231
  f"Available data limits have been expanded (since {expand_limits=}):\n"
File without changes
File without changes