time-split 0.5.0__tar.gz → 0.7.0__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 (68) hide show
  1. {time_split-0.5.0 → time_split-0.7.0}/PKG-INFO +30 -23
  2. {time_split-0.5.0 → time_split-0.7.0}/README.md +11 -8
  3. {time_split-0.5.0 → time_split-0.7.0}/pyproject.toml +56 -61
  4. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/__init__.py +2 -2
  5. time_split-0.7.0/src/time_split/__main__.py +9 -0
  6. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/_backend/_limits.py +15 -7
  7. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/_backend/_schedule.py +2 -2
  8. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/_backend/_splitter.py +1 -23
  9. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/_docstrings.py +2 -9
  10. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/_frontend/_plot.py +15 -5
  11. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/_frontend/_progress.py +2 -3
  12. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/_frontend/_to_string.py +64 -26
  13. time_split-0.7.0/src/time_split/app/__init__.py +11 -0
  14. {time_split-0.5.0/src/time_split/support → time_split-0.7.0/src/time_split/app}/_create_explorer_link.py +16 -10
  15. time_split-0.7.0/src/time_split/cli.py +29 -0
  16. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/settings.py +30 -0
  17. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/support/__init__.py +3 -5
  18. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/types.py +3 -1
  19. time_split-0.5.0/src/time_split/_compat.py +0 -49
  20. time_split-0.5.0/src/time_split/streamlit/README.md +0 -82
  21. time_split-0.5.0/src/time_split/streamlit/__init__.py +0 -1
  22. time_split-0.5.0/src/time_split/streamlit/_logging.py +0 -75
  23. time_split-0.5.0/src/time_split/streamlit/_support.py +0 -67
  24. time_split-0.5.0/src/time_split/streamlit/_views.py +0 -125
  25. time_split-0.5.0/src/time_split/streamlit/config.py +0 -68
  26. time_split-0.5.0/src/time_split/streamlit/widgets/__init__.py +0 -1
  27. time_split-0.5.0/src/time_split/streamlit/widgets/data/__init__.py +0 -7
  28. time_split-0.5.0/src/time_split/streamlit/widgets/data/_data.py +0 -336
  29. time_split-0.5.0/src/time_split/streamlit/widgets/data/_datasets.py +0 -123
  30. time_split-0.5.0/src/time_split/streamlit/widgets/data/_sample_data.py +0 -147
  31. time_split-0.5.0/src/time_split/streamlit/widgets/data/load.py +0 -111
  32. time_split-0.5.0/src/time_split/streamlit/widgets/data/sample.csv +0 -397
  33. time_split-0.5.0/src/time_split/streamlit/widgets/display/__init__.py +0 -15
  34. time_split-0.5.0/src/time_split/streamlit/widgets/display/_aggregate.py +0 -227
  35. time_split-0.5.0/src/time_split/streamlit/widgets/display/_code.py +0 -175
  36. time_split-0.5.0/src/time_split/streamlit/widgets/display/_overview.py +0 -51
  37. time_split-0.5.0/src/time_split/streamlit/widgets/display/_performance.py +0 -176
  38. time_split-0.5.0/src/time_split/streamlit/widgets/display/_plot_folds.py +0 -92
  39. time_split-0.5.0/src/time_split/streamlit/widgets/parameters/__init__.py +0 -21
  40. time_split-0.5.0/src/time_split/streamlit/widgets/parameters/_datetime.py +0 -30
  41. time_split-0.5.0/src/time_split/streamlit/widgets/parameters/_duration.py +0 -78
  42. time_split-0.5.0/src/time_split/streamlit/widgets/parameters/_expand_limits.py +0 -141
  43. time_split-0.5.0/src/time_split/streamlit/widgets/parameters/_schedule.py +0 -135
  44. time_split-0.5.0/src/time_split/streamlit/widgets/parameters/_schedule_filter.py +0 -43
  45. time_split-0.5.0/src/time_split/streamlit/widgets/parameters/_span.py +0 -122
  46. time_split-0.5.0/src/time_split/streamlit/widgets/parameters/_splitter_kwargs.py +0 -29
  47. time_split-0.5.0/src/time_split/streamlit/widgets/ruff.toml +0 -6
  48. time_split-0.5.0/src/time_split/streamlit/widgets/types.py +0 -351
  49. {time_split-0.5.0 → time_split-0.7.0}/LICENSE.md +0 -0
  50. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/_backend/__init__.py +1 -1
  51. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/_backend/_datetime_index_like.py +0 -0
  52. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/_backend/_process_available.py +0 -0
  53. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/_backend/_span.py +0 -0
  54. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/_frontend/__init__.py +2 -2
  55. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/_frontend/_split.py +0 -0
  56. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/_frontend/_weight.py +0 -0
  57. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/_support.py +0 -0
  58. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/integration/__init__.py +0 -0
  59. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/integration/_log_progress.py +0 -0
  60. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/integration/base.py +0 -0
  61. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/integration/pandas/__init__.py +0 -0
  62. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/integration/pandas/_impl.py +0 -0
  63. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/integration/polars/__init__.py +0 -0
  64. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/integration/polars/_impl.py +0 -0
  65. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/integration/sklearn/__init__.py +0 -0
  66. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/integration/sklearn/_impl.py +0 -0
  67. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/py.typed +0 -0
  68. {time_split-0.5.0 → time_split-0.7.0}/src/time_split/support/types.py +0 -0
