pyrregular 0.2.1__tar.gz → 0.2.2__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 (147) hide show
  1. {pyrregular-0.2.1 → pyrregular-0.2.2}/.github/workflows/build.yml +10 -5
  2. {pyrregular-0.2.1 → pyrregular-0.2.2}/.github/workflows/python-publish.yml +11 -0
  3. {pyrregular-0.2.1 → pyrregular-0.2.2}/.github/workflows/sphinx.yml +2 -3
  4. {pyrregular-0.2.1 → pyrregular-0.2.2}/PKG-INFO +2 -1
  5. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyproject.toml +1 -0
  6. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/_version.py +3 -3
  7. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/accessor.py +2 -2
  8. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/conversion_utils.py +7 -1
  9. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/io_utils.py +46 -2
  10. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/models/ncde.py +1 -29
  11. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/repository.py +5 -2
  12. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular.egg-info/PKG-INFO +2 -1
  13. pyrregular-0.2.2/pyrregular.egg-info/scm_version.json +8 -0
  14. {pyrregular-0.2.1 → pyrregular-0.2.2}/setup.cfg +1 -0
  15. {pyrregular-0.2.1 → pyrregular-0.2.2}/tests/test_dataset_loading.py +2 -0
  16. {pyrregular-0.2.1 → pyrregular-0.2.2}/tests/test_offline.py +52 -0
  17. pyrregular-0.2.1/pyrregular.egg-info/scm_version.json +0 -8
  18. {pyrregular-0.2.1 → pyrregular-0.2.2}/.gitignore +0 -0
  19. {pyrregular-0.2.1 → pyrregular-0.2.2}/.gitmodules +0 -0
  20. {pyrregular-0.2.1 → pyrregular-0.2.2}/.pre-commit-config.yaml +0 -0
  21. {pyrregular-0.2.1 → pyrregular-0.2.2}/README.md +0 -0
  22. {pyrregular-0.2.1 → pyrregular-0.2.2}/assets/images/logo_01.png +0 -0
  23. {pyrregular-0.2.1 → pyrregular-0.2.2}/assets/results/accuracy_mean.csv +0 -0
  24. {pyrregular-0.2.1 → pyrregular-0.2.2}/assets/results/accuracy_std.csv +0 -0
  25. {pyrregular-0.2.1 → pyrregular-0.2.2}/assets/results/balanced_accuracy_mean.csv +0 -0
  26. {pyrregular-0.2.1 → pyrregular-0.2.2}/assets/results/balanced_accuracy_std.csv +0 -0
  27. {pyrregular-0.2.1 → pyrregular-0.2.2}/assets/results/f1_mean.csv +0 -0
  28. {pyrregular-0.2.1 → pyrregular-0.2.2}/assets/results/f1_std.csv +0 -0
  29. {pyrregular-0.2.1 → pyrregular-0.2.2}/assets/results/fit_time_mean.csv +0 -0
  30. {pyrregular-0.2.1 → pyrregular-0.2.2}/assets/results/fit_time_std.csv +0 -0
  31. {pyrregular-0.2.1 → pyrregular-0.2.2}/assets/results/jaccard_mean.csv +0 -0
  32. {pyrregular-0.2.1 → pyrregular-0.2.2}/assets/results/jaccard_std.csv +0 -0
  33. {pyrregular-0.2.1 → pyrregular-0.2.2}/assets/results/precision_mean.csv +0 -0
  34. {pyrregular-0.2.1 → pyrregular-0.2.2}/assets/results/precision_std.csv +0 -0
  35. {pyrregular-0.2.1 → pyrregular-0.2.2}/assets/results/predict_time_mean.csv +0 -0
  36. {pyrregular-0.2.1 → pyrregular-0.2.2}/assets/results/predict_time_std.csv +0 -0
  37. {pyrregular-0.2.1 → pyrregular-0.2.2}/assets/results/recall_mean.csv +0 -0
  38. {pyrregular-0.2.1 → pyrregular-0.2.2}/assets/results/recall_std.csv +0 -0
  39. {pyrregular-0.2.1 → pyrregular-0.2.2}/assets/results/roc_auc_mean.csv +0 -0
  40. {pyrregular-0.2.1 → pyrregular-0.2.2}/assets/results/roc_auc_std.csv +0 -0
  41. {pyrregular-0.2.1 → pyrregular-0.2.2}/assets/results/total_time_mean.csv +0 -0
  42. {pyrregular-0.2.1 → pyrregular-0.2.2}/assets/results/total_time_std.csv +0 -0
  43. {pyrregular-0.2.1 → pyrregular-0.2.2}/docs/Makefile +0 -0
  44. {pyrregular-0.2.1 → pyrregular-0.2.2}/docs/api/index.rst +0 -0
  45. {pyrregular-0.2.1 → pyrregular-0.2.2}/docs/conf.py +0 -0
  46. {pyrregular-0.2.1 → pyrregular-0.2.2}/docs/index.rst +0 -0
  47. {pyrregular-0.2.1 → pyrregular-0.2.2}/docs/make.bat +0 -0
  48. {pyrregular-0.2.1 → pyrregular-0.2.2}/docs/notebooks/dataset_conversion.ipynb +0 -0
  49. {pyrregular-0.2.1 → pyrregular-0.2.2}/docs/notebooks/quick_start.ipynb +0 -0
  50. {pyrregular-0.2.1 → pyrregular-0.2.2}/docs/notebooks/your_dataset.h5 +0 -0
  51. {pyrregular-0.2.1 → pyrregular-0.2.2}/docs/notebooks/your_original_dataset.csv +0 -0
  52. {pyrregular-0.2.1 → pyrregular-0.2.2}/docs/requirements.txt +0 -0
  53. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/Abf.yml +0 -0
  54. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/Ais.yml +0 -0
  55. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/AllGestureWiimoteX.yml +0 -0
  56. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/AllGestureWiimoteY.yml +0 -0
  57. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/AllGestureWiimoteZ.yml +0 -0
  58. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/Animals.yml +0 -0
  59. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/AsphaltObstaclesCoordinates.yml +0 -0
  60. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/AsphaltPavementTypeCoordinates.yml +0 -0
  61. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/AsphaltRegularityCoordinates.yml +0 -0
  62. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/CharacterTrajectories.yml +0 -0
  63. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/CombinedTrajectories.yml +0 -0
  64. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/DodgerLoopDay.yml +0 -0
  65. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/DodgerLoopGame.yml +0 -0
  66. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/DodgerLoopWeekend.yml +0 -0
  67. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/Garment.yml +0 -0
  68. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/Geolife.yml +0 -0
  69. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/GeolifeSupervised.yml +0 -0
  70. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/GestureMidAirD1.yml +0 -0
  71. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/GestureMidAirD2.yml +0 -0
  72. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/GestureMidAirD3.yml +0 -0
  73. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/GesturePebbleZ1.yml +0 -0
  74. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/GesturePebbleZ2.yml +0 -0
  75. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/InsectWingbeat.yml +0 -0
  76. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/JapaneseVowels.yml +0 -0
  77. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/Ldfpa.yml +0 -0
  78. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/MelbournePedestrian.yml +0 -0
  79. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/Mimic3.yml +0 -0
  80. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/PLAID.yml +0 -0
  81. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/Pamap2.yml +0 -0
  82. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/Physionet2012.yml +0 -0
  83. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/Physionet2019.yml +0 -0
  84. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/PickupGestureWiimoteZ.yml +0 -0
  85. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/Seabirds.yml +0 -0
  86. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/ShakeGestureWiimoteZ.yml +0 -0
  87. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/SpokenArabicDigits.yml +0 -0
  88. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/TDrive.yml +0 -0
  89. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/Taxi.yml +0 -0
  90. {pyrregular-0.2.1 → pyrregular-0.2.2}/metadata/Vehicles.yml +0 -0
  91. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/__init__.py +0 -0
  92. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/backend.py +0 -0
  93. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/data_utils.py +0 -0
  94. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/datasets/__init__.py +0 -0
  95. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/datasets/abf.py +0 -0
  96. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/datasets/ais.py +0 -0
  97. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/datasets/animals.py +0 -0
  98. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/datasets/combined_trajectories.py +0 -0
  99. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/datasets/garment.py +0 -0
  100. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/datasets/geolife.py +0 -0
  101. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/datasets/geolife_supervised.py +0 -0
  102. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/datasets/ldfpa.py +0 -0
  103. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/datasets/mimic3.py +0 -0
  104. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/datasets/pamap2.py +0 -0
  105. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/datasets/physionet2012.py +0 -0
  106. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/datasets/physionet2019.py +0 -0
  107. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/datasets/seabirds.py +0 -0
  108. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/datasets/t_drive.py +0 -0
  109. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/datasets/taxi.py +0 -0
  110. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/datasets/vehicles.py +0 -0
  111. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/describe.py +0 -0
  112. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/dev/__init__.py +0 -0
  113. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/dev/repository_dev.py +0 -0
  114. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/models/__init__.py +0 -0
  115. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/models/borf.py +0 -0
  116. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/models/brits.py +0 -0
  117. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/models/grud.py +0 -0
  118. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/models/knn.py +0 -0
  119. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/models/lgbm.py +0 -0
  120. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/models/nodes.py +0 -0
  121. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/models/raindrop.py +0 -0
  122. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/models/ridge_cv.py +0 -0
  123. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/models/rifc.py +0 -0
  124. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/models/rocket.py +0 -0
  125. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/models/saits.py +0 -0
  126. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/models/svm.py +0 -0
  127. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/models/timesnet.py +0 -0
  128. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/models/torch_dataloader.py +0 -0
  129. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/reader_interface.py +0 -0
  130. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/registry.txt +0 -0
  131. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/uea_ucr_datasets.py +0 -0
  132. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/wrappers/__init__.py +0 -0
  133. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/wrappers/pypots_wrapper.py +0 -0
  134. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular/wrappers/tslearn_wrapper.py +0 -0
  135. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular.egg-info/SOURCES.txt +0 -0
  136. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular.egg-info/dependency_links.txt +0 -0
  137. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular.egg-info/entry_points.txt +0 -0
  138. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular.egg-info/requires.txt +0 -0
  139. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular.egg-info/scm_file_list.json +0 -0
  140. {pyrregular-0.2.1 → pyrregular-0.2.2}/pyrregular.egg-info/top_level.txt +0 -0
  141. {pyrregular-0.2.1 → pyrregular-0.2.2}/setup.py +0 -0
  142. {pyrregular-0.2.1 → pyrregular-0.2.2}/tests/__init__.py +0 -0
  143. {pyrregular-0.2.1 → pyrregular-0.2.2}/tests/_deprecated/__init__.py +0 -0
  144. {pyrregular-0.2.1 → pyrregular-0.2.2}/tests/_deprecated/test_dataset_conversion.py +0 -0
  145. {pyrregular-0.2.1 → pyrregular-0.2.2}/tests/_deprecated/test_dataset_sanity.py +0 -0
  146. {pyrregular-0.2.1 → pyrregular-0.2.2}/tests/_deprecated/utils.py +0 -0
  147. {pyrregular-0.2.1 → pyrregular-0.2.2}/tests/constants.py +0 -0
