tsdf 0.5.1__py3-none-any.whl → 0.6.0__py3-none-any.whl

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.
tsdf/numpy_utils.py CHANGED
@@ -61,6 +61,7 @@ _map_from_numpy_endianness = {
61
61
  "<": "little",
62
62
  ">": "big",
63
63
  "=": sys.byteorder,
64
+ "|": "not applicable",
64
65
  }
65
66
  """ Supported endianness values. """
66
67
 
@@ -79,6 +80,7 @@ def endianness_numpy_to_tsdf(data: np.ndarray) -> str:
79
80
  _map_to_numpy_endianness = {
80
81
  "little": "<",
81
82
  "big": ">",
83
+ "not applicable": "|",
82
84
  }
83
85
  """ Supported endianness values. """
84
86
 
tsdf/parse_metadata.py CHANGED
@@ -6,6 +6,8 @@ Reference: https://arxiv.org/abs/2211.11294
6
6
 
7
7
  import os
8
8
  from typing import Any, Dict, List
9
+ import re
10
+ from dateutil import parser
9
11
 
10
12
  from tsdf import constants
11
13
  from tsdf import tsdfmetadata
@@ -82,7 +84,7 @@ def _read_struct(
82
84
  # levels of the TSDF structure.
83
85
  # Extend the mapping recursively with values provided at those levels.
84
86
  for key, value in remaining_data.items():
85
- if _is_a_list(value):
87
+ if isinstance(value, list):
86
88
  for each_value in value:
87
89
  all_streams = all_streams | _read_struct(
88
90
  each_value, defined_properties.copy(), source_path, version
@@ -135,17 +137,6 @@ def _contains_file_name(data: Any) -> bool:
135
137
  return False
136
138
 
137
139
 
138
- def _is_a_list(value) -> bool:
139
- """
140
- Function returns True if the value is a list, otherwise it returns False.
141
-
142
- :param value: value to be checked.
143
-
144
- :return: True if the value is a list, otherwise False.
145
- """
146
- return isinstance(value, list)
147
-
148
-
149
140
  def contains_tsdf_mandatory_fields(dictionary: Dict[str, Any]) -> bool:
150
141
  """
151
142
  Verifies that all the mandatory properties for TSDF metadata are provided,
@@ -242,4 +233,33 @@ def confirm_dir_of_metadata(metadatas: List["tsdfmetadata.TSDFMetadata"]) -> Non
242
233
  if init_metadata.file_name == curr_metadata.file_name:
243
234
  raise tsdfmetadata.TSDFMetadataFieldValueError(
244
235
  "Two metadata objects cannot reference the same binary file (file_name)."
236
+ #TODO: why not?
245
237
  )
238
+
239
+ def is_iso8601(date_string: str) -> bool:
240
+ """
241
+ Checks if the given date string is in ISO8601 format.
242
+
243
+ :param date_string: date string to be checked.
244
+ """
245
+ # Note that we need both the regex and the parser to validate the date string
246
+ # The regex only still allows for invalid dates, e.g. 2021-02-29
247
+ # The parser is too lenient in accepting different formats
248
+ iso8601_regex = r"^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])(T(2[0-3]|[01][0-9]):[0-5][0-9]:[0-5][0-9](?:\.[0-9]+)?(?:Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9])?)?$"
249
+ if re.match(iso8601_regex, date_string):
250
+ try:
251
+ parser.parse(date_string)
252
+ return True
253
+ except tsdfmetadata.TSDFMetadataFieldValueError:
254
+ return False
255
+ return False
256
+
257
+ def validate_datetimes(metadata: tsdfmetadata.TSDFMetadata) -> bool:
258
+ """
259
+ Validates the start and end date format of the TSDFMetaData object.
260
+ """
261
+ if not is_iso8601(metadata.start_iso8601):
262
+ raise tsdfmetadata.TSDFMetadataFieldValueError(f"Invalid start_iso8601: {metadata.start_iso8601}")
263
+ if not is_iso8601(metadata.end_iso8601):
264
+ raise tsdfmetadata.TSDFMetadataFieldValueError(f"Invalid end_iso8601: {metadata.end_iso8601}")
265
+ return True
tsdf/read_tsdf.py CHANGED
@@ -6,6 +6,7 @@ Reference: https://arxiv.org/abs/2211.11294
6
6
 
7
7
  import json
8
8
  import os
9
+ from pathlib import Path
9
10
  from typing import Dict, List
10
11
  from tsdf import file_utils
11
12
  from tsdf.constants import METADATA_NAMING_PATTERN
@@ -71,7 +72,7 @@ def load_metadatas_from_dir(
71
72
  return metadatas
72
73
 
73
74
 
74
- def load_metadata_from_path(path: str) -> Dict[str, TSDFMetadata]:
75
+ def load_metadata_from_path(path: Path) -> Dict[str, TSDFMetadata]:
75
76
  """
76
77
  Loads a TSDF metadata file, returns a dictionary
77
78
 
tsdf/tsdfmetadata.py CHANGED
@@ -1,5 +1,7 @@
1
1
  import copy
2
2
  from typing import Any, Dict, List
3
+ from datetime import datetime
4
+ from dateutil import parser
3
5
 
4
6
  from tsdf import parse_metadata
5
7
 
@@ -48,11 +50,11 @@ class TSDFMetadata:
48
50
 
49
51
  file_dir_path: str
50
52
  """ A reference to the directory path, so we don't need it again when reading associated binary files. """
51
- metadata_file_name: str
53
+ metadata_file_name: str #TODO: do we need this?? / is it used?
52
54
  """ A reference to the source path, so we don't need it again when reading associated binary files. """
53
55
 
54
56
  def __init__(
55
- self, dictionary: Dict[str, Any], dir_path: str, metadata_file_name: str = ""
57
+ self, dictionary: Dict[str, Any], dir_path: str, metadata_file_name: str = "", do_validate: bool = True
56
58
  ) -> None:
57
59
  """
58
60
  The default constructor takes a dictionary as an argument and creates each
@@ -61,14 +63,34 @@ class TSDFMetadata:
61
63
 
62
64
  :param dictionary: dictionary containing TSDF metadata.
63
65
  :param dir_path: path to the directory where the metadata file is stored.
64
- :param file_name: (optional) name of the metadata file.
66
+ :param metadata_file_name: (optional) name of the metadata file.
67
+ :param do_validate: (optional) flag to validate the metadata.
65
68
  """
66
- parse_metadata.contains_tsdf_mandatory_fields(dictionary) #TODO: how to load a dict that is not complete yet?
69
+
70
+ # Copy the attributes from the dictionary to the object
67
71
  for key, value in dictionary.items():
68
72
  setattr(self, key, value)
69
73
  self.file_dir_path = dir_path
70
74
  self.metadata_file_name = metadata_file_name
71
75
 
76
+ # Validate the metadata
77
+ if do_validate:
78
+ if not self.validate():
79
+ raise TSDFMetadataFieldValueError("The provided metadata is invalid.")
80
+
81
+
82
+ def validate(self) -> bool:
83
+ isValid: bool = True
84
+
85
+ # Validate presence of mandatory fields
86
+ dict = self.get_plain_tsdf_dict_copy()
87
+ isValid = isValid and parse_metadata.contains_tsdf_mandatory_fields(dict)
88
+
89
+ # Validate datetimes
90
+ isValid = isValid and parse_metadata.validate_datetimes(self)
91
+
92
+ return isValid
93
+
72
94
  def get_plain_tsdf_dict_copy(self) -> Dict[str, Any]:
73
95
  """
74
96
  Method returns the a copy of the dict containing fields needed for the TSDF file.
@@ -81,3 +103,31 @@ class TSDFMetadata:
81
103
  if simple_dict.get("metadata_file_name") is not None:
82
104
  simple_dict.pop("metadata_file_name")
83
105
  return simple_dict
106
+
107
+ def set_start_datetime(self, date_time: datetime) -> None:
108
+ """
109
+ Sets the start date of the recording in ISO8601 format.
110
+ :param date_time: datetime object containing the start date.
111
+ """
112
+ self.start_iso8601 = date_time.isoformat()
113
+
114
+ def get_start_datetime(self) -> datetime:
115
+ """
116
+ Returns the start date of the recording as a datetime object.
117
+ :return: datetime object containing the start date.
118
+ """
119
+ return parser.parse(self.start_iso8601)
120
+
121
+ def set_end_datetime(self, date_time: datetime) -> None:
122
+ """
123
+ Sets the end date of the recording in ISO8601 format.
124
+ :param date_time: datetime object containing the end date.
125
+ """
126
+ self.end_iso8601 = date_time.isoformat()
127
+
128
+ def get_end_datetime(self) -> datetime:
129
+ """
130
+ Returns the end date of the recording as a datetime object.
131
+ :return: datetime object containing the end date.
132
+ """
133
+ return parser.parse(self.end_iso8601)
tsdf/write_binary.py CHANGED
@@ -5,26 +5,24 @@ Reference: https://arxiv.org/abs/2211.11294
5
5
  """
6
6
 
7
7
  import os
8
- from typing import Any, Dict
8
+ from typing import Any, Dict, List
9
9
  import numpy as np
10
10
  import pandas as pd
11
- from tsdf import numpy_utils
11
+ from tsdf import numpy_utils
12
12
 
13
13
  from tsdf.tsdfmetadata import TSDFMetadata
14
14
 
15
15
 
16
16
  def write_dataframe_to_binaries(
17
- file_dir: str, df: pd.DataFrame, metadatas: [TSDFMetadata]
17
+ file_dir: str, df: pd.DataFrame, metadatas: List[TSDFMetadata]
18
18
  ) -> None:
19
19
  """
20
20
  Save binary file based on the provided pandas DataFrame.
21
21
 
22
- :param file_dir: path to the directory where the file will be saved.
23
- :param file_name: name of the file to be saved.
24
- :param data: pandas DataFrame containing the data.
25
- :param metadata: dictionary containing the metadata.
26
-
27
- :return: TSDFMetadata object.
22
+ :param file_dir: path to the directory where the file will be saved.
23
+ :param df: pandas DataFrame containing the data.
24
+ :param metadatas: list of metadata objects to be saved, also contains
25
+ channels to be retrieved from dataframe.
28
26
  """
29
27
  for metadata in metadatas:
30
28
  file_name = metadata.file_name
tsdf/write_tsdf.py CHANGED
@@ -19,6 +19,9 @@ def write_metadata(metadatas: List[TSDFMetadata], file_name: str) -> None:
19
19
 
20
20
  :raises TSDFMetadataFieldValueError: if the metadata files cannot be combined (e.g. they have no common fields) or if the list of TSDFMetadata objects is empty.
21
21
  """
22
+ for meta in metadatas:
23
+ meta.validate()
24
+
22
25
  if len(metadatas) == 0:
23
26
  raise TSDFMetadataFieldValueError(
24
27
  "Metadata cannot be saved, as the list of TSDFMetadata objects is empty."
@@ -42,7 +45,7 @@ def write_metadata(metadatas: List[TSDFMetadata], file_name: str) -> None:
42
45
  )
43
46
 
44
47
  if len(plain_meta) > 0:
45
- overlap["sensors"] = _calculate_ovelaps_rec(plain_meta)
48
+ overlap["sensors"] = _calculate_overlaps_rec(plain_meta)
46
49
  file_utils.write_to_file(overlap, metadatas[0].file_dir_path, file_name)
47
50
 
48
51
 
@@ -76,7 +79,7 @@ def _extract_common_fields(metadatas: List[Dict[str, Any]]) -> Dict[str, Any]:
76
79
  return meta_overlap
77
80
 
78
81
 
79
- def _calculate_ovelaps_rec(metadatas: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
82
+ def _calculate_overlaps_rec(metadatas: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
80
83
  """
81
84
  A recursive call that optimises the structure of the TSDF metadata, by grouping common values. For the input the list of dictionaries
82
85
  corresponds to a list of "flat" metadata dictionaries. The output is a list of dictionaries (potentially of length 1) that contain
@@ -107,11 +110,11 @@ def _calculate_ovelaps_rec(metadatas: List[Dict[str, Any]]) -> List[Dict[str, An
107
110
  # Handle the first group
108
111
  first_overlap = _extract_common_fields(first_group)
109
112
  if len(first_group) > 0:
110
- first_overlap["sensors"] = _calculate_ovelaps_rec(first_group)
113
+ first_overlap["sensors"] = _calculate_overlaps_rec(first_group)
111
114
  final_metadata.append(first_overlap)
112
115
 
113
116
  # Handle the rest of the elements
114
- second_overlap = _calculate_ovelaps_rec(second_grop)
117
+ second_overlap = _calculate_overlaps_rec(second_grop)
115
118
  final_metadata.extend(second_overlap)
116
119
 
117
120
  return final_metadata
@@ -1,19 +1,19 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tsdf
3
- Version: 0.5.1
3
+ Version: 0.6.0
4
4
  Summary: A Python library that provides methods for encoding and decoding TSDF (Time Series Data Format) data, which allows you to easily create, manipulate and serialize TSDF files in your Python code.
5
5
  Home-page: https://github.com/biomarkersParkinson/tsdf
6
6
  License: Apache-2.0
7
7
  Keywords: Time Series Data Format (TSDF),binary data,digital sensors
8
8
  Author: Peter Kok
9
9
  Author-email: p.kok@esciencecenter.nl
10
- Requires-Python: >=3.9,<4.0
10
+ Requires-Python: >=3.10,<4.0
11
11
  Classifier: License :: OSI Approved :: Apache Software License
12
12
  Classifier: Programming Language :: Python
13
13
  Classifier: Programming Language :: Python :: 3
14
- Classifier: Programming Language :: Python :: 3.9
15
14
  Classifier: Programming Language :: Python :: 3.10
16
15
  Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
17
  Requires-Dist: numpy (>=1.24.1,<2.0.0)
18
18
  Requires-Dist: pandas (>=2.1.3,<3.0.0)
19
19
  Project-URL: Repository, https://github.com/biomarkersParkinson/tsdf
@@ -25,7 +25,7 @@ Description-Content-Type: text/markdown
25
25
  | Badges | |
26
26
  |:----:|----|
27
27
  | **Packages and Releases** | [![Latest release](https://img.shields.io/github/release/biomarkersparkinson/tsdf.svg)](https://github.com/biomarkersparkinson/tsdf/releases/latest) [![PyPI](https://img.shields.io/pypi/v/tsdf.svg)](https://pypi.python.org/pypi/tsdf/) [![Static Badge](https://img.shields.io/badge/RSD-tsdf-lib)](https://research-software-directory.org/software/tsdf) |
28
- | **Build Status** | [![](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/) ![Python package](https://github.com/biomarkersparkinson/tsdf/workflows/Python%20package/badge.svg) |
28
+ | **Build Status** | [![](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/) ![Python package](https://github.com/biomarkersparkinson/tsdf/workflows/Python%20package/badge.svg) [![pytype Type Check](https://github.com/biomarkersParkinson/tsdf/actions/workflows/pytype-checking.yml/badge.svg)](https://github.com/biomarkersParkinson/tsdf/actions/workflows/pytype-checking.yml) |
29
29
  | **DOI** | [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.7867899.svg)](https://doi.org/10.5281/zenodo.7867899) |
30
30
  | **License** | [![GitHub license](https://img.shields.io/github/license/biomarkersParkinson/tsdf)](https://github.com/biomarkersparkinson/tsdf/blob/main/LICENSE) |
31
31
  | **Fairness** | [![fair-software.eu](https://img.shields.io/badge/fair--software.eu-%E2%97%8F%20%20%E2%97%8F%20%20%E2%97%8F%20%20%E2%97%8F%20%20%E2%97%8F-green)](https://fair-software.eu) [![OpenSSF Best Practices](https://bestpractices.coreinfrastructure.org/projects/8083/badge)](https://www.bestpractices.dev/projects/8083) |
@@ -38,7 +38,7 @@ A package ([documentation](https://biomarkersparkinson.github.io/tsdf/)) to load
38
38
 
39
39
  ### Using `pip`
40
40
 
41
- The package is available in PyPi and requires [Python 3.9](https://www.python.org/downloads/) or higher. It can be installed using:
41
+ The package is available in PyPi and requires [Python 3.10](https://www.python.org/downloads/) or higher. It can be installed using:
42
42
 
43
43
  ```bash
44
44
  $ pip install tsdf
@@ -59,17 +59,19 @@ poetry run pytest
59
59
 
60
60
  ### Building the documentation
61
61
 
62
- We use [mkdocs](https://www.mkdocs.org/) to build the documentation. If you want to build the documentation locally, the following commands will prove useful:
62
+ We use [Sphinx](https://www.sphinx-doc.org/) to build the documentation. Use this command to build the documentation locally:
63
63
 
64
64
  ```bash
65
- mkdocs build # build the documentation
66
- mkdocs serve # serve the documentation on a local server
67
- mkdocs gh-deploy # deploy the documentation to GitHub pages
65
+ poetry run make html --directory docs
68
66
  ```
69
67
 
70
68
  ## Contributing
71
69
 
72
- Interested in contributing? Check out the contributing guidelines. Please note that this project is released with a Code of Conduct. By contributing to this project, you agree to abide by its terms.
70
+ We welcome contributions! Please see our [Contributing Guidelines](CONTRIBUTING.md) for more details on coding standards, how to get started, and the submission process.
71
+
72
+ ## Code of Conduct
73
+
74
+ To ensure a welcoming and respectful community, all contributors and participants are expected to adhere to our [Code of Conduct](CONDUCT.md). By participating in this project, you agree to abide by its terms.
73
75
 
74
76
  ## License
75
77
 
@@ -0,0 +1,17 @@
1
+ tsdf/__init__.py,sha256=1XpOrMtNGP815j8U6GqIClsb9hnvsC78uVHOzTtrRwI,894
2
+ tsdf/constants.py,sha256=2b_X9JKG18Xno1xo3ZWMFsJtsYRgCsu6J5cNbKqLjVY,1246
3
+ tsdf/file_utils.py,sha256=NlhwgPUPTFUY0gsfVPm9EdbKhgKLMXEFgcgS_g4MC-4,907
4
+ tsdf/legacy_tsdf_utils.py,sha256=ykE1taqkOpbZkoZmtCSJZXd9uFS_VvpZcLUH7MfhYqU,4136
5
+ tsdf/numpy_utils.py,sha256=ma87nmF9eYu0oRVqvtWC2uTvShuvkBokQmVlOCbwhoQ,2421
6
+ tsdf/parse_metadata.py,sha256=OtzCKWaM7Mg0GdS3H0V6i1Cj4liQ-mEG6OcfaqKJOy4,9859
7
+ tsdf/read_binary.py,sha256=G-EyiioIP_JxjYduJUujLbKBlfaV8eydRNd4hrBTGVw,4113
8
+ tsdf/read_tsdf.py,sha256=vhAT7vO_NVEmQUg1rij3eUk5fBWOn5tva1d9MtGpxKc,3103
9
+ tsdf/tsdfmetadata.py,sha256=EBq-Z8f3Eu92R0i174xNo9KfTsPm2m_VbbXD-7S42fk,4831
10
+ tsdf/validator.py,sha256=8PFB0PHqKKHtDpddyGIIKeqVqvDqcip7Bk7bY_wYzsw,1579
11
+ tsdf/write_binary.py,sha256=G5QiUXdpYgCZbS4pKhg8tFcqZU7FyaZGTzcNmZwXaPw,2425
12
+ tsdf/write_tsdf.py,sha256=Ivudc5g1l56R4LX9KfRtRXE1O8KY7uLb3U3XvzYDzM8,6090
13
+ tsdf-0.6.0.dist-info/LICENSE,sha256=ps-dSIu_bKnNIZ3_A9i8DjNNcN21Dg81znC5pTQKg3M,9748
14
+ tsdf-0.6.0.dist-info/METADATA,sha256=uBwU21vrGsnLiA7Hu3HXowqF5qMxlZHixF1_8uaHZ8o,4114
15
+ tsdf-0.6.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
16
+ tsdf-0.6.0.dist-info/entry_points.txt,sha256=Bsc8N48btp0lRWhtEwmOOmzZuvdlYDfVSkHFrHK2EXQ,53
17
+ tsdf-0.6.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.7.0
2
+ Generator: poetry-core 1.9.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,17 +0,0 @@
1
- tsdf/__init__.py,sha256=1XpOrMtNGP815j8U6GqIClsb9hnvsC78uVHOzTtrRwI,894
2
- tsdf/constants.py,sha256=2b_X9JKG18Xno1xo3ZWMFsJtsYRgCsu6J5cNbKqLjVY,1246
3
- tsdf/file_utils.py,sha256=NlhwgPUPTFUY0gsfVPm9EdbKhgKLMXEFgcgS_g4MC-4,907
4
- tsdf/legacy_tsdf_utils.py,sha256=ykE1taqkOpbZkoZmtCSJZXd9uFS_VvpZcLUH7MfhYqU,4136
5
- tsdf/numpy_utils.py,sha256=TKjKqX5QeI-yq6izVcFaKnLVE5LER3xWTBoDYsJMuLM,2367
6
- tsdf/parse_metadata.py,sha256=vJxFGL5QcaMOEFr1hvr9eEcoV4kykIyorcvIBnYY2iI,8773
7
- tsdf/read_binary.py,sha256=G-EyiioIP_JxjYduJUujLbKBlfaV8eydRNd4hrBTGVw,4113
8
- tsdf/read_tsdf.py,sha256=A7zIqdjGgKr1PCOiETaKybuvKc-KNIXALenYAoXMlFQ,3077
9
- tsdf/tsdfmetadata.py,sha256=0ILoFLW2h6a1RtbgGNH1hvhdQoVz_WRvSkpPJMbAdWA,3111
10
- tsdf/validator.py,sha256=8PFB0PHqKKHtDpddyGIIKeqVqvDqcip7Bk7bY_wYzsw,1579
11
- tsdf/write_binary.py,sha256=JamPBGFCigyV3SFRJqVE7lCeJB4L6TPuZ9J6ceMXMbM,2409
12
- tsdf/write_tsdf.py,sha256=t_Yd9vI4qJdEd3KPN4gVCJAjEFlpF-Cq_PZbOGaSDwY,6034
13
- tsdf-0.5.1.dist-info/LICENSE,sha256=ps-dSIu_bKnNIZ3_A9i8DjNNcN21Dg81znC5pTQKg3M,9748
14
- tsdf-0.5.1.dist-info/METADATA,sha256=HOQWnlHiJq07grdJ3-W3cnDTL4b7E2yag0kkxOIVcY4,3874
15
- tsdf-0.5.1.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
16
- tsdf-0.5.1.dist-info/entry_points.txt,sha256=Bsc8N48btp0lRWhtEwmOOmzZuvdlYDfVSkHFrHK2EXQ,53
17
- tsdf-0.5.1.dist-info/RECORD,,
File without changes