Skip to content
Open
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
2 changes: 1 addition & 1 deletion .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ The process is straight-forward.

- Fork the LVA repository.
- Write the code for your feature or fix.
- Ensure tests pass and linting succeeds (`./script/lint` and `./script/tests`).
- Ensure tests pass and linting succeeds (`prek run lint --all-files` and `prek run tests --all-files`).
- Create a Pull Request against the `main` branch.

## Feature suggestions
Expand Down
4 changes: 2 additions & 2 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ Tick exactly one box. CI derives the label from the ticked box.
## Checklist

- [ ] The code change is tested and works locally.
- [ ] `./script/lint` passes.
- [ ] `./script/tests` passes, and tests have been added/updated under `tests/` where applicable.
- [ ] `prek run lint --all-files` lint passes.
- [ ] `prek run tests --all-files` passes, and tests have been added/updated under `tests/` where applicable.
51 changes: 3 additions & 48 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,51 +11,6 @@ on:
types: [opened, synchronize, reopened]

jobs:
lint_black:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: "3.13"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
script/setup --dev
- name: Run black
run: ./script/lint_black

lint_flake8:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: "3.13"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
script/setup --dev
- name: Run flake8
run: ./script/lint_flake8

lint_isort:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: "3.13"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
script/setup --dev
- name: Run isort
run: ./script/lint_isort

lint_mypy:
runs-on: ubuntu-latest
steps:
Expand All @@ -72,7 +27,7 @@ jobs:
run: |
./script/lint_mypy

lint_pylint:
lint_ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
Expand All @@ -84,6 +39,6 @@ jobs:
run: |
python -m pip install --upgrade pip
script/setup --dev
- name: Run pylint
run: ./script/lint_pylint
- name: Run ruff
run: ./script/lint_ruff --no-auto

5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,7 @@ venv/
.env
dev.env
version.txt
version_githash.txt
version_githash.txt

__pycache__/
.ruff_cache/
16 changes: 16 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
repos:
- repo: local
hooks:
- id: lint
name: Lint (script/lint)
entry: ./script/lint
language: system
pass_filenames: false
types: [python]

- id: tests
name: Tests (script/tests)
entry: ./script/tests
language: system
pass_filenames: false
always_run: true
1 change: 1 addition & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"recommendations": [
"ms-python.python",
"ms-python.vscode-pylance",
"charliermarsh.ruff",
"kilo.kilocode"
]
}
5 changes: 3 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
"configurations": [
{
"name": "Run Linux Voice Assistant",
"type": "python",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/linux_voice_assistant/__main__.py",
"module": "linux_voice_assistant",
"cwd": "${workspaceFolder}",
"console": "integratedTerminal",
"justMyCode": true,
"envFile": "${workspaceFolder}/.env"
Expand Down
23 changes: 17 additions & 6 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,22 @@
"python.testing.pytestEnabled": true,
"python.testing.pytestArgs": ["tests"],
"python.testing.pytestAutoInclude": false,
"python.linting.enabled": true,
"python.linting.flake8Enabled": true,
"python.linting.mypyEnabled": true,
"python.formatting.provider": "none",
"python.terminal.activateEnvironment": true,
"python.terminal.executeInShell": true,
"python.pythonPath": "./.venv/bin/python"
}

"pylint.enabled": false,

"python.analysis.typeCheckingMode": "standard",

"ruff.lint.enable": true,
"ruff.organizeImports": true,

"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.ruff": "explicit",
"source.organizeImports.ruff": "explicit"
}
}
}
24 changes: 10 additions & 14 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,26 +41,23 @@

### Linting
```bash
./script/lint # Run all linting checks
./script/lint_black # Black formatting check (add --auto to fix)
./script/lint_isort # isort import sorting check (add --auto to fix)
./script/lint_flake8 # flake8 style checks
./script/lint_mypy # mypy type checking
./script/lint_pylint # pylint code quality checks
prek run lint --all-files # Run all linting checks (has to be done inside the dev venv)
./script/lint_ruff # Run Ruff
./script/lint_mypy # pylint code quality checks
```

### Testing
```bash
./script/tests # Run pytest unit tests
prek run tests --all-files # Run pytest unit tests (has to be done inside the dev venv)
```

## Code Quality Standards

- **Python**: 3.11, 3.12, 3.13 supported
- **Formatting**: Black (200 char line length, py312/py312 target)
- **Import Sorting**: isort with black profile
- **Formatting**: BRuff
- **Import Sorting**: Ruff
- **Type Checking**: mypy with strict settings
- **Linting**: pylint (many checks disabled in pyproject.toml for practical reasons)
- **Linting**: Ruff (many checks disabled in pyproject.toml for practical reasons)

## Testing Strategy

Expand All @@ -83,9 +80,8 @@

When making code changes, run these commands in order:

1. **Format code**: `./script/lint_black --auto` and `./script/lint_isort --auto`
2. **Run linting**: `./script/lint`
3. **Run tests**: `./script/tests`
1. **Format code and Lint**: `prek run lint --all-files`(inside the dev venv)
2. **Run tests**: `prek run tests --all-files` (inside the dev venv)

## Code Style

Expand Down Expand Up @@ -116,7 +112,7 @@ Private methods should be at the bottom of the file, public at the top.
## Verification Checklist

