harp-python 0.2.0__tar.gz → 0.3.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.
- harp_python-0.3.0/.github/workflows/build.yml +37 -0
- {harp-python-0.2.0 → harp_python-0.3.0}/PKG-INFO +19 -3
- {harp-python-0.2.0 → harp_python-0.3.0}/README.md +13 -1
- {harp-python-0.2.0 → harp_python-0.3.0}/harp/__init__.py +2 -0
- {harp-python-0.2.0 → harp_python-0.3.0}/harp/io.py +8 -15
- {harp-python-0.2.0 → harp_python-0.3.0}/harp/model.py +6 -17
- {harp-python-0.2.0 → harp_python-0.3.0}/harp/reader.py +28 -14
- {harp-python-0.2.0 → harp_python-0.3.0}/harp/schema.py +9 -11
- {harp-python-0.2.0 → harp_python-0.3.0}/harp_python.egg-info/PKG-INFO +19 -3
- {harp-python-0.2.0 → harp_python-0.3.0}/harp_python.egg-info/SOURCES.txt +1 -0
- {harp-python-0.2.0 → harp_python-0.3.0}/harp_python.egg-info/requires.txt +5 -1
- {harp-python-0.2.0 → harp_python-0.3.0}/pyproject.toml +24 -14
- {harp-python-0.2.0 → harp_python-0.3.0}/tests/params.py +4 -2
- {harp-python-0.2.0 → harp_python-0.3.0}/tests/test_io.py +7 -10
- {harp-python-0.2.0 → harp_python-0.3.0}/tests/test_reader.py +1 -0
- {harp-python-0.2.0 → harp_python-0.3.0}/tests/test_schema.py +1 -0
- {harp-python-0.2.0 → harp_python-0.3.0}/.gitignore +0 -0
- {harp-python-0.2.0 → harp_python-0.3.0}/.gitmodules +0 -0
- {harp-python-0.2.0 → harp_python-0.3.0}/LICENSE +0 -0
- {harp-python-0.2.0 → harp_python-0.3.0}/MANIFEST.in +0 -0
- {harp-python-0.2.0 → harp_python-0.3.0}/harp/common.yml +0 -0
- {harp-python-0.2.0 → harp_python-0.3.0}/harp_python.egg-info/dependency_links.txt +0 -0
- {harp-python-0.2.0 → harp_python-0.3.0}/harp_python.egg-info/top_level.txt +0 -0
- {harp-python-0.2.0 → harp_python-0.3.0}/setup.cfg +0 -0
- {harp-python-0.2.0 → harp_python-0.3.0}/tests/__init__.py +0 -0
- {harp-python-0.2.0 → harp_python-0.3.0}/tests/data/device.yml +0 -0
- {harp-python-0.2.0 → harp_python-0.3.0}/tests/data/device_0.bin +0 -0
- {harp-python-0.2.0 → harp_python-0.3.0}/tests/data/write_0.bin +0 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Builds the python environment; linter and formatting via ruff; type annotations via pyright;
|
|
2
|
+
# tests via pytest; reports test coverage via pytest-cov.
|
|
3
|
+
|
|
4
|
+
name: build
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
branches: ['*']
|
|
8
|
+
pull_request:
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build_run_tests:
|
|
13
|
+
name: Python ${{ matrix.python-version }} on ${{ matrix.os }}
|
|
14
|
+
runs-on: ${{ matrix.os }}
|
|
15
|
+
if: github.event.pull_request.draft == false
|
|
16
|
+
strategy:
|
|
17
|
+
matrix:
|
|
18
|
+
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
19
|
+
python-version: [3.9, 3.11]
|
|
20
|
+
fail-fast: false
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout
|
|
23
|
+
uses: actions/checkout@v4
|
|
24
|
+
- name: Setup Python
|
|
25
|
+
uses: actions/setup-python@v5
|
|
26
|
+
with:
|
|
27
|
+
python-version: ${{ matrix.python-version }}
|
|
28
|
+
cache: 'pip'
|
|
29
|
+
- name: Install dependencies
|
|
30
|
+
run: pip install -e .[dev]
|
|
31
|
+
|
|
32
|
+
- name: ruff
|
|
33
|
+
run: ruff check .
|
|
34
|
+
- name: pyright
|
|
35
|
+
run: pyright .
|
|
36
|
+
- name: pytest
|
|
37
|
+
run: pytest --cov harp
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: harp-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: A low-level interface for loading binary Harp protocol data
|
|
5
5
|
Author-email: Goncalo Lopes <g.lopes@neurogears.org>
|
|
6
6
|
License: MIT License
|
|
@@ -20,15 +20,31 @@ Requires-Dist: pydantic-yaml
|
|
|
20
20
|
Requires-Dist: pandas
|
|
21
21
|
Provides-Extra: dev
|
|
22
22
|
Requires-Dist: datamodel-code-generator; extra == "dev"
|
|
23
|
+
Requires-Dist: pandas-stubs; extra == "dev"
|
|
23
24
|
Requires-Dist: pytest; extra == "dev"
|
|
24
|
-
Requires-Dist:
|
|
25
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
26
|
+
Requires-Dist: pyright; extra == "dev"
|
|
27
|
+
Requires-Dist: ruff; extra == "dev"
|
|
28
|
+
Requires-Dist: codespell; extra == "dev"
|
|
25
29
|
Provides-Extra: jupyter
|
|
26
30
|
Requires-Dist: ipykernel; extra == "jupyter"
|
|
27
31
|
Requires-Dist: matplotlib; extra == "jupyter"
|
|
28
32
|
|
|
29
33
|
# harp-python
|
|
30
34
|
|
|
31
|
-
A low-level interface to data collected with the [Harp](https://harp-tech.org/
|
|
35
|
+
A low-level interface to data collected with the [Harp binary protocol](https://harp-tech.org/protocol/BinaryProtocol-8bit.html).
|
|
36
|
+
|
|
37
|
+
## How to install
|
|
38
|
+
|
|
39
|
+
The source code is currently hosted on [GitHub](https://github.com/harp-tech/harp-python).
|
|
40
|
+
|
|
41
|
+
Binary installers for the latest released version are available at the [Python Package Index (PyPI)](https://pypi.org/project/harp-python) and can be installed using `pip`.
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
pip install harp-python
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The list of changes between each release can be found [here](https://github.com/harp-tech/harp-python/releases).
|
|
32
48
|
|
|
33
49
|
## Data model
|
|
34
50
|
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
# harp-python
|
|
2
2
|
|
|
3
|
-
A low-level interface to data collected with the [Harp](https://harp-tech.org/
|
|
3
|
+
A low-level interface to data collected with the [Harp binary protocol](https://harp-tech.org/protocol/BinaryProtocol-8bit.html).
|
|
4
|
+
|
|
5
|
+
## How to install
|
|
6
|
+
|
|
7
|
+
The source code is currently hosted on [GitHub](https://github.com/harp-tech/harp-python).
|
|
8
|
+
|
|
9
|
+
Binary installers for the latest released version are available at the [Python Package Index (PyPI)](https://pypi.org/project/harp-python) and can be installed using `pip`.
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
pip install harp-python
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The list of changes between each release can be found [here](https://github.com/harp-tech/harp-python/releases).
|
|
4
16
|
|
|
5
17
|
## Data model
|
|
6
18
|
|
|
@@ -2,9 +2,10 @@ from datetime import datetime
|
|
|
2
2
|
from enum import IntEnum
|
|
3
3
|
from os import PathLike
|
|
4
4
|
from typing import Any, BinaryIO, Optional, Union
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
import numpy as np
|
|
7
7
|
import pandas as pd
|
|
8
|
+
from pandas._typing import Axes
|
|
8
9
|
|
|
9
10
|
REFERENCE_EPOCH = datetime(1904, 1, 1)
|
|
10
11
|
"""The reference epoch for UTC harp time."""
|
|
@@ -73,29 +74,23 @@ def read(
|
|
|
73
74
|
"""
|
|
74
75
|
data = np.fromfile(file, dtype=np.uint8)
|
|
75
76
|
if len(data) == 0:
|
|
76
|
-
return pd.DataFrame(
|
|
77
|
-
columns=columns, index=pd.Index([], dtype=np.float64, name="Time")
|
|
78
|
-
)
|
|
77
|
+
return pd.DataFrame(columns=columns, index=pd.Index([], dtype=np.float64, name="Time"))
|
|
79
78
|
|
|
80
79
|
if address is not None and address != data[2]:
|
|
81
80
|
raise ValueError(f"expected address {address} but got {data[2]}")
|
|
82
81
|
|
|
83
82
|
index = None
|
|
84
|
-
stride = data[1] + 2
|
|
83
|
+
stride = int(data[1] + 2)
|
|
85
84
|
nrows = len(data) // stride
|
|
86
85
|
payloadtype = data[4]
|
|
87
86
|
payloadoffset = 5
|
|
88
87
|
if payloadtype & 0x10 != 0:
|
|
89
|
-
seconds = np.ndarray(
|
|
90
|
-
nrows, dtype=np.uint32, buffer=data, offset=payloadoffset, strides=stride
|
|
91
|
-
)
|
|
88
|
+
seconds = np.ndarray(nrows, dtype=np.uint32, buffer=data, offset=payloadoffset, strides=stride)
|
|
92
89
|
payloadoffset += 4
|
|
93
|
-
micros = np.ndarray(
|
|
94
|
-
nrows, dtype=np.uint16, buffer=data, offset=payloadoffset, strides=stride
|
|
95
|
-
)
|
|
90
|
+
micros = np.ndarray(nrows, dtype=np.uint16, buffer=data, offset=payloadoffset, strides=stride)
|
|
96
91
|
payloadoffset += 2
|
|
97
92
|
time = micros * _SECONDS_PER_TICK + seconds
|
|
98
|
-
payloadtype = payloadtype & ~0x10
|
|
93
|
+
payloadtype = payloadtype & ~np.uint8(0x10)
|
|
99
94
|
if epoch is not None:
|
|
100
95
|
time = epoch + pd.to_timedelta(time, "s") # type: ignore
|
|
101
96
|
index = pd.Series(time)
|
|
@@ -121,9 +116,7 @@ def read(
|
|
|
121
116
|
|
|
122
117
|
result = pd.DataFrame(payload, index=index, columns=columns)
|
|
123
118
|
if keep_type:
|
|
124
|
-
msgtype = np.ndarray(
|
|
125
|
-
nrows, dtype=np.uint8, buffer=data, offset=0, strides=stride
|
|
126
|
-
)
|
|
119
|
+
msgtype = np.ndarray(nrows, dtype=np.uint8, buffer=data, offset=0, strides=stride)
|
|
127
120
|
msgtype = pd.Categorical.from_codes(msgtype, categories=_messagetypes) # type: ignore
|
|
128
121
|
result[MessageType.__name__] = msgtype
|
|
129
122
|
return result
|
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
7
|
from enum import Enum
|
|
8
|
-
from typing import Dict, List, Optional, Union
|
|
9
|
-
from typing_extensions import Annotated
|
|
8
|
+
from typing import Annotated, Dict, List, Optional, Union
|
|
10
9
|
|
|
11
10
|
from pydantic import (
|
|
12
11
|
BaseModel,
|
|
@@ -136,16 +135,12 @@ class Visibility(Enum):
|
|
|
136
135
|
class Register(BaseModel):
|
|
137
136
|
address: Annotated[
|
|
138
137
|
int,
|
|
139
|
-
Field(
|
|
140
|
-
le=255, description="Specifies the unique 8-bit address of the register."
|
|
141
|
-
),
|
|
138
|
+
Field(le=255, description="Specifies the unique 8-bit address of the register."),
|
|
142
139
|
]
|
|
143
140
|
type: Annotated[PayloadType, BeforeValidator(lambda v: PayloadType[v])]
|
|
144
141
|
length: Annotated[
|
|
145
142
|
Optional[int],
|
|
146
|
-
Field(
|
|
147
|
-
ge=1, default=1, description="Specifies the length of the register payload."
|
|
148
|
-
),
|
|
143
|
+
Field(ge=1, default=1, description="Specifies the length of the register payload."),
|
|
149
144
|
]
|
|
150
145
|
access: Union[Access, List[Access]] = Field(
|
|
151
146
|
..., description="Specifies the expected use of the register."
|
|
@@ -191,12 +186,6 @@ class Registers(BaseModel):
|
|
|
191
186
|
|
|
192
187
|
class Model(Registers):
|
|
193
188
|
device: str = Field(..., description="Specifies the name of the device.")
|
|
194
|
-
whoAmI: int = Field(
|
|
195
|
-
|
|
196
|
-
)
|
|
197
|
-
firmwareVersion: str = Field(
|
|
198
|
-
..., description="Specifies the semantic version of the device firmware."
|
|
199
|
-
)
|
|
200
|
-
hardwareTargets: str = Field(
|
|
201
|
-
..., description="Specifies the semantic version of the device hardware."
|
|
202
|
-
)
|
|
189
|
+
whoAmI: int = Field(..., description="Specifies the unique identifier for this device type.")
|
|
190
|
+
firmwareVersion: str = Field(..., description="Specifies the semantic version of the device firmware.")
|
|
191
|
+
hardwareTargets: str = Field(..., description="Specifies the semantic version of the device hardware.")
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import os
|
|
2
|
+
from collections import UserDict
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from functools import partial
|
|
2
6
|
from math import log2
|
|
3
7
|
from os import PathLike
|
|
4
8
|
from pathlib import Path
|
|
5
|
-
from
|
|
6
|
-
|
|
7
|
-
from dataclasses import dataclass
|
|
9
|
+
from typing import Any, BinaryIO, Callable, Iterable, Mapping, Optional, Protocol, Union
|
|
10
|
+
|
|
8
11
|
from numpy import dtype
|
|
9
12
|
from pandas import DataFrame, Series
|
|
10
|
-
from typing import Any, BinaryIO, Callable, Iterable, Optional, Protocol, Union
|
|
11
13
|
from pandas._typing import Axes
|
|
12
|
-
|
|
14
|
+
|
|
13
15
|
from harp.io import MessageType, read
|
|
16
|
+
from harp.model import BitMask, GroupMask, Model, PayloadMember, Register
|
|
14
17
|
from harp.schema import read_schema
|
|
15
18
|
|
|
16
19
|
|
|
@@ -27,8 +30,7 @@ class _ReadRegister(Protocol):
|
|
|
27
30
|
file: Optional[Union[str, bytes, PathLike[Any], BinaryIO]] = None,
|
|
28
31
|
epoch: Optional[datetime] = None,
|
|
29
32
|
keep_type: bool = False,
|
|
30
|
-
) -> DataFrame:
|
|
31
|
-
...
|
|
33
|
+
) -> DataFrame: ...
|
|
32
34
|
|
|
33
35
|
|
|
34
36
|
class RegisterReader:
|
|
@@ -44,13 +46,27 @@ class RegisterReader:
|
|
|
44
46
|
self.read = read
|
|
45
47
|
|
|
46
48
|
|
|
49
|
+
class RegisterMap(UserDict[str, RegisterReader]):
|
|
50
|
+
_address_map: Mapping[int, RegisterReader]
|
|
51
|
+
|
|
52
|
+
def __init__(self, registers: Mapping[str, RegisterReader]) -> None:
|
|
53
|
+
super().__init__(registers)
|
|
54
|
+
self._address_map = {value.register.address: value for value in registers.values()}
|
|
55
|
+
|
|
56
|
+
def __getitem__(self, key: Union[str, int]) -> RegisterReader:
|
|
57
|
+
if isinstance(key, int):
|
|
58
|
+
return self._address_map[key]
|
|
59
|
+
else:
|
|
60
|
+
return super().__getitem__(key)
|
|
61
|
+
|
|
62
|
+
|
|
47
63
|
class DeviceReader:
|
|
48
64
|
device: Model
|
|
49
|
-
registers:
|
|
65
|
+
registers: RegisterMap
|
|
50
66
|
|
|
51
|
-
def __init__(self, device: Model, registers:
|
|
67
|
+
def __init__(self, device: Model, registers: Mapping[str, RegisterReader]) -> None:
|
|
52
68
|
self.device = device
|
|
53
|
-
self.registers = registers
|
|
69
|
+
self.registers = RegisterMap(registers)
|
|
54
70
|
|
|
55
71
|
def __dir__(self) -> Iterable[str]:
|
|
56
72
|
return self.registers.keys()
|
|
@@ -214,7 +230,7 @@ def create_reader(
|
|
|
214
230
|
keep_type: bool = False,
|
|
215
231
|
):
|
|
216
232
|
"""Creates a device reader object from the specified dataset or schema.
|
|
217
|
-
|
|
233
|
+
|
|
218
234
|
Parameters
|
|
219
235
|
----------
|
|
220
236
|
device
|
|
@@ -249,9 +265,7 @@ def create_reader(
|
|
|
249
265
|
base_path = path / device.device if is_dir else path.parent / device.device
|
|
250
266
|
|
|
251
267
|
reg_readers = {
|
|
252
|
-
name: _create_register_parser(
|
|
253
|
-
device, name, _ReaderParams(base_path, epoch, keep_type)
|
|
254
|
-
)
|
|
268
|
+
name: _create_register_parser(device, name, _ReaderParams(base_path, epoch, keep_type))
|
|
255
269
|
for name in device.registers.keys()
|
|
256
270
|
}
|
|
257
271
|
return DeviceReader(device, reg_readers)
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
+
from importlib import resources
|
|
1
2
|
from os import PathLike
|
|
2
3
|
from typing import TextIO, Union
|
|
3
|
-
|
|
4
|
+
|
|
4
5
|
from pydantic_yaml import parse_yaml_raw_as
|
|
5
|
-
|
|
6
|
+
|
|
7
|
+
from harp.model import Model, Registers
|
|
6
8
|
|
|
7
9
|
|
|
8
10
|
def _read_common_registers() -> Registers:
|
|
9
11
|
file = resources.files(__package__) / "common.yml"
|
|
10
|
-
with file.open("
|
|
12
|
+
with file.open("r") as fileIO:
|
|
11
13
|
return parse_yaml_raw_as(Registers, fileIO.read())
|
|
12
14
|
|
|
13
15
|
|
|
14
|
-
def read_schema(
|
|
15
|
-
file: Union[str, PathLike, TextIO], include_common_registers: bool = True
|
|
16
|
-
) -> Model:
|
|
16
|
+
def read_schema(file: Union[str, PathLike, TextIO], include_common_registers: bool = True) -> Model:
|
|
17
17
|
"""Read and parse a device schema from the specified file.
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
Parameters
|
|
20
20
|
----------
|
|
21
21
|
file
|
|
@@ -35,14 +35,12 @@ def read_schema(
|
|
|
35
35
|
return read_schema(fileIO)
|
|
36
36
|
else:
|
|
37
37
|
schema = parse_yaml_raw_as(Model, file.read())
|
|
38
|
-
if
|
|
38
|
+
if "WhoAmI" not in schema.registers and include_common_registers:
|
|
39
39
|
common = _read_common_registers()
|
|
40
40
|
schema.registers = dict(common.registers, **schema.registers)
|
|
41
41
|
if common.bitMasks:
|
|
42
42
|
schema.bitMasks = (
|
|
43
|
-
common.bitMasks
|
|
44
|
-
if schema.bitMasks is None
|
|
45
|
-
else dict(common.bitMasks, **schema.bitMasks)
|
|
43
|
+
common.bitMasks if schema.bitMasks is None else dict(common.bitMasks, **schema.bitMasks)
|
|
46
44
|
)
|
|
47
45
|
if common.groupMasks:
|
|
48
46
|
schema.groupMasks = (
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: harp-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: A low-level interface for loading binary Harp protocol data
|
|
5
5
|
Author-email: Goncalo Lopes <g.lopes@neurogears.org>
|
|
6
6
|
License: MIT License
|
|
@@ -20,15 +20,31 @@ Requires-Dist: pydantic-yaml
|
|
|
20
20
|
Requires-Dist: pandas
|
|
21
21
|
Provides-Extra: dev
|
|
22
22
|
Requires-Dist: datamodel-code-generator; extra == "dev"
|
|
23
|
+
Requires-Dist: pandas-stubs; extra == "dev"
|
|
23
24
|
Requires-Dist: pytest; extra == "dev"
|
|
24
|
-
Requires-Dist:
|
|
25
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
26
|
+
Requires-Dist: pyright; extra == "dev"
|
|
27
|
+
Requires-Dist: ruff; extra == "dev"
|
|
28
|
+
Requires-Dist: codespell; extra == "dev"
|
|
25
29
|
Provides-Extra: jupyter
|
|
26
30
|
Requires-Dist: ipykernel; extra == "jupyter"
|
|
27
31
|
Requires-Dist: matplotlib; extra == "jupyter"
|
|
28
32
|
|
|
29
33
|
# harp-python
|
|
30
34
|
|
|
31
|
-
A low-level interface to data collected with the [Harp](https://harp-tech.org/
|
|
35
|
+
A low-level interface to data collected with the [Harp binary protocol](https://harp-tech.org/protocol/BinaryProtocol-8bit.html).
|
|
36
|
+
|
|
37
|
+
## How to install
|
|
38
|
+
|
|
39
|
+
The source code is currently hosted on [GitHub](https://github.com/harp-tech/harp-python).
|
|
40
|
+
|
|
41
|
+
Binary installers for the latest released version are available at the [Python Package Index (PyPI)](https://pypi.org/project/harp-python) and can be installed using `pip`.
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
pip install harp-python
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The list of changes between each release can be found [here](https://github.com/harp-tech/harp-python/releases).
|
|
32
48
|
|
|
33
49
|
## Data model
|
|
34
50
|
|
|
@@ -31,9 +31,14 @@ classifiers = [
|
|
|
31
31
|
[project.optional-dependencies]
|
|
32
32
|
dev = [
|
|
33
33
|
"datamodel-code-generator",
|
|
34
|
+
"pandas-stubs",
|
|
34
35
|
"pytest",
|
|
35
|
-
"
|
|
36
|
+
"pytest-cov",
|
|
37
|
+
"pyright",
|
|
38
|
+
"ruff",
|
|
39
|
+
"codespell"
|
|
36
40
|
]
|
|
41
|
+
|
|
37
42
|
jupyter = [
|
|
38
43
|
"ipykernel",
|
|
39
44
|
"matplotlib"
|
|
@@ -55,16 +60,21 @@ include = ["harp*"]
|
|
|
55
60
|
|
|
56
61
|
[tool.setuptools_scm]
|
|
57
62
|
|
|
58
|
-
[tool.
|
|
59
|
-
line-length =
|
|
60
|
-
target-version =
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
63
|
+
[tool.ruff]
|
|
64
|
+
line-length = 108
|
|
65
|
+
target-version = "py39"
|
|
66
|
+
exclude = [
|
|
67
|
+
"reflex-generator"
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
[tool.pyright]
|
|
71
|
+
venvPath = "."
|
|
72
|
+
venv = ".venv"
|
|
73
|
+
exclude = [
|
|
74
|
+
".venv/*",
|
|
75
|
+
"reflex-generator"
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
[tool.codespell]
|
|
79
|
+
skip = '.git,*.pdf,*.svg'
|
|
80
|
+
ignore-words-list = 'nd'
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
from dataclasses import dataclass
|
|
2
2
|
from os import PathLike
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from dataclasses import dataclass
|
|
5
4
|
from typing import Iterable, Optional, Type, Union
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
6
8
|
from harp.model import Model
|
|
7
9
|
|
|
8
10
|
datapath = Path(__file__).parent
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import pytest
|
|
2
|
-
import numpy as np
|
|
3
1
|
from contextlib import nullcontext
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import pytest
|
|
4
5
|
from pytest import mark
|
|
5
|
-
|
|
6
|
+
|
|
7
|
+
from harp.io import MessageType, read
|
|
6
8
|
from tests.params import DataFileParam
|
|
7
9
|
|
|
8
10
|
testdata = [
|
|
@@ -26,9 +28,7 @@ testdata = [
|
|
|
26
28
|
expected_error=ValueError,
|
|
27
29
|
),
|
|
28
30
|
DataFileParam(path="data/write_0.bin", expected_address=0, expected_rows=4),
|
|
29
|
-
DataFileParam(
|
|
30
|
-
path="data/write_0.bin", expected_address=0, expected_rows=4, keep_type=True
|
|
31
|
-
),
|
|
31
|
+
DataFileParam(path="data/write_0.bin", expected_address=0, expected_rows=4, keep_type=True),
|
|
32
32
|
]
|
|
33
33
|
|
|
34
34
|
|
|
@@ -45,10 +45,7 @@ def test_read(dataFile: DataFileParam):
|
|
|
45
45
|
)
|
|
46
46
|
assert len(data) == dataFile.expected_rows
|
|
47
47
|
if dataFile.keep_type:
|
|
48
|
-
assert
|
|
49
|
-
MessageType.__name__ in data.columns
|
|
50
|
-
and data[MessageType.__name__].dtype == "category"
|
|
51
|
-
)
|
|
48
|
+
assert MessageType.__name__ in data.columns and data[MessageType.__name__].dtype == "category"
|
|
52
49
|
|
|
53
50
|
if dataFile.expected_cols:
|
|
54
51
|
for col in dataFile.expected_cols:
|
|
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
|