anemoi-utils 0.4.37__tar.gz → 0.4.38__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.

Potentially problematic release.


This version of anemoi-utils might be problematic. Click here for more details.

Files changed (113) hide show
  1. anemoi_utils-0.4.38/.release-please-manifest.json +3 -0
  2. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/CHANGELOG.md +14 -0
  3. {anemoi_utils-0.4.37/src/anemoi_utils.egg-info → anemoi_utils-0.4.38}/PKG-INFO +1 -1
  4. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/_version.py +3 -3
  5. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/checkpoints.py +38 -17
  6. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/dates.py +8 -26
  7. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/testing.py +1 -1
  8. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38/src/anemoi_utils.egg-info}/PKG-INFO +1 -1
  9. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/tests/test_frequency.py +3 -2
  10. anemoi_utils-0.4.37/.release-please-manifest.json +0 -3
  11. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/.gitattributes +0 -0
  12. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/.github/CODEOWNERS +0 -0
  13. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/.github/ci-hpc-config.yml +0 -0
  14. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/.github/dependabot.yml +0 -0
  15. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/.github/labeler.yml +0 -0
  16. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/.github/pull_request_template.md +0 -0
  17. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/.github/workflows/downstream-ci-hpc.yml +0 -0
  18. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/.github/workflows/pr-conventional-commit.yml +0 -0
  19. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/.github/workflows/pr-label-ats.yml +0 -0
  20. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/.github/workflows/pr-label-conventional-commits.yml +0 -0
  21. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/.github/workflows/pr-label-file-based.yml +0 -0
  22. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/.github/workflows/pr-label-public.yml +0 -0
  23. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/.github/workflows/python-publish.yml +0 -0
  24. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/.github/workflows/python-pull-request.yml +0 -0
  25. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/.github/workflows/readthedocs-pr-update.yml +0 -0
  26. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/.github/workflows/release-please.yml +0 -0
  27. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/.gitignore +0 -0
  28. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/.pre-commit-config.yaml +0 -0
  29. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/.readthedocs.yaml +0 -0
  30. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/.release-please-config.json +0 -0
  31. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/CONTRIBUTORS.md +0 -0
  32. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/LICENSE +0 -0
  33. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/README.md +0 -0
  34. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/docs/Makefile +0 -0
  35. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/docs/_static/logo.png +0 -0
  36. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/docs/_static/style.css +0 -0
  37. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/docs/_templates/.gitkeep +0 -0
  38. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/docs/_templates/apidoc/package.rst.jinja +0 -0
  39. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/docs/conf.py +0 -0
  40. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/docs/index.rst +0 -0
  41. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/docs/installing.rst +0 -0
  42. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/docs/modules/checkpoints.rst +0 -0
  43. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/docs/modules/config.rst +0 -0
  44. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/docs/modules/dates.rst +0 -0
  45. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/docs/modules/grib.rst +0 -0
  46. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/docs/modules/humanize.rst +0 -0
  47. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/docs/modules/provenance.rst +0 -0
  48. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/docs/modules/s3.rst +0 -0
  49. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/docs/modules/testing.rst +0 -0
  50. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/docs/modules/text.rst +0 -0
  51. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/docs/scripts/api_build.sh +0 -0
  52. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/pyproject.toml +0 -0
  53. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/setup.cfg +0 -0
  54. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/__init__.py +0 -0
  55. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/__main__.py +0 -0
  56. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/_environment.py +0 -0
  57. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/caching.py +0 -0
  58. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/cli.py +0 -0
  59. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/commands/__init__.py +0 -0
  60. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/commands/config.py +0 -0
  61. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/commands/metadata.py +0 -0
  62. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/commands/requests.py +0 -0
  63. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/commands/transfer.py +0 -0
  64. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/compatibility.py +0 -0
  65. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/config.py +0 -0
  66. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/devtools.py +0 -0
  67. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/grib.py +0 -0
  68. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/grids.py +0 -0
  69. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/hindcasts.py +0 -0
  70. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/humanize.py +0 -0
  71. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/logs.py +0 -0
  72. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/mars/__init__.py +0 -0
  73. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/mars/mars.yaml +0 -0
  74. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/mars/requests.py +0 -0
  75. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/mlflow/__init__.py +0 -0
  76. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/mlflow/auth.py +0 -0
  77. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/mlflow/client.py +0 -0
  78. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/mlflow/utils.py +0 -0
  79. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/provenance.py +0 -0
  80. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/registry.py +0 -0
  81. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/remote/__init__.py +0 -0
  82. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/remote/s3.py +0 -0
  83. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/remote/ssh.py +0 -0
  84. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/rules.py +0 -0
  85. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/s3.py +0 -0
  86. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/sanitise.py +0 -0
  87. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/sanitize.py +0 -0
  88. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/schemas/__init__.py +0 -0
  89. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/schemas/errors.py +0 -0
  90. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/text.py +0 -0
  91. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi/utils/timer.py +0 -0
  92. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi_utils.egg-info/SOURCES.txt +0 -0
  93. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi_utils.egg-info/dependency_links.txt +0 -0
  94. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi_utils.egg-info/entry_points.txt +0 -0
  95. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi_utils.egg-info/requires.txt +0 -0
  96. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/src/anemoi_utils.egg-info/top_level.txt +0 -0
  97. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/tests/test-transfer-data/directory/b/c/x +0 -0
  98. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/tests/test-transfer-data/directory/b/y +0 -0
  99. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/tests/test-transfer-data/directory/exotic filename ;^/"'[=.,#]()/303/252/303/274/303/247/303/262/342/234/205.txt" +0 -0
  100. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/tests/test-transfer-data/directory/z +0 -0
  101. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/tests/test-transfer-data/file +0 -0
  102. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/tests/test_caching.py +0 -0
  103. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/tests/test_checkpoints.py +0 -0
  104. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/tests/test_compatibility.py +0 -0
  105. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/tests/test_dates.py +0 -0
  106. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/tests/test_mlflow_auth.py +0 -0
  107. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/tests/test_mlflow_client.py +0 -0
  108. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/tests/test_provenance.py +0 -0
  109. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/tests/test_registry.py +0 -0
  110. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/tests/test_remote.py +0 -0
  111. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/tests/test_s3.py +0 -0
  112. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/tests/test_sanitise.py +0 -0
  113. {anemoi_utils-0.4.37 → anemoi_utils-0.4.38}/tests/test_utils.py +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.4.38"