@@ -1,34 +1,38 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: time-split
3
- Version: 0.5.0
3
+ Version: 0.7.0
4
4
  Summary: Time-based k-fold validation splits for heterogeneous data.
5
- Home-page: https://github.com/rsundqvist/time-split
5
+ License: MIT
6
+ Keywords: hyper,parameter,optimization,cross,validation,time,temporal,heterogenous,data
6
7
  Author: Richard Sundqvist
7
8
  Author-email: richard.sundqvist@live.se
8
9
  Requires-Python: >=3.11
9
- Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Development Status :: 4 - Beta
10
11
  Classifier: Intended Audience :: Developers
11
12
  Classifier: Intended Audience :: Science/Research
12
- Classifier: License :: OSI Approved :: MIT License
13
- Classifier: Natural Language :: English
13
+ Classifier: Operating System :: POSIX :: Linux
14
14
  Classifier: Operating System :: MacOS
15
15
  Classifier: Operating System :: Microsoft :: Windows
16
- Classifier: Operating System :: POSIX :: Linux
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Natural Language :: English
18
+ Classifier: Typing :: Typed
17
19
  Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3 :: Only
18
21
  Classifier: Programming Language :: Python :: 3.11
19
22
  Classifier: Programming Language :: Python :: 3.12
20
- Classifier: Programming Language :: Python :: 3 :: Only
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Provides-Extra: app
21
25
  Provides-Extra: plotting
22
- Provides-Extra: streamlit
23
- Requires-Dist: croniter ; extra == "streamlit"
24
- Requires-Dist: matplotlib ; extra == "plotting" or extra == "streamlit"
26
+ Requires-Dist: click ; extra == "app"
27
+ Requires-Dist: matplotlib ; extra == "plotting"
25
28
  Requires-Dist: pandas (>=2.0.3)
26
- Requires-Dist: rics (>=4.1.1)
27
- Requires-Dist: seaborn ; extra == "plotting" or extra == "streamlit"
28
- Requires-Dist: streamlit ; extra == "streamlit"
29
+ Requires-Dist: rics (>=6.0.1)
30
+ Requires-Dist: seaborn ; extra == "plotting"
31
+ Requires-Dist: time-split-app ; extra == "app"
29
32
  Project-URL: Bug Tracker, https://github.com/rsundqvist/time-split/issues
30
33
  Project-URL: Changelog, https://github.com/rsundqvist/time-split/blob/master/CHANGELOG.md
31
- Project-URL: Documentation, https://time-split.readthedocs.io
34
+ Project-URL: Documentation, https://time-split
35
+ Project-URL: Homepage, https://github.com/rsundqvist/time-split
32
36
  Project-URL: Repository, https://github.com/rsundqvist/time-split
33
37
  Description-Content-Type: text/markdown
34
38
 
@@ -64,26 +68,29 @@ strong non-stationary characteristics.
64
68
  schedule itself.