Before claiming completion:
- [ ] Ran `./script/lint` - all checks passed
- [ ] Ran `prek run lint --all-files` - all checks passed
- [ ] Ran `./script/tests` - all tests passed
- [ ] For audio-related changes: Note that hardware testing (microphone/speaker) was NOT performed
- [ ] Did NOT claim hardware behavior is verified unless actually exercised
Expand Down
21 changes: 6 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,44 +183,35 @@ source .venv/bin/activate
```

### Linting Commands

The `prek` commands have to be run inside the dev virtual environment.
#### Run all linting checks

```sh
./script/lint...
prek run lint --all-files
```

#### Individual linting commands (with auto-fix support)


| Script | Description | Auto-fix Available? |
| ------------------------ | ------------------------------------------ | ----------------------- |
| `./script/lint_black` | Checks Python code formatting with Black | Yes, use`--auto` flag |
| `./script/lint_flake8` | Runs style and syntax checks with flake8 | No |
| `./script/lint_isort` | Checks import sorting with isort | Yes, use`--auto` flag |
| `./script/lint_ruff` | Checks Python code formatting with Ruff | Yes, use`--auto` flag |
| `./script/lint_mypy` | Runs static type analysis with mypy | No |
| `./script/lint_pylint` | Runs code quality checks with pylint | Yes, use`--auto` flag |

#### Examples

Run a specific lint check:

```sh
./script/lint_black
```

Auto-fix formatting issues (Black + isort):

```sh
./script/lint_black --auto
./script/lint_isort --auto
./script/lint_ruff
```

### Testing
The `prek` commands have to be run inside the dev virtual environment.

Run the test suite:
``` sh
./script/tests
prek run tests --all-files
```

## License
Expand Down
1 change: 0 additions & 1 deletion linux_voice_assistant/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,6 @@ def process_audio(state: ServerState, mic, block_size: int):

has_oww = False
for idx, wake_word in enumerate(wake_words):

# Load default threshold from model json
wake_word_id = wake_word.id if hasattr(wake_word, "id") else next(iter(state.wake_words.keys()))
available_word = state.available_wake_words.get(wake_word_id)
Expand Down
1 change: 0 additions & 1 deletion linux_voice_assistant/api_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@


class APIServer(asyncio.Protocol):

def __init__(self, name: str) -> None:
self.name = name

Expand Down
11 changes: 5 additions & 6 deletions linux_voice_assistant/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,12 +421,11 @@ def handle_message(self, msg: message.Message) -> Iterable[message.Message]:
self._state = new_val
self._set_value(new_val)
yield SelectStateResponse(key=self.key, state=new_val)
else:
if isinstance(msg, NumberCommandRequest) and (msg.key == self.key):
new_val = msg.state
self._state = new_val
self._set_value(new_val)
yield NumberStateResponse(key=self.key, state=new_val)
elif isinstance(msg, NumberCommandRequest) and (msg.key == self.key):
new_val = msg.state
self._state = new_val
self._set_value(new_val)
yield NumberStateResponse(key=self.key, state=new_val)

# --- 2. DISCOVERY (TELL HA WHAT TYPE TO SHOW) ---
if isinstance(msg, ListEntitiesRequest):
Expand Down
2 changes: 1 addition & 1 deletion linux_voice_assistant/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def load(self) -> "Union[MicroWakeWord, OpenWakeWord]":
from pyopen_wakeword import OpenWakeWord

oww_model = OpenWakeWord.from_model(model_path=self.wake_word_path)
setattr(oww_model, "wake_word", self.wake_word)
oww_model.wake_word = self.wake_word # type: ignore[attr-defined]

return oww_model

Expand Down
3 changes: 0 additions & 3 deletions linux_voice_assistant/peripheral_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,6 @@ async def _dispatch_command(self, raw: str) -> None:

# Push the new volume to HA so its media player entity updates in real time
if satellite is not None:

satellite.send_messages(
[
MediaPlayerStateResponse(
Expand Down Expand Up @@ -401,7 +400,6 @@ async def _dispatch_command(self, raw: str) -> None:

# Push the new volume to HA so its media player entity updates in real time
if satellite is not None:

satellite.send_messages(
[
MediaPlayerStateResponse(
Expand Down Expand Up @@ -429,7 +427,6 @@ async def _dispatch_command(self, raw: str) -> None:
elif command == LVACommand.STOP_MEDIA_PLAYER:
state.music_player.stop()
if state.media_player_entity is not None:

state.media_player_entity.state = MediaPlayerState.IDLE
if satellite is not None:
satellite.send_messages([self._create_media_player_response(MediaPlayerState.IDLE)])
Expand Down
1 change: 0 additions & 1 deletion linux_voice_assistant/player/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@


class AudioPlayer(ABC):

@abstractmethod
def play(self, url: str) -> None:
pass
Expand Down
1 change: 0 additions & 1 deletion linux_voice_assistant/satellite.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@


class VoiceSatelliteProtocol(APIServer):

def __init__(self, state: ServerState) -> None:
super().__init__(state.name)

Expand Down
2 changes: 1 addition & 1 deletion mypy.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[mypy]
python_version >= 3.11
python_version = 3.13
warn_return_any = True
warn_unused_configs = True

Expand Down
Loading
Loading