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
83 changes: 83 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[dev]"

- name: Lint with ruff
run: ruff check .

test:
name: Test (Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']

steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[dev]"

- name: Run tests
run: pytest -v

version-check:
name: Version sync
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Check version consistency
run: |
PYPROJECT_VERSION=$(python -c "
import re
with open('pyproject.toml') as f:
match = re.search(r'^version\s*=\s*\"(.+?)\"', f.read(), re.MULTILINE)
print(match.group(1))
")
INIT_VERSION=$(python -c "
import re
with open('plexus/__init__.py') as f:
match = re.search(r'^__version__\s*=\s*\"(.+?)\"', f.read(), re.MULTILINE)
print(match.group(1))
")
echo "pyproject.toml version: $PYPROJECT_VERSION"
echo "__init__.py version: $INIT_VERSION"
if [ "$PYPROJECT_VERSION" != "$INIT_VERSION" ]; then
echo "::error::Version mismatch! pyproject.toml=$PYPROJECT_VERSION, __init__.py=$INIT_VERSION"
exit 1
fi
echo "Versions match: $PYPROJECT_VERSION"
50 changes: 42 additions & 8 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,60 @@ name: Publish to PyPI
on:
release:
types: [published]
workflow_dispatch:
inputs:
version:
description: 'Version to publish (leave empty for current)'
required: false

jobs:
validate:
name: Validate release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[dev]"

- name: Check tag matches code version
run: |
TAG="${GITHUB_REF#refs/tags/v}"
CODE_VERSION=$(python -c "
import re
with open('pyproject.toml') as f:
match = re.search(r'^version\s*=\s*\"(.+?)\"', f.read(), re.MULTILINE)
print(match.group(1))
")
echo "Git tag version: $TAG"
echo "Code version: $CODE_VERSION"
if [ "$TAG" != "$CODE_VERSION" ]; then
echo "::error::Tag v$TAG does not match code version $CODE_VERSION"
exit 1
fi

- name: Lint
run: ruff check .

- name: Run tests
run: pytest -v

publish:
name: Publish to PyPI
needs: validate
runs-on: ubuntu-latest
permissions:
id-token: write # Required for trusted publishing
id-token: write

steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
python-version: '3.12'

- name: Install build tools
run: |
Expand All @@ -36,4 +71,3 @@ jobs:

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
# Uses trusted publishing - configure at pypi.org/manage/project/plexus-agent/settings/publishing/
33 changes: 0 additions & 33 deletions .github/workflows/test.yml

This file was deleted.

2 changes: 1 addition & 1 deletion plexus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@
from plexus.config import load_config, save_config
from plexus.typed_commands import param, CommandRegistry

__version__ = "0.5.3"
__version__ = "0.5.4"
__all__ = ["Plexus", "param", "CommandRegistry", "load_config", "save_config"]
2 changes: 1 addition & 1 deletion plexus/adapters/mavlink_detect.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import os
import socket
from dataclasses import dataclass
from typing import List, Optional
from typing import List

logger = logging.getLogger(__name__)

Expand Down
19 changes: 9 additions & 10 deletions plexus/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@

import click

logger = logging.getLogger(__name__)

from plexus import __version__
from plexus.client import Plexus, AuthenticationError, PlexusError
from plexus.config import (
Expand All @@ -31,6 +29,8 @@
get_config_path,
)

logger = logging.getLogger(__name__)


# ─────────────────────────────────────────────────────────────────────────────
# Console Styling
Expand Down Expand Up @@ -294,7 +294,7 @@ def start(key: Optional[str], name: Optional[str], bus: int):
try:
sensor_hub, sensors = detect_sensors(bus)
except PermissionError:
i2c_error = f"I2C permission denied (run: sudo usermod -aG i2c $USER)"
i2c_error = "I2C permission denied (run: sudo usermod -aG i2c $USER)"
except ImportError:
from plexus.deps import prompt_install
if prompt_install("smbus2", extra="sensors"):
Expand Down Expand Up @@ -443,7 +443,7 @@ def add(capabilities: tuple):
plexus add can # Add CAN bus support
plexus add sensors camera # Add multiple
"""
from plexus.deps import is_available, DEPENDENCY_MAP
from plexus.deps import is_available
import subprocess

if not capabilities:
Expand Down Expand Up @@ -593,7 +593,7 @@ def run(name: Optional[str], no_sensors: bool, no_cameras: bool, bus: int, senso
try:
sensor_hub, sensors = detect_sensors(bus)
except PermissionError:
i2c_error = f"permission denied (run: sudo usermod -aG i2c $USER)"
i2c_error = "permission denied (run: sudo usermod -aG i2c $USER)"
except ImportError:
from plexus.deps import prompt_install
if prompt_install("smbus2", extra="sensors"):
Expand All @@ -602,7 +602,7 @@ def run(name: Optional[str], no_sensors: bool, no_cameras: bool, bus: int, senso
except Exception as e:
i2c_error = str(e)
else:
i2c_error = f"smbus2 not installed (run: pip install plexus-agent[sensors])"
i2c_error = "smbus2 not installed (run: pip install plexus-agent[sensors])"
except Exception as e:
i2c_error = str(e)

Expand Down Expand Up @@ -1587,7 +1587,7 @@ def _warn(msg: str):
_pass(f"I2C bus {bus_num}: accessible")
else:
_fail(f"I2C bus {bus_num}: permission denied")
dim(f" Fix: sudo usermod -aG i2c $USER")
dim(" Fix: sudo usermod -aG i2c $USER")

# Serial ports
import glob
Expand All @@ -1597,7 +1597,7 @@ def _warn(msg: str):
_pass(f"{port}: accessible")
else:
_fail(f"{port}: permission denied")
dim(f" Fix: sudo usermod -aG dialout $USER")
dim(" Fix: sudo usermod -aG dialout $USER")

# Camera
video_devs = glob.glob("/dev/video*")
Expand All @@ -1606,7 +1606,7 @@ def _warn(msg: str):
_pass(f"{dev}: accessible")
else:
_fail(f"{dev}: permission denied")
dim(f" Fix: sudo usermod -aG video $USER")
dim(" Fix: sudo usermod -aG video $USER")

if not any(os.path.exists(p) for p in ["/dev/i2c-0", "/dev/i2c-1"]) and not serial_ports and not video_devs:
dim(" No hardware devices detected on this system")
Expand Down Expand Up @@ -1636,7 +1636,6 @@ def _warn(msg: str):

# ── Summary ──────────────────────────────────────────────────────────

total = checks_passed + checks_failed + checks_warned
if checks_failed == 0:
click.secho(
f" {Style.CHECK} All {checks_passed} checks passed",
Expand Down
12 changes: 10 additions & 2 deletions plexus/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
"""

import logging
import threading
import time
from contextlib import contextmanager
from typing import Any, Dict, List, Optional, Tuple, Union
Expand Down Expand Up @@ -107,7 +106,7 @@ def __init__(
self.source_id = source_id or get_source_id()
self.timeout = timeout
self.retry_config = retry_config or RetryConfig()
self.max_buffer_size = max_buffer_size
self._max_buffer_size = max_buffer_size

self._session_id: Optional[str] = None
self._session: Optional[requests.Session] = None
Expand All @@ -123,6 +122,15 @@ def __init__(
else:
self._buffer: BufferBackend = MemoryBuffer(max_size=max_buffer_size)

@property
def max_buffer_size(self):
return self._max_buffer_size

@max_buffer_size.setter
def max_buffer_size(self, value):
self._max_buffer_size = value
self._buffer._max_size = value

def _get_session(self) -> requests.Session:
"""Get or create a requests session for connection pooling."""
if self._session is None:
Expand Down
1 change: 0 additions & 1 deletion plexus/detect.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import shutil
import socket
import subprocess
import sys
from dataclasses import dataclass, field, asdict
from typing import List, Optional, Tuple, Dict, Any, TYPE_CHECKING

Expand Down
1 change: 0 additions & 1 deletion plexus/sensors/gps.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
print(f"{reading.metric}: {reading.value}")
"""

import time
import logging
from typing import List, Optional
from .base import BaseSensor, SensorReading
Expand Down
18 changes: 12 additions & 6 deletions plexus/sensors/magnetometer.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,12 @@ def read(self) -> List[SensorReading]:
z = (data[5] << 8) | data[4]

# Convert to signed
if x > 32767: x -= 65536
if y > 32767: y -= 65536
if z > 32767: z -= 65536
if x > 32767:
x -= 65536
if y > 32767:
y -= 65536
if z > 32767:
z -= 65536

# At 8 Gauss range: 3000 LSB/Gauss, 1 Gauss = 100 µT
# So LSB = 100/3000 µT ≈ 0.0333 µT
Expand Down Expand Up @@ -205,9 +208,12 @@ def read(self) -> List[SensorReading]:
y = (data[4] << 8) | data[5]

# Convert to signed
if x > 32767: x -= 65536
if y > 32767: y -= 65536
if z > 32767: z -= 65536
if x > 32767:
x -= 65536
if y > 32767:
y -= 65536
if z > 32767:
z -= 65536

# At 1.3 Gauss gain: 1090 LSB/Gauss, 1 Gauss = 100 µT
scale = 100.0 / 1090.0
Expand Down
2 changes: 1 addition & 1 deletion plexus/sensors/sht3x.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def __init__(

def setup(self) -> None:
try:
from smbus2 import SMBus, i2c_msg
from smbus2 import SMBus
except ImportError:
raise ImportError(
"smbus2 is required for SHT3x. Install with: pip install smbus2"
Expand Down
Loading
Loading