Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new DeviceReader constructors #26

Open
wants to merge 35 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
b64f17f
Add new constructor methods
bruno-f-cruz May 9, 2024
ebd1956
Deprecate function
bruno-f-cruz May 9, 2024
2e51fc4
Document methods
bruno-f-cruz May 9, 2024
24b8977
Linting
bruno-f-cruz May 9, 2024
a304318
Add isort and codespell linters and respective settings (#28)
bruno-f-cruz May 20, 2024
caaa619
Add extended skip settings for isort
glopesdev May 21, 2024
c84e835
Run black formatting
glopesdev May 21, 2024
41b5c7a
Avoid importing typing_extensions
glopesdev May 21, 2024
df62f75
Run isort formatting
glopesdev May 21, 2024
177c4af
Remove redundant file mode
glopesdev May 21, 2024
c90387e
Merge pull request #29 from harp-tech/gl-dev
bruno-f-cruz May 21, 2024
f684ed3
Avoid silent overflow for numpy compatibility
glopesdev Oct 22, 2024
750bb53
Ensure stride uses default int type
glopesdev Oct 29, 2024
0bf15f9
Merge pull request #35 from harp-tech/gl-dev
glopesdev Oct 29, 2024
6ee0dc4
Replace black and isort with ruff and pyright
glopesdev Oct 30, 2024
ec7db7b
Add CI pipeline and code coverage
glopesdev Oct 30, 2024
110250e
Apply ruff recommendations
glopesdev Oct 30, 2024
ff87f12
Apply pyright recommendations
glopesdev Oct 30, 2024
3f7cb51
Update matrix job names
glopesdev Oct 30, 2024
41d9038
Avoid using environment in CI pipeline
glopesdev Oct 30, 2024
849f30d
Cache pip dependencies
glopesdev Oct 30, 2024
5bc3ebe
Merge pull request #36 from harp-tech/gl-dev
glopesdev Oct 30, 2024
9c8bb7d
Add new constructor methods
bruno-f-cruz May 9, 2024
a890991
Deprecate function
bruno-f-cruz May 9, 2024
1b3d438
Document methods
bruno-f-cruz May 9, 2024
a76c6f0
Linting
bruno-f-cruz May 9, 2024
dbdbaa3
Merge branch 'feat-device-reader-constructors' of https://github.com/…
bruno-f-cruz Dec 13, 2024
828cd3b
Fix rebasing
bruno-f-cruz Dec 13, 2024
13a6862
Add deprecated decorator
bruno-f-cruz Dec 13, 2024
3cefa8e
Fix rebasing
bruno-f-cruz Dec 13, 2024
89870d9
Favor library's deprecated decorator
bruno-f-cruz Dec 13, 2024
83397d1
Linting
bruno-f-cruz Dec 13, 2024
48dadeb
Add requests as dependency
bruno-f-cruz Dec 13, 2024
4c39bd8
Move decorator to separate private helper module to prevent circular …
bruno-f-cruz Dec 13, 2024
132cb73
Ignore warnings emitted by deprecated decorator
bruno-f-cruz Dec 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Builds the python environment; linter and formatting via ruff; type annotations via pyright;
# tests via pytest; reports test coverage via pytest-cov.

name: build
on:
push:
branches: ['*']
pull_request:
workflow_dispatch:

jobs:
build_run_tests:
name: Python ${{ matrix.python-version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
if: github.event.pull_request.draft == false
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: [3.9, 3.11]
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
- name: Install dependencies
run: pip install -e .[dev]

- name: ruff
run: ruff check .
- name: pyright
run: pyright .
- name: pytest
run: pytest --cov harp
3 changes: 3 additions & 0 deletions harp/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from harp.io import REFERENCE_EPOCH, MessageType, read
from harp.reader import create_reader
from harp.schema import read_schema


__all__ = ["REFERENCE_EPOCH", "MessageType", "read", "create_reader", "read_schema"]
20 changes: 20 additions & 0 deletions harp/_helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import warnings
import functools


def deprecated(message):
# This decorator is only available from the stdlib warnings module in Python 3.13
# Making it available here for compatibility with older versions
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
warnings.warn(
f"Call to deprecated function {func.__name__}: {message}",
category=DeprecationWarning,
stacklevel=1,
)
return func(*args, **kwargs)

return wrapper

return decorator
23 changes: 8 additions & 15 deletions harp/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
from enum import IntEnum
from os import PathLike
from typing import Any, BinaryIO, Optional, Union
from pandas._typing import Axes

import numpy as np
import pandas as pd
from pandas._typing import Axes

REFERENCE_EPOCH = datetime(1904, 1, 1)
"""The reference epoch for UTC harp time."""
Expand Down Expand Up @@ -73,29 +74,23 @@ def read(
"""
data = np.fromfile(file, dtype=np.uint8)
if len(data) == 0:
return pd.DataFrame(
columns=columns, index=pd.Index([], dtype=np.float64, name="Time")
)
return pd.DataFrame(columns=columns, index=pd.Index([], dtype=np.float64, name="Time"))

if address is not None and address != data[2]:
raise ValueError(f"expected address {address} but got {data[2]}")

index = None
stride = data[1] + 2
stride = int(data[1] + 2)
nrows = len(data) // stride
payloadtype = data[4]
payloadoffset = 5
if payloadtype & 0x10 != 0:
seconds = np.ndarray(
nrows, dtype=np.uint32, buffer=data, offset=payloadoffset, strides=stride
)
seconds = np.ndarray(nrows, dtype=np.uint32, buffer=data, offset=payloadoffset, strides=stride)
payloadoffset += 4
micros = np.ndarray(
nrows, dtype=np.uint16, buffer=data, offset=payloadoffset, strides=stride
)
micros = np.ndarray(nrows, dtype=np.uint16, buffer=data, offset=payloadoffset, strides=stride)
payloadoffset += 2
time = micros * _SECONDS_PER_TICK + seconds
payloadtype = payloadtype & ~0x10
payloadtype = payloadtype & ~np.uint8(0x10)
if epoch is not None:
time = epoch + pd.to_timedelta(time, "s") # type: ignore
index = pd.Series(time)
Expand All @@ -121,9 +116,7 @@ def read(

result = pd.DataFrame(payload, index=index, columns=columns)
if keep_type:
msgtype = np.ndarray(
nrows, dtype=np.uint8, buffer=data, offset=0, strides=stride
)
msgtype = np.ndarray(nrows, dtype=np.uint8, buffer=data, offset=0, strides=stride)
msgtype = pd.Categorical.from_codes(msgtype, categories=_messagetypes) # type: ignore
result[MessageType.__name__] = msgtype
return result
32 changes: 7 additions & 25 deletions harp/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,9 @@
from __future__ import annotations

from enum import Enum
from typing import Dict, List, Optional, Union
from typing_extensions import Annotated
from typing import Annotated, Dict, List, Optional, Union

from pydantic import (
BaseModel,
BeforeValidator,
ConfigDict,
Field,
RootModel,
field_serializer,
)
from pydantic import BaseModel, BeforeValidator, ConfigDict, Field, RootModel, field_serializer


class PayloadType(str, Enum):
Expand Down Expand Up @@ -136,16 +128,12 @@ class Visibility(Enum):
class Register(BaseModel):
address: Annotated[
int,
Field(
le=255, description="Specifies the unique 8-bit address of the register."
),
Field(le=255, description="Specifies the unique 8-bit address of the register."),
]
type: Annotated[PayloadType, BeforeValidator(lambda v: PayloadType[v])]
length: Annotated[
Optional[int],
Field(
ge=1, default=1, description="Specifies the length of the register payload."
),
Field(ge=1, default=1, description="Specifies the length of the register payload."),
]
access: Union[Access, List[Access]] = Field(
..., description="Specifies the expected use of the register."
Expand Down Expand Up @@ -191,12 +179,6 @@ class Registers(BaseModel):

class Model(Registers):
device: str = Field(..., description="Specifies the name of the device.")
whoAmI: int = Field(
..., description="Specifies the unique identifier for this device type."
)
firmwareVersion: str = Field(
..., description="Specifies the semantic version of the device firmware."
)
hardwareTargets: str = Field(
..., description="Specifies the semantic version of the device hardware."
)
whoAmI: int = Field(..., description="Specifies the unique identifier for this device type.")
firmwareVersion: str = Field(..., description="Specifies the semantic version of the device firmware.")
hardwareTargets: str = Field(..., description="Specifies the semantic version of the device hardware.")
Loading
Loading