@@ -4,15 +4,15 @@ on:
4
4
  pull_request:
5
5
  branches: [ main ]
6
6
  workflow_dispatch:
7
- release:
8
- types: [ published ]
7
+ workflow_call:
9
8
 
10
9
  jobs:
11
10
  build:
12
11
  strategy:
12
+ fail-fast: false
13
13
  matrix:
14
14
  os: [ubuntu-latest]
15
- python-version: ["3.11"]
15
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
16
16
  runs-on: ${{ matrix.os }}
17
17
 
18
18
  steps:
@@ -35,6 +35,11 @@ jobs:
35
35
  run: |
36
36
  pip install ".[test]"
37
37
 
38
- - name: Test with pytest
38
+ - name: Test with pytest (offline)
39
39
  run: |
40
- pytest
40
+ pytest -m "not network"
41
+
42
+ - name: Test with pytest (dataset downloads)
43
+ if: matrix.python-version == '3.11'
44
+ run: |
45
+ pytest -m network
@@ -8,7 +8,11 @@ permissions:
8
8
  contents: read
9
9
 
10
10
  jobs:
11
+ test:
12
+ uses: ./.github/workflows/build.yml
13
+
11
14
  deploy:
15
+ needs: test
12
16
  runs-on: ubuntu-latest
13
17
  steps:
