Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
BasedOnStyle: LLVM
IndentWidth: 4
ColumnLimit: 100
AllowShortFunctionsOnASingleLine: Empty
AlignConsecutiveAssignments: false
PointerAlignment: Left
SpaceBeforeParens: Never
BreakBeforeBraces: Linux
IndentCaseLabels: false
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ jobs:
python -m unittest
- name: Test DBC Files
run: |
cantools dump tests/outputs/test.dbc
cantools dump tests/outputs/test.dbc
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ jobs:
- name: Build docs
run: |
cd docs
make html SPHINXOPTS="-W --keep-going -n"
make html SPHINXOPTS="-W --keep-going -n"
57 changes: 57 additions & 0 deletions .pre-commit-README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Pre-commit Hooks for Avlos

This project uses [pre-commit](https://pre-commit.com/) to automatically format and lint code before commits.

## Setup

1. Install pre-commit (if not already installed):
```bash
pip install pre-commit
```

2. Install the git hooks:
```bash
pre-commit install
```

## What Gets Checked

The pre-commit hooks run the following checks:

- **black**: Python code formatting (line length: 127)
- **isort**: Import statement sorting
- **flake8**: Python linting (configured in setup.cfg)
- **trailing-whitespace**: Removes trailing whitespace
- **end-of-file-fixer**: Ensures files end with a newline
- **check-yaml**: Validates YAML syntax
- **check-added-large-files**: Prevents large files from being committed
- **check-merge-conflict**: Detects merge conflict markers
- **mixed-line-ending**: Ensures consistent line endings
- **rstcheck**: Validates RST documentation files

## Manual Execution

To run all hooks on all files (useful after initial setup or major changes):
```bash
pre-commit run --all-files
```

To run hooks on specific files:
```bash
pre-commit run --files path/to/file1.py path/to/file2.py
```

To skip hooks for a single commit (not recommended):
```bash
git commit --no-verify
```

## Configuration

- Pre-commit hooks are configured in `.pre-commit-config.yaml`
- Flake8 and isort settings are in `setup.cfg`
- clang-format style is configured in `.clang-format`

## CI Integration

The same linting checks run in GitHub Actions CI, so passing pre-commit locally ensures CI will pass.
43 changes: 43 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Pre-commit hooks for Avlos
# See https://pre-commit.com for more information
repos:
# Python code formatting with black
- repo: https://github.com/psf/black
rev: 24.1.1
hooks:
- id: black
language_version: python3
args: ['--line-length=127']

# Python import sorting
- repo: https://github.com/PyCQA/isort
rev: 5.13.2
hooks:
- id: isort
args: ['--profile', 'black', '--line-length', '127']

# Python linting with flake8
- repo: https://github.com/PyCQA/flake8
rev: 7.0.0
hooks:
- id: flake8
args: ['--max-line-length=127', '--max-complexity=10', '--extend-ignore=E203,W503']

# Trailing whitespace and file endings
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- id: check-merge-conflict
- id: mixed-line-ending

# RST file checking
- repo: https://github.com/rstcheck/rstcheck
rev: v6.2.0
hooks:
- id: rstcheck
args: ['--report-level=warning']
additional_dependencies: ['sphinx']
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@
"justMyCode": false
}
]
}
}
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@
"python.testing.pytestEnabled": false,
"python.testing.unittestEnabled": true,
"python.formatting.provider": "black"
}
}
1 change: 0 additions & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,3 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Stop writing serialization code twice. Stop debugging protocol mismatches.
- 🔒 **Type-safe across the boundary** → Catch errors at build time, not runtime
- 🎯 **Battle-tested** → Production-proven in [Tinymovr](https://tinymovr.com) motor controllers

[Αυλός (Avlόs)](https://en.wikipedia.org/wiki/Aulos) - _flute_, also _channel_.
[Αυλός (Avlόs)](https://en.wikipedia.org/wiki/Aulos) - _flute_, also _channel_.

<p align="center">
<img src="docs/diagram.png" width="800"/>
Expand Down Expand Up @@ -74,7 +74,7 @@ Given the above, Avlos can generate the following:

- [CAN DBC file](https://www.csselectronics.com/pages/can-dbc-file-database-intro) (CAN database), for every endpoint, for use with CAN-based comm channels.

In addition, Avlos will compute a checksum for the spec and add it as a variable to the implementation so that it can be retrieved by the client for comparing client and device specs.
In addition, Avlos will compute a checksum for the spec and add it as a variable to the implementation so that it can be retrieved by the client for comparing client and device specs.

The output location, as well as many other attributes of the files are flexible and easily configurable.

Expand Down Expand Up @@ -127,7 +127,7 @@ In addition, the object resulting from the deserialization of the spec can be us
import yaml
from avlos import deserialize
from myProject import myChannel # update this

device_description = ...
obj = deserialize(yaml.safe_load(device_description))
obj.set_channel(myChannel())
Expand Down Expand Up @@ -164,4 +164,3 @@ Between releases, development versions are automatically generated (e.g., `0.8.7
## 🔑 License

MIT

5 changes: 3 additions & 2 deletions avlos/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
# Package is not installed, version will be determined from git
try:
from setuptools_scm import get_version
__version__ = get_version(root='..', relative_to=__file__)

__version__ = get_version(root="..", relative_to=__file__)
except (ImportError, LookupError):
__version__ = "unknown"

__all__ = ["get_registry", "__version__"]
__all__ = ["get_registry", "__version__"]
3 changes: 2 additions & 1 deletion avlos/bitmask_field.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import enum
from marshmallow import fields, ValidationError

from marshmallow import ValidationError, fields


class BitmaskField(fields.Field):
Expand Down
8 changes: 5 additions & 3 deletions avlos/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
--config=<config_path> Path of the Avlos config file [default: ./avlos_config.yaml]
"""

import yaml
from typing import Dict
import logging
import pkg_resources
import urllib.request
from typing import Dict

import pkg_resources
import yaml
from docopt import docopt

from avlos.deserializer import deserialize
from avlos.processor import process_with_config_file

Expand Down
11 changes: 10 additions & 1 deletion avlos/datatypes.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from enum import Enum
from marshmallow import fields, ValidationError

from marshmallow import ValidationError, fields


class DataType(Enum):
Expand Down Expand Up @@ -54,6 +55,8 @@ def from_string(self, str_value):
DataType.UINT16: "uint16_t",
DataType.INT32: "int32_t",
DataType.UINT32: "uint32_t",
DataType.INT64: "int64_t",
DataType.UINT64: "uint64_t",
DataType.FLOAT: "float",
DataType.DOUBLE: "double",
DataType.STR: "char[]",
Expand All @@ -68,6 +71,8 @@ def from_string(self, str_value):
DataType.UINT16: int,
DataType.INT32: int,
DataType.UINT32: int,
DataType.INT64: int,
DataType.UINT64: int,
DataType.FLOAT: float,
DataType.DOUBLE: float,
DataType.STR: str,
Expand All @@ -82,6 +87,8 @@ def from_string(self, str_value):
DataType.UINT16: 2,
DataType.INT32: 4,
DataType.UINT32: 4,
DataType.INT64: 8,
DataType.UINT64: 8,
DataType.FLOAT: 4,
DataType.DOUBLE: 8,
DataType.STR: -1,
Expand All @@ -97,6 +104,8 @@ def from_string(self, str_value):
"uint16": DataType.UINT16,
"int32": DataType.INT32,
"uint32": DataType.UINT32,
"int64": DataType.INT64,
"uint64": DataType.UINT64,
"float": DataType.FLOAT,
"double": DataType.DOUBLE,
"string": DataType.STR,
Expand Down
2 changes: 1 addition & 1 deletion avlos/definitions/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from avlos.definitions.remote_attribute import RemoteAttribute
from avlos.definitions.remote_function import RemoteFunction, RemoteArgument, RemoteArgumentSchema
from avlos.definitions.remote_bitmask import RemoteBitmask
from avlos.definitions.remote_enum import RemoteEnum
from avlos.definitions.remote_function import RemoteArgument, RemoteArgumentSchema, RemoteFunction
from avlos.definitions.remote_node import RemoteNode, RemoteNodeSchema
from avlos.definitions.remote_root_node import RootNode, RootNodeSchema
51 changes: 43 additions & 8 deletions avlos/definitions/remote_attribute.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from avlos import get_registry
from avlos.mixins.comm_node import CommNode
from avlos.mixins.named_node import NamedNode
from avlos.mixins.meta_node import MetaNode
from avlos.mixins.impex_node import ImpexNode
from avlos.mixins.func_attr_node import FuncAttrNode
from avlos.mixins.impex_node import ImpexNode
from avlos.mixins.meta_node import MetaNode
from avlos.mixins.named_node import NamedNode


class RemoteAttribute(CommNode, NamedNode, MetaNode, ImpexNode, FuncAttrNode):
Expand Down Expand Up @@ -91,8 +91,43 @@ def str_dump(self):
format_str = "{0} [{1}]: {2:.6g}"
else:
format_str = "{0} [{1}]: {2}"
return format_str.format(
self.name,
self.dtype.nickname,
value
)
return format_str.format(self.name, self.dtype.nickname, value)

@property
def getter_strategy(self) -> str:
"""
Determine the strategy for getter implementation.

Returns:
'string' for char[] types, 'byval' for all other types
"""
if self.dtype.c_name == "char[]":
return "string"
return "byval"

@property
def setter_strategy(self) -> str:
"""
Determine the strategy for setter implementation.

Returns:
'string' for char[] types, 'byval' for all other types
"""
if self.dtype.c_name == "char[]":
return "string"
return "byval"

@property
def endpoint_function_name(self) -> str:
"""
Get the C function name for this endpoint.

Returns:
Function name in format 'avlos_parent_child_attribute'
"""
return "avlos_" + self.full_name.replace(".", "_")

@property
def is_string_type(self) -> bool:
"""Check if this attribute uses string/char[] type."""
return self.dtype.c_name == "char[]"
23 changes: 19 additions & 4 deletions avlos/definitions/remote_bitmask.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from avlos.mixins.comm_node import CommNode
from avlos.mixins.named_node import NamedNode
from avlos.mixins.meta_node import MetaNode
from avlos.mixins.impex_node import ImpexNode
from avlos.datatypes import DataType
from avlos.mixins.comm_node import CommNode
from avlos.mixins.func_attr_node import FuncAttrNode
from avlos.mixins.impex_node import ImpexNode
from avlos.mixins.meta_node import MetaNode
from avlos.mixins.named_node import NamedNode


class RemoteBitmask(CommNode, NamedNode, MetaNode, ImpexNode):
Expand Down Expand Up @@ -95,3 +95,18 @@ def str_dump(self):
self.name,
str(val) if val > 0 else "(no flags)",
)

@property
def endpoint_function_name(self) -> str:
"""Get the C function name for this endpoint."""
return "avlos_" + self.full_name.replace(".", "_")

@property
def getter_strategy(self) -> str:
"""Bitmasks always use byval strategy."""
return "byval"

@property
def setter_strategy(self) -> str:
"""Bitmasks always use byval strategy."""
return "byval"
23 changes: 19 additions & 4 deletions avlos/definitions/remote_enum.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from avlos.mixins.comm_node import CommNode
from avlos.mixins.named_node import NamedNode
from avlos.mixins.meta_node import MetaNode
from avlos.mixins.impex_node import ImpexNode
from avlos.datatypes import DataType
from avlos.mixins.comm_node import CommNode
from avlos.mixins.func_attr_node import FuncAttrNode
from avlos.mixins.impex_node import ImpexNode
from avlos.mixins.meta_node import MetaNode
from avlos.mixins.named_node import NamedNode


class RemoteEnum(CommNode, NamedNode, MetaNode, ImpexNode):
Expand Down Expand Up @@ -114,3 +114,18 @@ def str_dump(self):
"""
val = self.get_value()
return "{0}: {1}".format(self.name, str(val))

@property
def endpoint_function_name(self) -> str:
"""Get the C function name for this endpoint."""
return "avlos_" + self.full_name.replace(".", "_")

@property
def getter_strategy(self) -> str:
"""Enums always use byval strategy."""
return "byval"

@property
def setter_strategy(self) -> str:
"""Enums always use byval strategy."""
return "byval"
Loading