65
69
  - Automatically extract and [normalize](https://time-split.readthedocs.io/en/stable/guide/expand_limits.html) data limits for
66
70
  supported data types.
67
- - [Plotting function](https://time-split.readthedocs.io/en/stable/generated/time_split.html#time_split.plot) for
71
+ - [Plotting function](https://time-split.readthedocs.io/en/stable/api/time_split.html#time_split.plot) for
68
72
  visualization of folds. Display fold sizes (hour/row count), or
69
73
  [use custom text](https://time-split.readthedocs.io/en/stable/auto_examples/plotting_with_metrics.html).
70
- - [Integrations](https://time-split.readthedocs.io/en/stable/generated/time_split.integration.html) for popular
74
+ - [Integrations](https://time-split.readthedocs.io/en/stable/api/time_split.integration.html) for popular
71
75
  libraries such as `pandas`, `polars` and `scikit-learn`.
72
76
  - Convenient [web application](#experimenting-with-parameters) for exploring folds with different parameters.
73
77
 
74
78
  ## Experimenting with parameters
75
- The **Time Fold Explorer** application
76
- (available [here](http://20.240.208.202/time-split/?data=1554942900-1557610200&schedule=0+0+%2A+%2A+MON%2CFRI&n_splits=2&step=2&show_removed=True))
79
+ The **Time Split** application
80
+ (available [here](https://time-split.streamlit.app/?data=1554942900-1557610200&schedule=0+0+%2A+%2A+MON%2CFRI&n_splits=2&step=2&show_removed=True))
77
81
  is designed to help evaluate the effects of different
78
82
  [parameters](https://time-split.readthedocs.io/en/stable/#parameter-overview).
79
- To start it locally using
80
- [![Docker Image Size (tag)](https://img.shields.io/docker/image-size/rsundqvist/time-split/latest?logo=docker&label=time-split)](https://hub.docker.com/r/rsundqvist/time-split/)
81
- Docker, run
83
+ To start it locally, run
82
84
  ```sh
83
85
  docker run -p 8501:8501 rsundqvist/time-split
84
86
  ```
87
+ or
88
+ ```bash
89
+ pip install time-split[app]
90
+ python -m time_split app start
91
+ ```
85
92
  in the terminal. You may use
86
- [`create_explorer_link()`](https://time-split.readthedocs.io/en/stable/generated/time_split.support.html#time_split.support.create_explorer_link)
93
+ [`create_explorer_link()`](https://time-split.readthedocs.io/en/stable/api/time_split.app.html#time_split.app.create_explorer_link)
87
94
  to build application URLs with preselected splitting parameters.
88
95
 
89
96
  ## Installation
@@ -30,26 +30,29 @@ strong non-stationary characteristics.
30
30
  schedule itself.
31
31
  - Automatically extract and [normalize](https://time-split.readthedocs.io/en/stable/guide/expand_limits.html) data limits for
32
32
  supported data types.
33
- - [Plotting function](https://time-split.readthedocs.io/en/stable/generated/time_split.html#time_split.plot) for
33
+ - [Plotting function](https://time-split.readthedocs.io/en/stable/api/time_split.html#time_split.plot) for
34
34
  visualization of folds. Display fold sizes (hour/row count), or
35
35
  [use custom text](https://time-split.readthedocs.io/en/stable/auto_examples/plotting_with_metrics.html).
36
- - [Integrations](https://time-split.readthedocs.io/en/stable/generated/time_split.integration.html) for popular
36
+ - [Integrations](https://time-split.readthedocs.io/en/stable/api/time_split.integration.html) for popular
37
37
  libraries such as `pandas`, `polars` and `scikit-learn`.
38
38
  - Convenient [web application](#experimenting-with-parameters) for exploring folds with different parameters.
39
39
 
40
40
  ## Experimenting with parameters
41
- The **Time Fold Explorer** application
42
- (available [here](http://20.240.208.202/time-split/?data=1554942900-1557610200&schedule=0+0+%2A+%2A+MON%2CFRI&n_splits=2&step=2&show_removed=True))
41
+ The **Time Split** application
42
+ (available [here](https://time-split.streamlit.app/?data=1554942900-1557610200&schedule=0+0+%2A+%2A+MON%2CFRI&n_splits=2&step=2&show_removed=True))
43
43
  is designed to help evaluate the effects of different
44
44
  [parameters](https://time-split.readthedocs.io/en/stable/#parameter-overview).
45
- To start it locally using
46
- [![Docker Image Size (tag)](https://img.shields.io/docker/image-size/rsundqvist/time-split/latest?logo=docker&label=time-split)](https://hub.docker.com/r/rsundqvist/time-split/)
47
- Docker, run
45
+ To start it locally, run
48
46
  ```sh
49
47
  docker run -p 8501:8501 rsundqvist/time-split
50
48
  ```
49
+ or
50
+ ```bash
51
+ pip install time-split[app]
52
+ python -m time_split app start
53
+ ```
51
54
  in the terminal. You may use
52
- [`create_explorer_link()`](https://time-split.readthedocs.io/en/stable/generated/time_split.support.html#time_split.support.create_explorer_link)
55
+ [`create_explorer_link()`](https://time-split.readthedocs.io/en/stable/api/time_split.app.html#time_split.app.create_explorer_link)
53
56
  to build application URLs with preselected splitting parameters.
54
57
 
55
58
  ## Installation
@@ -1,15 +1,15 @@
1
- [tool.poetry]
1
+ [project]
2
2
  name = "time-split"
3
- version = "0.5.0"
3
+ version = "0.7.0"
4
4
  description = "Time-based k-fold validation splits for heterogeneous data."
5
- authors = ["Richard Sundqvist <richard.sundqvist@live.se>"]
6
-
5
+ authors = [
6
+ { name = "Richard Sundqvist", email = "richard.sundqvist@live.se" },
7
+ ]
8
+ license = { text = "MIT" }
7
9
  readme = "README.md"
8
- homepage = "https://github.com/rsundqvist/time-split"
9
- repository = "https://github.com/rsundqvist/time-split"
10
- documentation = "https://time-split.readthedocs.io"
10
+ keywords = ["hyper", "parameter", "optimization", "cross", "validation", "time", "temporal", "heterogenous", "data"]
11
11
  classifiers = [
12
- "Development Status :: 3 - Alpha",
12
+ "Development Status :: 4 - Beta",
13
13
  "Intended Audience :: Developers",
14
14
  "Intended Audience :: Science/Research",
15
15
  "Operating System :: POSIX :: Linux",
@@ -17,55 +17,54 @@ classifiers = [
17
17
  "Operating System :: Microsoft :: Windows",
18
18
  "License :: OSI Approved :: MIT License",
19
19
  "Natural Language :: English",
20
+ "Typing :: Typed",
20
21
  "Programming Language :: Python :: 3",
21
22
  "Programming Language :: Python :: 3 :: Only",
22
23
  "Programming Language :: Python :: 3.11",
23
24
  "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
24
26
  ]
27
+ requires-python = ">=3.11"
25
28
 
29
+ dependencies = [
30
+ "pandas >= 2.0.3",
31
+ "rics >= 6.0.1",
32
+ ]
26
33
 
27
- [tool.poetry.urls]
34
+ [project.optional-dependencies]
35
+ app = ["click", "time-split-app"] # Constraints managed by app.
36
+ plotting = ["matplotlib", "seaborn"]
37
+
38
+ [project.urls]
39
+ homepage = "https://github.com/rsundqvist/time-split"
40
+ repository = "https://github.com/rsundqvist/time-split"
41
+ documentation = "https://time-split"
28
42
  "Bug Tracker" = "https://github.com/rsundqvist/time-split/issues"
29
43
  "Changelog" = "https://github.com/rsundqvist/time-split/blob/master/CHANGELOG.md"
30
44
 
31
- [tool.poetry.scripts]
45
+ [project.entry-points."rics.cli"]
46
+ time-split = "time_split.cli:main"
32
47
 
33
- [tool.poetry.dependencies]
34
- python = ">=3.11"
35
-
36
- pandas = ">=2.0.3"
37
- rics = ">=4.1.1"
38
-
39
- # plotting
40
- matplotlib = { version = "*", optional = true }
41
- seaborn = { version = "*", optional = true }
42
-
43
- # explorer
44
- streamlit = { version = "*", optional = true }
45
- croniter = { version = "*", optional = true }
46
-
47
- [tool.poetry.extras]
48
- plotting = ["matplotlib", "seaborn"]
49
- streamlit = ["matplotlib", "seaborn", "streamlit", "croniter"]
48
+ [tool.poetry.requires-plugins]
49
+ poetry-plugin-export = ">=1.8"
50
50
 
51
51
  [tool.poetry.group.manual-extras.dependencies]
52
52
  # Extras that must be available for docs + tests go here. Doc/test-only deps go in their respective groups.
53
- croniter = "^2.0.3"
54
- pyarrow = ">=15.0.2,<17.0.0"
55
- polars = { version = "^0.20.19", extras = ["pandas"] }
56
- streamlit = "*"
53
+ croniter = "^6.0.0"
54
+ pyarrow = "^19.0.0"
55
+ polars = { version = "^1.21.0", extras = ["pandas"] }
57
56
 
58
57
  [tool.poetry.group.docs]
59
58
  [tool.poetry.group.docs.dependencies]
60
59
  # duplicate object warnings for sphinx>=4
61
60
  # description: https://github.com/astropy/astropy/issues/11723
62
61
  # https://github.com/astropy/astropy/pull/12270
63
- sphinx = "^7.2.6"
64
- sphinx-gallery = "^0.16.0"
65
- pydata-sphinx-theme = "^0.15.2"
66
- myst-parser = ">=2,<4"
67
- nbsphinx = "^0.9.3"
68
- ipython = "^8.23.0"
62
+ sphinx = "~8.1.3"
63
+ sphinx-gallery = "^0.18.0"
64
+ pydata-sphinx-theme = "^0.16.1"
65
+ myst-parser = "^4.0.0"
66
+ nbsphinx = "^0.9.6"
67
+ ipython = "^8.31.0"
69
68
 
70
69
  [tool.poetry.group.notebooks]
71
70
  optional = true
@@ -76,26 +75,22 @@ jupyterlab-execute-time = "*"
76
75
  tqdm = "*"
77
76
 
78
77
  [tool.poetry.group.test.dependencies]
79
- pytest = "^8.1.1"
80
- xdoctest = "^1.1.3"
81
- coverage = "^7.4.4"
82
- pytest-cov = "^5.0.0"
83
-
84
- scikit-learn = "^1.4.2"
85
- # TODO Unpin.
86
- # dask.datasets.timeseries() warns:
87
- # UserWarning: dask_expr does not support the DataFrameIOFunction protocol for column projection
88
- # on dask == 2024.3.1
89
- dask = { version = "==2024.5.0", extras = ["dataframe"] }
78
+ pytest = "^8.3.4"
79
+ xdoctest = "^1.2.0"
80
+ coverage = "^7.6.10"
81
+ pytest-cov = "^6.0.0"
82
+
83
+ scikit-learn = "^1.6.1"
84
+ dask = { version = "^2025.1.0", extras = ["dataframe"] }
90
85
 
91
86
  [tool.poetry.group.devops.dependencies]
92
- invoke = "^2.2.0"
93
- mypy = "^1.10.1"
94
- ruff = "^0.5.0"
87
+ invoke = "~2.2.0"
88
+ mypy = "~1.17.0"
89
+ ruff = "~0.12.3"
95
90
 
96
- safety = "^3.2.3"
97
- codespell = "^2.3.0"
98
- bump2version = "^1.0.1"
91
+ safety = "~3.5.1"
92
+ codespell = "~2.4.1"
93
+ bump2version = "~1.0.1"
99
94
 
100
95
  [tool.ruff]
101
96
  line-length = 120
@@ -140,8 +135,6 @@ select = [
140
135
  "TRY",
141
136
  ]
142
137
  ignore = [
143
- "ANN101", # Missing type annotation for `self` in method
144
- "ANN102", # Missing type annotation for `cls` in method
145
138
  "D105", # Missing docstring in magic method
146
139
  "D107", # Missing docstring in `__init__`
147
140
  "ANN401",
@@ -152,8 +145,9 @@ ignore = [
152
145
  "PLR0913", #
153
146
  "SIM108", # Use ternary operator - coverage issue, see https://github.com/nedbat/coveragepy/issues/509
154
147
  "TD003", # Missing issue link
148
+ "TC006", # Add quotes to type expression in `typing.cast()`
149
+ "UP038", # https://github.com/astral-sh/ruff/issues/7871
155
150
  ]
156
- allowed-confusables = ["ℹ"]
157
151
 
158
152
  [tool.ruff.lint.per-file-ignores]
159
153
  "tests/*" = [
@@ -174,6 +168,10 @@ allowed-confusables = ["ℹ"]
174
168
  "ARG002", # Unused method argument: `groups`
175
169
  ]
176
170
 
171
+ "**/time_split/app/*" = [
172
+ "S101" # Allow 'assert' keyword
173
+ ]
174
+
177
175
  [tool.ruff.lint.pydocstyle]
178
176
  convention = "google"
179
177
  [tool.ruff.lint.pycodestyle]
@@ -184,13 +182,10 @@ max-line-length = 150
184
182
  filterwarnings = [
185
183
  "error",
186
184
  "ignore:Matplotlib is currently using agg:UserWarning",
187
- "ignore:.*utcfromtimestamp.*:DeprecationWarning", # Detta är farligt - ta bort
185
+ "ignore:.*'mode' parameter.*Pillow 13.*:DeprecationWarning",
188
186
  ]
189
187
  log_file_level = 10
190
188
  log_file = "pytest.log"
191
- norecursedirs = [
192
- "**/cli_modules/*",
193
- ]
194
189
 
195
190
  [build-system]
196
191
  requires = ["poetry-core>=1.0.8"]
@@ -5,12 +5,12 @@ import logging as _logging
5
5
  from ._frontend import log_split_progress, plot, split
6
6
 
7
7
  __all__ = [
8
+ "__version__", # Make MyPy happy
8
9
  "log_split_progress",
9
10
  "plot",
10
11
  "split",
11
- "__version__", # Make MyPy happy
12
12
  ]
13
13
 
14
- __version__ = "0.5.0"
14
+ __version__ = "0.7.0"
15
15
 
16
16
  _logging.getLogger(__name__).addHandler(_logging.NullHandler())
@@ -0,0 +1,9 @@
1
+ """Alias of :mod:`time_split.cli`.
2
+
3
+ As per, https://docs.python.org/3.13/library/__main__.html#id1,
4
+ this file doesn't use a ``if __name__ == "__main__"``-block.
5
+ """
6
+
7
+ from .cli import main
8
+
9
+ main()
@@ -4,7 +4,7 @@ from typing import NamedTuple
4
4
 
5
5
  from pandas import Timedelta, Timestamp
6
6
 
7
- from ..settings import auto_expand_limits
7
+ from ..settings import auto_expand_limits, misc
8
8
  from ..types import ExpandLimits, TimedeltaTypes
9
9
 
10
10
  LimitsTuple = tuple[Timestamp, Timestamp]
@@ -23,6 +23,8 @@ def expand_limits(
23
23
  ) -> LimitsTuple:
24
24
  """Derive the `"real"` bounds of `limits`.
25
25
 
26
+ Use :attr:`time_split.settings.misc.round_limits` to allow inward "expansion".
27
+
26
28
  Args:
27
29
  limits: A tuple ``(min, max)`` of timestamps.
28
30
  spec: Expansion spec as described in the :ref:`User guide`. Also supports level-tuples
@@ -61,6 +63,7 @@ def expand_limits(
61
63
  >>> expand_limits(limits, "d<14h")
62
64
  (Timestamp('2019-05-11 00:00:00'), Timestamp('2019-05-11 11:05:30'))
63
65
 
66
+ To disable this restriction, set :attr:`round_limits=True <.misc.round_limits>` in the settings.
64
67
  """
65
68
  if limits[0] >= limits[1]:
66
69
  msg = f"Bad limits. Expected limits[1] > limits[0], but got {limits=}."
@@ -102,19 +105,24 @@ def _from_levels(limits: LimitsTuple, *, levels: Iterable[_TimedeltaTuple] | Non
102
105
  def _apply(limits: LimitsTuple, *, level: _TimedeltaTuple) -> LimitsTuple:
103
106
  lo, hi = limits
104
107
 
105
- lo_floor = lo.floor(level.round_to)
108
+ round = misc.round_limits
109
+ lo_floor = lo.round(level.round_to) if round else lo.floor(level.round_to)
106
110
  if abs(lo_floor - lo) > level.tolerance:
107
111
  return limits
108
112
 
109
- hi_ceil = hi.ceil(level.round_to)
113
+ hi_ceil = hi.round(level.round_to) if round else hi.ceil(level.round_to)
110
114
  if abs(hi_ceil - hi) > level.tolerance:
111
115
  return limits
112
116
 
113
117
  if auto_expand_limits.SANITY_CHECK:
114
- if lo.round(level.round_to) != lo_floor:
115
- return limits
116
- if hi.round(level.round_to) != hi_ceil:
117
- return limits
118
+ if round:
119
+ if lo_floor == hi_ceil:
120
+ return limits
121
+ else:
122
+ if lo.round(level.round_to) != lo_floor:
123
+ return limits
124
+ if hi.round(level.round_to) != hi_ceil:
125
+ return limits
118
126
 
119
127
  return lo_floor, hi_ceil
120
128
 
@@ -1,4 +1,4 @@
1
- from typing import NamedTuple, cast, get_args
1
+ from typing import NamedTuple, get_args
2
2
 
3
3
  from pandas import DatetimeIndex, NaT, Timedelta, Timestamp, date_range
4
4
 
@@ -6,7 +6,7 @@ from ..types import DatetimeIterable, ExpandLimits, Schedule, TimedeltaTypes
6
6
  from ._limits import LimitsTuple
7
7
  from ._process_available import ProcessAvailableResult, process_available
8
8
 
9
- NO_LIMITS = cast(LimitsTuple, (NaT, NaT))
9
+ NO_LIMITS: LimitsTuple = NaT, NaT
10
10
 
11
11
 
12
12
  class MaterializedSchedule(NamedTuple):
@@ -1,6 +1,4 @@
1
- import logging
2
1
  from dataclasses import asdict, dataclass
3
- from functools import lru_cache
4
2
  from typing import cast, get_args
5
3
 
6
4
  from pandas import Timedelta
@@ -17,12 +15,9 @@ from ..types import (
17
15
  Span,
18
16
  TimedeltaTypes,
19
17
  )
20
- from ._limits import LimitsTuple
21
18
  from ._schedule import MaterializedSchedule, materialize_schedule
22
19
  from ._span import OffsetCalculator, to_strict_span
23
20
 
24
- LOGGER = logging.getLogger("time_split")
25
-
26
21
 
27
22
  @dataclass(frozen=True)
28
23
  class DatetimeIndexSplitter:
@@ -39,7 +34,6 @@ class DatetimeIndexSplitter:
39
34
  def get_splits(self, available: DatetimeIterable | None = None) -> DatetimeSplits:
40
35
  """Compute a split of given user data."""
41
36
  ms = self._materialize_schedule(available)
42
- self._log_expansion(ms.available_metadata.limits, expanded=ms.available_metadata.expanded_limits)
43
37
  return self._make_bounds_list(ms)
44
38
 
45
39
  def get_plot_data(self, available: DatetimeIterable | None = None) -> tuple[DatetimeSplits, MaterializedSchedule]:
@@ -70,7 +64,7 @@ class DatetimeIndexSplitter:
70
64
  return ms
71
65
 
72
66
  from_end = ms.available_metadata.expanded_limits[1] - (ms.schedule[-1] + Timedelta(self.after))
73
- from_end = from_end.floor(schedule_frequency.base)
67
+ from_end = from_end.floor(schedule_frequency.base) # TODO(settings): should this depend on misc.round_limits?
74
68
 
75
69
  return ms._replace(schedule=ms.schedule + from_end)
76
70
 
@@ -109,7 +103,6 @@ class DatetimeIndexSplitter:
109
103
 
110
104
  Returns:
111
105
  Filtered splits.
112
-
113
106
  """
114
107
  if self.step != 1:
115
108
  step = abs(self.step)
@@ -127,21 +120,6 @@ class DatetimeIndexSplitter:
127
120
 
128
121
  return [s for s in splits if settings.filter(*s)]
129
122
 
130
- def _log_expansion(self, original: LimitsTuple, *, expanded: LimitsTuple) -> None:
131
- from .._frontend import format_expanded_limits
132
-
133
- if original == expanded or not LOGGER.isEnabledFor(logging.INFO):
134
- return
135
-
136
- message = format_expanded_limits(original, expanded=expanded, expand_limits=self.expand_limits)
137
- self._emit_once(message)
138
-
139
- @staticmethod
140
- @lru_cache(8)
141
- def _emit_once(message: str) -> None:
142
- """Emit if **not** in the eight most recent emission messages."""
143
- LOGGER.info(message)
144
-
145
123
  def __post_init__(self) -> None:
146
124
  # Verify n_splits
147
125
  if self.n_splits < 0:
@@ -1,6 +1,5 @@
1
- from typing import Callable, ParamSpec, TypeVar
2
-
3
- from time_split._compat import deprecated_params
1
+ from collections.abc import Callable
2
+ from typing import ParamSpec, TypeVar
4
3
 
5
4
  P = ParamSpec("P")
6
5
  T = TypeVar("T")
@@ -15,12 +14,6 @@ def docs(__func: Callable[P, T], /) -> Callable[P, T]:
15
14
  """Add info the docstring of a function."""
16
15
  assert __func.__doc__ is not None # noqa: S101
17
16
  __func.__doc__ = __func.__doc__.format(**_DOCSTRINGS)
18
-
19
- if isinstance(__func, type):
20
- __func.__init__ = deprecated_params(__func.__init__)
21
- else:
22
- __func = deprecated_params(__func)
23
-
24
17
  return __func
25
18
 
26
19
 
@@ -1,11 +1,11 @@
1
+ from collections.abc import Sized
1
2
  from dataclasses import asdict, dataclass, replace
2
- from typing import TYPE_CHECKING, Any, Literal, Sized
3
+ from typing import TYPE_CHECKING, Any, Literal
3
4
 
4
5
  import pandas as pd
5
6
  from pandas import Timestamp
6
7
  from rics.misc import format_kwargs, get_public_module
7
-
8
- from time_split._compat import fmt_sec
8
+ from rics.strings import format_seconds as fmt_sec
9
9
 
10
10
  from .._backend import DatetimeIndexSplitter
11
11
  from .._backend._datetime_index_like import DatetimeIndexLike
@@ -65,7 +65,7 @@ def plot(
65
65
  after: Span = 1,
66
66
  step: int = 1,
67
67
  n_splits: int = 0,
68
- available: DatetimeIterable | None = None,
68
+ available: DatetimeIterable | pd.DataFrame | pd.Series | None = None,
69
69
  expand_limits: ExpandLimits = "auto",
70
70
  ignore_filters: bool = False,
71
71
  # Split plot args
@@ -112,6 +112,15 @@ def plot(
112
112
  """
113
113
  import matplotlib.pyplot as plt
114
114
 
115
+ if (
116
+ available is not None
117
+ and hasattr(available, "index")
118
+ and not callable(available.index)
119
+ and hasattr(available, "shape")
120
+ and len(available.shape) != 1
121
+ ):
122
+ available = available.index
123
+
115
124
  splitter = DatetimeIndexSplitter(
116
125
  schedule,
117
126
  before=before,
@@ -121,6 +130,7 @@ def plot(
121
130
  expand_limits=expand_limits,
122
131
  ignore_filters=ignore_filters,
123
132
  )
133
+
124
134
  plot_data = _get_plot_data(available, splitter, row_count_bin=row_count_bin, show_removed=show_removed)
125
135
 
126
136
  if bar_labels is True:
@@ -249,7 +259,7 @@ def _add_bar_labels(
249
259
  unit=unit_or_labels,
250
260
  )
251
261
 
252
- for bar, label in zip(ax.containers, labels):
262
+ for bar, label in zip(ax.containers, labels, strict=True):
253
263
  ax.bar_label(bar, labels=[label], **kwargs) # type: ignore[arg-type]
254
264
 
255
265
 
@@ -6,8 +6,7 @@ from typing import Any, Generic
6
6
 
7
7
  import pandas as pd
8
8
  from rics.collections.dicts import flatten_dict
9
-
10
- from time_split._compat import fmt_sec
9
+ from rics.strings import format_seconds as fmt_sec
11
10
 
12
11
  from ..settings import log_split_progress as settings
13
12
  from ..types import DatetimeSplitBounds, FormatMetrics, GetMetrics, LoggerArg, MetricsType, SplitProgressExtras
@@ -122,7 +121,7 @@ class _ProgressTracker(Generic[MetricsType]):
122
121
  n_splits = len(splits)
123
122
 
124
123
  for n, split in enumerate(splits, start=1):
125
- default_extras = SplitProgressExtras(
124
+ default_extras = SplitProgressExtras[MetricsType](
126
125
  n=n,
127
126
  n_splits=n_splits,
128
127
  start=split.start.isoformat(),