14
18
  - uses: actions/checkout@v4
@@ -33,3 +37,10 @@ jobs:
33
37
  with:
34
38
  user: __token__
35
39
  password: ${{ secrets.PYPI_API_TOKEN }}
40
+
41
+ docs:
42
+ needs: test
43
+ uses: ./.github/workflows/sphinx.yml
44
+ permissions:
45
+ contents: write
46
+ pages: write
@@ -1,9 +1,8 @@
1
1
  name: "docs"
2
2
 
3
3
  on:
4
- release:
5
- types: [published]
6
4
  workflow_dispatch:
5
+ workflow_call:
7
6
 
8
7
  permissions:
9
8
  contents: write
@@ -39,7 +38,7 @@ jobs:
39
38
  make clean html SPHINXOPTS='-a'
40
39
 
41
40
  - name: Deploy to GitHub Pages
42
- if: github.ref == 'refs/heads/main'
41
+ if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')
43
42
  uses: peaceiris/actions-gh-pages@v3
44
43
  with:
45
44
  github_token: ${{ secrets.GITHUB_TOKEN }}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyrregular
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: Irregular time series made easy
5
5
  Author: Francesco Spinnato, Cristiano Landi
6
6
  Author-email: francesco.spinnato@unipi.it
@@ -8,6 +8,7 @@ Classifier: Programming Language :: Python :: 3
8
8
  Classifier: Programming Language :: Python :: 3.10