3
+ }
@@ -8,6 +8,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8
8
  Please add your functional changes to the appropriate section in the PR.
9
9
  Keep it human-readable, your future self will thank you!
10
10
 
11
+ ## [0.4.38](https://github.com/ecmwf/anemoi-utils/compare/0.4.37...0.4.38) (2025-10-22)
12
+
13
+
14
+ ### Features
15
+
16
+ * **testing:** Add download timeout ([#230](https://github.com/ecmwf/anemoi-utils/issues/230)) ([721d114](https://github.com/ecmwf/anemoi-utils/commit/721d114f2702985d9fbabf68f384f7ccedb7cfb3))
17
+ * **testing:** Sane test data download retries ([#227](https://github.com/ecmwf/anemoi-utils/issues/227)) ([1e08996](https://github.com/ecmwf/anemoi-utils/commit/1e089962b14f05f4aa56eb66a884bfe50ce60dcc))
18
+
19
+
20
+ ### Bug Fixes
21
+
22
+ * Fix frequency_to_string outputing 108000s ([#216](https://github.com/ecmwf/anemoi-utils/issues/216)) ([5806a0c](https://github.com/ecmwf/anemoi-utils/commit/5806a0c996235fb3a19d34eeb25813280c5c989f))
23
+ * Support dicts of supporting_arrays ([#229](https://github.com/ecmwf/anemoi-utils/issues/229)) ([9badbad](https://github.com/ecmwf/anemoi-utils/commit/9badbad360609d254717e0d32c6171beb903eb21))
24
+
11
25
  ## [0.4.37](https://github.com/ecmwf/anemoi-utils/compare/0.4.36...0.4.37) (2025-09-30)
12
26
 
13
27
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: anemoi-utils
3
- Version: 0.4.37
3
+ Version: 0.4.38
4
4
  Summary: A package to hold various functions to support training of ML models on ECMWF data.
5
5
  Author-email: "European Centre for Medium-Range Weather Forecasts (ECMWF)" <software.support@ecmwf.int>
6
6
  License: Apache License
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.4.37'
32
- __version_tuple__ = version_tuple = (0, 4, 37)
31
+ __version__ = version = '0.4.38'
32
+ __version_tuple__ = version_tuple = (0, 4, 38)
33
33
 
34
- __commit_id__ = commit_id = 'gceecf1ec8'
34
+ __commit_id__ = commit_id = 'g30b2d7452'
@@ -20,6 +20,7 @@ import zipfile
20
20
  from collections.abc import Callable
21
21
  from tempfile import TemporaryDirectory
22
22
 
23
+ import numpy as np
23
24
  import tqdm
24
25
 
25
26
  LOG = logging.getLogger(__name__)
@@ -147,6 +148,41 @@ def load_supporting_arrays(zipf: zipfile.ZipFile, entries: dict) -> dict:
147
148
  return supporting_arrays
148
149
 
149
150
 
151
+ def _get_supporting_arrays_paths(directory: str, folder: str, supporting_arrays: dict | np.ndarray) -> dict:
152
+ """Get the paths of supporting arrays."""
153
+ if supporting_arrays is None:
154
+ return {}
155
+
156
+ if isinstance(supporting_arrays, dict):
157
+ return {
158
+ new_key: _get_supporting_arrays_paths(f"{directory}/{folder}", new_key, new_value)
159
+ for new_key, new_value in supporting_arrays.items()
160
+ }
161
+
162
+ return dict(
163
+ path=f"{directory}/{folder}.numpy",
164
+ shape=supporting_arrays.shape,
165
+ dtype=str(supporting_arrays.dtype),
166
+ )
167
+
168
+
169
+ def _write_array_to_bytes(array: dict | np.ndarray, name: str, entry: dict, zipf: zipfile.ZipFile) -> None:
170
+ """Write a supporting array to bytes in a zip file."""
171
+ if isinstance(array, dict):
172
+ for sub_name, sub_array in array.items():
173
+ _write_array_to_bytes(sub_array, sub_name, entry[sub_name], zipf)
174
+ return None
175
+
176
+ LOG.info(
177
+ "Saving supporting array `%s` to %s (shape=%s, dtype=%s)",
178
+ name,
179
+ entry["path"],
180
+ entry["shape"],
181
+ entry["dtype"],
182
+ )
183
+ zipf.writestr(entry["path"], array.tobytes())
184
+
185
+
150
186
  def save_metadata(
151
187
  path: str, metadata: dict, *, supporting_arrays: dict = None, name: str = DEFAULT_NAME, folder: str = DEFAULT_FOLDER
152
188
  ) -> None:
@@ -189,29 +225,14 @@ def save_metadata(
189
225
  LOG.info("Saving metadata to %s/%s/%s", directory, folder, name)
190
226
 
191
227
  metadata = metadata.copy()
192
- if supporting_arrays is not None:
193
- metadata["supporting_arrays_paths"] = {
194
- key: dict(path=f"{directory}/{folder}/{key}.numpy", shape=value.shape, dtype=str(value.dtype))
195
- for key, value in supporting_arrays.items()
196
- }
197
- else:
198
- metadata["supporting_arrays_paths"] = {}
228
+ metadata["supporting_arrays_paths"] = _get_supporting_arrays_paths(directory, folder, supporting_arrays)
199
229
 
200
230
  zipf.writestr(
201
231
  f"{directory}/{folder}/{name}",
202
232
  json.dumps(metadata),
203
233
  )
204
234
 
205
- for name, entry in metadata["supporting_arrays_paths"].items():
206
- value = supporting_arrays[name]
207
- LOG.info(
208
- "Saving supporting array `%s` to %s (shape=%s, dtype=%s)",
209
- name,
210
- entry["path"],
211
- entry["shape"],
212
- entry["dtype"],
213
- )
214
- zipf.writestr(entry["path"], value.tobytes())
235
+ _write_array_to_bytes(supporting_arrays, "", metadata["supporting_arrays_paths"], zipf)
215
236
 
216
237
 
217
238
  def _edit_metadata(path: str, name: str, callback: Callable, supporting_arrays: dict | None = None) -> None:
@@ -260,39 +260,21 @@ def frequency_to_string(frequency: datetime.timedelta) -> str:
260
260
  A string representation of the frequency.
261
261
  """
262
262
 
263
- frequency = frequency_to_timedelta(frequency)
263
+ total_seconds = int(frequency.total_seconds())
264
264
 
265
- total_seconds = frequency.total_seconds()
266
265
  if total_seconds < 0:
267
266
  return f"-{frequency_to_string(-frequency)}"
268
- assert int(total_seconds) == total_seconds, total_seconds
269
- total_seconds = int(total_seconds)
270
267
 
271
- seconds = total_seconds
268
+ if total_seconds % (24 * 3600) == 0:
269
+ return f"{total_seconds // (24 * 3600)}d"
272
270
 
273
- days = seconds // (24 * 3600)
274
- seconds %= 24 * 3600
275
- hours = seconds // 3600
276
- seconds %= 3600
277
- minutes = seconds // 60
278
- seconds %= 60
271
+ if total_seconds % 3600 == 0:
272
+ return f"{total_seconds // 3600}h"
279
273
 
280
- if days > 0 and hours == 0 and minutes == 0 and seconds == 0:
281
- return f"{days}d"
274
+ if total_seconds % 60 == 0:
275
+ return f"{total_seconds // 60}m"
282
276
 
283
- if days == 0 and hours > 0 and minutes == 0 and seconds == 0:
284
- return f"{hours}h"
285
-
286
- if days == 0 and hours == 0 and minutes > 0 and seconds == 0:
287
- return f"{minutes}m"
288
-
289
- if days == 0 and hours == 0 and minutes == 0 and seconds > 0:
290
- return f"{seconds}s"
291
-
292
- if days > 0:
293
- return f"{total_seconds}s"
294
-
295
- return str(frequency)
277
+ return f"{total_seconds}s"
296
278
 
297
279
 
298
280
  def frequency_to_seconds(frequency: int | str | datetime.timedelta) -> int:
@@ -114,7 +114,7 @@ class GetTestData:
114
114
 
115
115
  LOG.info(f"Downloading test data from {url} to {target}")
116
116
 
117
- download(url, target)
117
+ download(url, target, maximum_retries=5, retry_after=60, timeout=60)
118
118
 
119
119
  if gzipped:
120
120
  import gzip
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: anemoi-utils
3
- Version: 0.4.37
3
+ Version: 0.4.38
4
4
  Summary: A package to hold various functions to support training of ML models on ECMWF data.
5
5
  Author-email: "European Centre for Medium-Range Weather Forecasts (ECMWF)" <software.support@ecmwf.int>
6
6
  License: Apache License
@@ -17,10 +17,11 @@ from anemoi.utils.dates import frequency_to_timedelta
17
17
  def test_frequency_to_string() -> None:
18
18
  """Test the frequency_to_string function for converting timedelta to string."""
19
19
  assert frequency_to_string(datetime.timedelta(hours=1)) == "1h"
20
- assert frequency_to_string(datetime.timedelta(hours=1, minutes=30)) == "1:30:00"
20
+ assert frequency_to_string(datetime.timedelta(hours=1, minutes=30)) == "90m"
21
21
  assert frequency_to_string(datetime.timedelta(days=10)) == "10d"
22
+ assert frequency_to_string(datetime.timedelta(hours=30)) == "30h"
22
23
  assert frequency_to_string(datetime.timedelta(minutes=10)) == "10m"
23
- assert frequency_to_string(datetime.timedelta(minutes=90)) == "1:30:00"
24
+ assert frequency_to_string(datetime.timedelta(minutes=90)) == "90m"
24
25
 
25
26
 
26
27
  def test_frequency_to_timedelta() -> None:
@@ -1,3 +0,0 @@
1
- {
2
- ".": "0.4.37"
3
- }
File without changes
File without changes
File without changes
File without changes