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
9 changes: 5 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ test:
rm .coverage

lint:
uv run ruff format
uv run ruff check --fix
uv run ruff format src/ tests/
uv run ruff check --fix src/ tests/

typecheck:
uv run pyright src
uv run pyright src/ tests/

format:
make lint
Expand All @@ -27,7 +27,8 @@ clean:
rm -rf build/
rm -rf dist/
rm -rf junit-pytest.xml
rm -rf logs/*
rm -rf data/logs/*
rm coverage.xml
find . -name ".coverage*" -delete
find . -name "__pycache__" -exec rm -r {} +

Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,13 @@ The package can then be found at: **https://pypi.org/project/exosuit-python**
## Module Usage
```python
"""Basic docstring for the exosuit module."""
from exosuit_python.exosuit import Exosuit, ExosuitConfig

def main() -> None:
"""Run a simple demonstration."""
logger.info("Hello World!")

config = ExosuitConfig(frequency=100)
exosuit = Exosuit(config=config)
exosuit.run()
if __name__ == "__main__":
main()
```
Expand Down
8 changes: 4 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,31 @@ description = "IMU sensor codes in Python for the exosuit"
readme = "README.md"
authors = [{ name = "Tsmorz", email = "tony.smoragiewicz@tum.de" }]
requires-python = ">=3.11,<3.14"
homepage = "https://github.com/TUM-Aries-Lab/exosuit-python"

# --- Core dependencies: NO hardware here ---
dependencies = [
"numpy>=2.2.3",
"loguru>=0.7.3",
"motor-python>=0.0.3",
"imu-python>=0.0.3",
]

[dependency-groups]
dev = [
"ruff>=0.6.9",
"mypy>=1.11",
"pytest>=8.3",
"pytest-cov>=6.0",
"pre-commit>=4.1.0",
"coveralls>=4.0.1",
"pyright>=1.1.407",
]
hw = [
"jetson-gpio>=2.1.12",
]
no_hw = [
]

[project.urls]
homepage = "https://github.com/TUM-Aries-Lab/exosuit-python"

[tool.ruff]
line-length = 88
fix = true
Expand Down
6 changes: 4 additions & 2 deletions repo_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
START_MARKER = "<!-- TREE-START -->"
END_MARKER = "<!-- TREE-END -->"
ENCODING = "utf-8"
README = "README.md"

# Manual ignores are still allowed
MANUAL_IGNORE = {
Expand Down Expand Up @@ -109,11 +110,12 @@ def generate_markdown_tree() -> str:

def update_readme_block(readme_path: Path) -> None:
"""Replace the section between markers with the generated tree."""
logger.info(f"Updating README tree for '{readme_path.name}'.")
readme = readme_path.read_text(encoding=ENCODING).splitlines()

if START_MARKER not in readme or END_MARKER not in readme:
raise RuntimeError(
f"README.md must contain '{START_MARKER}' and '{END_MARKER}' markers."
f"{README} must contain '{START_MARKER}' and '{END_MARKER}' markers."
)

start = readme.index(START_MARKER) + 1
Expand All @@ -134,7 +136,7 @@ def main() -> None:
args = parser.parse_args()

if args.update_readme:
update_readme_block(Path("README.md"))
update_readme_block(Path(README))
else:
logger.info(generate_markdown_tree())

Expand Down
19 changes: 18 additions & 1 deletion src/exosuit_python/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,24 @@
import argparse

from exosuit_python.definitions import DEFAULT_LOG_LEVEL, LogLevel
from exosuit_python.exosuit import main
from exosuit_python.exosuit import Exosuit, ExosuitConfig
from exosuit_python.utils import setup_logger


def main(log_level: str, stderr_level: str) -> None: # pragma: no cover
"""Run the main pipeline.

:param log_level: The log level to use.
:param stderr_level: The std err level to use.
:return: None
"""
setup_logger(log_level=log_level, stderr_level=stderr_level)

config = ExosuitConfig(frequency=100)
exosuit = Exosuit(config=config)
exosuit.run()
exosuit.cleanup()


if __name__ == "__main__": # pragma: no cover
parser = argparse.ArgumentParser("Run the pipeline.")
Expand Down
53 changes: 41 additions & 12 deletions src/exosuit_python/exosuit.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,48 @@
"""Sample doc string."""

from dataclasses import dataclass

from loguru import logger

from exosuit_python.definitions import DEFAULT_LOG_LEVEL
from exosuit_python.utils import setup_logger

@dataclass
class ExosuitConfig:
"""Exosuit configuration."""

frequency: float


class Exosuit:
"""Tendon-based soft exoskeleton."""

def __init__(self, config: ExosuitConfig):
self.config = config

self._is_running: bool = False

self.motor_left = "motor" # place holder
self.motor_right = "motor" # place holder

self.imu_left = "imu" # place holder
self.imu_right = "imu" # place holder

def run(self):
"""Start the soft exoskeleton."""
self.start()

def main(
log_level: str = DEFAULT_LOG_LEVEL, stderr_level: str = DEFAULT_LOG_LEVEL
) -> None:
"""Run the main pipeline.
def start(self):
"""Start the IMUs and Motors."""
logger.info(f"Starting Exosuit at '{self.config.frequency}' Hz.")
try:
logger.debug("Starting IMUs")
logger.debug("Starting Motors")
logger.debug("Starting Controller")
self._is_running = True
except Exception as err:
logger.info(f"Exosuit exception: '{err}'.")

:param log_level: The log level to use.
:param stderr_level: The std err level to use.
:return: None
"""
setup_logger(log_level=log_level, stderr_level=stderr_level)
logger.info("Hello, world!")
def cleanup(self):
"""Clean up the soft exoskeleton."""
logger.info("Cleaning up exosuit.")
self._is_running = False
logger.success("Exosuit shutdown.")
16 changes: 13 additions & 3 deletions tests/exosuit_test.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
"""Test the main program."""

from exosuit_python.exosuit import main
from exosuit_python.exosuit import Exosuit, ExosuitConfig


def test_main():
def test_exosuit():
"""Test the main function."""
assert main() is None
# Arrange
config = ExosuitConfig(frequency=100)

# Act
exosuit = Exosuit(config)
exosuit.run()

# Assert
assert exosuit._is_running
exosuit.cleanup()
assert not exosuit._is_running
4 changes: 2 additions & 2 deletions tests/utils_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
from pathlib import Path
from tempfile import TemporaryDirectory

from exosuit_python.definitions import LogLevel
from exosuit_python.definitions import DEFAULT_LOG_FILENAME, LogLevel
from exosuit_python.utils import setup_logger


def test_logger_init() -> None:
"""Test logger initialization."""
with TemporaryDirectory() as log_dir:
log_dir_path = Path(log_dir)
log_filepath = setup_logger(filename="log_file", log_dir=log_dir_path)
log_filepath = setup_logger(filename=DEFAULT_LOG_FILENAME, log_dir=log_dir_path)
assert Path(log_filepath).exists()
assert not Path(log_filepath).exists()

Expand Down
Loading