9
9
  Classifier: Programming Language :: Python :: 3.11
10
10
  Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
11
12
  Requires-Python: >=3.10
12
13
  Description-Content-Type: text/markdown
13
14
  Requires-Dist: awkward
@@ -9,3 +9,4 @@ write_to = "pyrregular/_version.py"
9
9
  addopts = "-ra -q"
10
10
  testpaths = ["tests"]
11
11
  norecursedirs = ["tests/_deprecated"]
12
+ markers = ["network: downloads datasets from Hugging Face"]
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.2.1'
22
- __version_tuple__ = version_tuple = (0, 2, 1)
21
+ __version__ = version = '0.2.2'
22
+ __version_tuple__ = version_tuple = (0, 2, 2)
23
23
 
24
- __commit_id__ = commit_id = 'g49dbc9f9d'
24
+ __commit_id__ = commit_id = 'ga0f3c03bc'
@@ -2,7 +2,7 @@ import numpy as np
2
2
  import pandas as pd
3
3
  import xarray as xr
4
4
 
5
- from pyrregular.conversion_utils import _ak_dropnan, _fill_time_index, _reset_time_index
5
+ from pyrregular.conversion_utils import _ak_dropnan, _reset_time_index
6
6
  from pyrregular.io_utils import save_to_file
7
7
 
8
8
 
@@ -212,7 +212,7 @@ class IrregularAccessor:
212
212
  columns[name] = _repeat(coord.values, idx[coord.dims[0]])
213
213
  return pd.DataFrame(columns)
214
214
 
215
- def to_hdf5(self, filename, compression="gzip", compression_opts=None):
215
+ def to_hdf5(self, filename, compression="gzip", compression_opts=1):
216
216
  save_to_file(
217
217
  data_array=self._da,
218
218
  filename=filename,
@@ -134,7 +134,7 @@ def _to_tslearn(X):
134
134
  return X.swapaxes(1, 2)
135
135
 
136
136
 
137
- def _fill_time_index(arr):
137
+ def _fill_time_index(arr, nan_delta=1):
138
138
  T = deepcopy(arr)
139
139
 
140
140
  # time delta
@@ -143,6 +143,12 @@ def _fill_time_index(arr):
143
143
  # mean time delta
144
144
  delta_mean = np.nanmean(a_diff, axis=2, keepdims=True)
145
145
 
146
+ nans = np.isnan(delta_mean)
147
+ if np.any(
148
+ nans
149
+ ): # this can happen if there is only 1 valid value in the time series
150
+ delta_mean[nans] = nan_delta
151
+
146
152
  # last timestep
147
153
  last_valid_t = np.nanmax(T, axis=2, keepdims=True)
148
154
 
@@ -159,6 +159,30 @@ def _get_metadata(
159
159
  return dates, ids, signals, n_records
160
160
 
161
161
 
162
+ def _check_static(keys, id_name, static_names, hint):
163
+ """Raise if an id has more than one value for a static column.
164
+
165
+ read_csv identifies an id by the tuple (id, *static values), so a column that
166
+ is not really static would silently split the id into several ones.
167
+ """
168
+ first = {}
169
+ for key in keys:
170
+ other = first.setdefault(key[0], key)
171
+ if other != key:
172
+ columns = [
173
+ n
174
+ for n, a, b in zip(static_names, other[1:], key[1:])
175
+ if a is not b and a != b
176
+ ]
177
+ names = ", ".join(repr(c) for c in columns)
178
+ verb = "is" if len(columns) == 1 else "are"
179
+ raise ValueError(
180
+ f"{names} {verb} not static for {id_name} {key[0]!r} (values "
181
+ f"{other[1:]} and {key[1:]}). A static column must have one value "
182
+ f"per id. {hint}"
183
+ )
184
+
185
+
162
186
  def read_csv(
163
187
  filenames: str | list | dict,
164
188
  ts_id: str = "ts_id",
@@ -193,6 +217,27 @@ def read_csv(
193
217
  **kwargs,
194
218
  )
195
219
 
220
+ # a static column must have one value per id, otherwise the id would be split
221
+ _check_static(
222
+ ids,
223
+ ts_id,
224
+ dims["ts_id"],
225
+ hint='If it changes over time, move it to dims["time_id"] or use it as a '
226
+ "signal; if each value should be its own series, include it in the series id.",
227
+ )
228
+ _check_static(
229
+ signals,
230
+ signal_id,
231
+ dims["signal_id"],
232
+ hint="If it differs between series, move it to dims['ts_id'].",
233
+ )
234
+ _check_static(
235
+ dates,
236
+ time_id,
237
+ dims["time_id"],
238
+ hint="If it differs between series, move it to dims['ts_id'] or use it as a signal.",
239
+ )
240
+
196
241
  # date strings are parsed before sorting, so the time axis follows real time
197
242
  parsed_dates = None
198
243
  if time_index_as_datetime and all(isinstance(d[0], str) for d in dates):
@@ -289,6 +334,5 @@ def read_csv(
289
334
 
290
335
  def get_current_aoe_time():
291
336
  aoe_tz = timezone(timedelta(hours=-12))
292
- current_time_utc = datetime.utcnow()
293
- current_time_aoe = current_time_utc.replace(tzinfo=timezone.utc).astimezone(aoe_tz)
337
+ current_time_aoe = datetime.now(timezone.utc).astimezone(aoe_tz)
294
338
  return current_time_aoe.isoformat()
@@ -15,38 +15,10 @@ import optax
15
15
  from sklearn.base import BaseEstimator, ClassifierMixin
16
16
  from sklearn.model_selection import train_test_split
17
17
 
18
+ from pyrregular.conversion_utils import _fill_time_index
18
19
  from pyrregular.models.nodes import _standardize
19
20
 
20
21
 
21
- def _fill_time_index(arr, nan_delta=1):
22
- T = deepcopy(arr)
23
-
24
- # time delta
25
- a_diff = T[:, :, 1:] - T[:, :, :-1]
26
-
27
- # mean time delta
28
- delta_mean = np.nanmean(a_diff, axis=2, keepdims=True)
29
-
30
- nans = np.isnan(delta_mean)
31
- if np.any(
32
- nans
33
- ): # this can happen if there is only 1 valid value in the time series
34
- delta_mean[nans] = nan_delta
35
-
36
- # last timestep
37
- last_valid_t = np.nanmax(T, axis=2, keepdims=True)
38
-
39
- # find where the nans are
40
- nan_mask = np.isnan(T)
41
-
42
- # where nans are there is an increasing value from 1 to the last nan
43
- nan_indices = np.cumsum(nan_mask, axis=2)
44
-
45
- replacement = (last_valid_t + delta_mean * nan_indices)[nan_mask]
46
- T[nan_mask] = replacement
47
- return T
48
-
49
-
50
22
  def _fill_all_nans_signals(X):
51
23
  X_ = deepcopy(X)
52
24
  mask = np.sum(np.isnan(X_), axis=2) >= X_.shape[2] - 2
@@ -25,7 +25,8 @@ def download_dataset_from_huggingface(
25
25
  if api_token is None:
26
26
  raise ValueError("You need to provide an API token to download the dataset")
27
27
  downloader = pooch.HTTPDownloader(
28
- **dict(headers={"Authorization": f"Bearer {api_token}"})
28
+ progressbar=progressbar,
29
+ headers={"Authorization": f"Bearer {api_token}"},
29
30
  )
30
31
  else:
31
32
  downloader = pooch.HTTPDownloader(progressbar=progressbar)
@@ -35,7 +36,9 @@ def download_dataset_from_huggingface(
35
36
  def load_dataset_from_file(name, api_token=None):
36
37
  if ".h5" not in name:
37
38
  name += ".h5"
38
- file = download_dataset_from_huggingface(name, api_token)
39
+ file = download_dataset_from_huggingface(
40
+ name, use_api_token=api_token is not None, api_token=api_token
41
+ )
39
42
  return file
40
43
 
41
44
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyrregular
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: Irregular time series made easy
5
5
  Author: Francesco Spinnato, Cristiano Landi
6
6
  Author-email: francesco.spinnato@unipi.it
@@ -8,6 +8,7 @@ Classifier: Programming Language :: Python :: 3
8
8
  Classifier: Programming Language :: Python :: 3.10
9
9
  Classifier: Programming Language :: Python :: 3.11
10
10
  Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
11
12
  Requires-Python: >=3.10
12
13
  Description-Content-Type: text/markdown
13
14
  Requires-Dist: awkward
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "0.2.2",
3
+ "distance": 0,
4
+ "node": "ga0f3c03bc664933363e4a80dbd04764d680873f4",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-10-04"
8
+ }
@@ -10,6 +10,7 @@ classifiers =
10
10
  Programming Language :: Python :: 3.10
11
11
  Programming Language :: Python :: 3.11
12
12
  Programming Language :: Python :: 3.12
13
+ Programming Language :: Python :: 3.13
13
14
 
14
15
  [options]
15
16
  packages = find:
@@ -3,6 +3,8 @@ import pytest
3
3
  from pyrregular import load_dataset
4
4
  from tests.constants import TEST_CASES_FAST as TEST_CASES
5
5
 
6
+ pytestmark = pytest.mark.network
7
+
6
8
 
7
9
  @pytest.fixture(params=TEST_CASES)
8
10
  def loaded_dataset(request):
@@ -355,3 +355,55 @@ def test_version():
355
355
  import pyrregular
356
356
 
357
357
  assert isinstance(pyrregular.__version__, str) and pyrregular.__version__
358
+
359
+
360
+ def test_read_csv_rejects_non_static_columns(tmp_path):
361
+ # label changes inside series a: it is not static, so read_csv must not split a
362
+ rows = [
363
+ ("a", "s", 1, 1.0, "x"),
364
+ ("a", "s", 2, 2.0, "x"),
365
+ ("a", "s", 3, 3.0, "y"),
366
+ ("b", "s", 1, 5.0, "z"),
367
+ ]
368
+ path = tmp_path / "static.csv"
369
+ pd.DataFrame(
370
+ rows, columns=["ts_id", "signal_id", "time_id", "value_id", "label"]
371
+ ).to_csv(path, index=False)
372
+ with pytest.raises(ValueError, match="'label' is not static for ts_id 'a'"):
373
+ read_csv(
374
+ path,
375
+ dims={"ts_id": ["label"], "signal_id": [], "time_id": []},
376
+ time_index_as_datetime=False,
377
+ )
378
+
379
+
380
+ def test_api_token_is_sent(monkeypatch):
381
+ # capture the downloader instead of downloading
382
+ from pyrregular import repository
383
+
384
+ seen = {}
385
+
386
+ def fake_fetch(name, downloader):
387
+ seen["name"], seen["downloader"] = name, downloader
388
+ return "fake/path.h5"
389
+
390
+ monkeypatch.delenv("HF_TOKEN", raising=False)
391
+ monkeypatch.setattr(repository.REPOSITORY, "fetch", fake_fetch)
392
+ assert (
393
+ repository.load_dataset_from_file("Garment", api_token="hf_x") == "fake/path.h5"
394
+ )
395
+ assert seen["name"] == "Garment.h5"
396
+ assert seen["downloader"].kwargs["headers"] == {"Authorization": "Bearer hf_x"}
397
+
398
+
399
+ def test_fill_time_index():
400
+ from pyrregular.conversion_utils import _fill_time_index
401
+
402
+ T = np.array(
403
+ [
404
+ [[0.0, 1.0, 3.0, nan, nan]], # mean step 1.5
405
+ [[5.0, nan, nan, nan, nan]], # one timestamp: no step, use nan_delta
406
+ ]
407
+ )
408
+ assert_equal_nan(_fill_time_index(T)[:, 0, :], [[0, 1, 3, 4.5, 6], [5, 6, 7, 8, 9]])
409
+ assert_equal_nan(_fill_time_index(T, nan_delta=2)[1, 0], [5, 7, 9, 11, 13])
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "0.2.1",
3
- "distance": 0,
4
- "node": "g49dbc9f9dd41bb03575d82efc1680f376c9282bc",
5
- "dirty": false,
6
- "branch": "HEAD",
7
- "node_date": "2026-10-03"
8
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes