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
46 changes: 46 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Use Ubuntu 22.04 as the base image
FROM ubuntu:22.04

# Set environment variables to prevent interactive prompts
ARG DEBIAN_FRONTEND=noninteractive

# Update package list and install necessary tools and dependencies
RUN apt-get update && \
apt-get install -y \
sudo \
git \
curl \
gnupg \
make \
build-essential \
pkg-config \
libzmq3-dev \
libssl-dev \
zlib1g-dev \
libncurses5-dev \
libgdbm-dev \
libnss3-dev \
libsqlite3-dev \
libreadline-dev \
libffi-dev \
libbz2-dev



# Make a 'dev' user
RUN echo 'root:dev' | chpasswd
RUN useradd -ms /bin/bash dev && echo 'dev:dev' | chpasswd && adduser dev sudo
RUN echo 'dev ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers

COPY --chown=dev:dev .devcontainer/scripts/gu /usr/local/bin/gu
COPY --chown=dev:dev .devcontainer/scripts/.bashrc /home/dev/.bashrc

USER dev

# Install Python 3 using apt
RUN sudo apt-get install -y python3 python3-pip

# Install uv
RUN curl -LsSf https://astral.sh/uv/install.sh | sh


24 changes: 24 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "ASE-roverlib-python-dev",
"build": {
"dockerfile": "./Dockerfile",
"context": "..",
"options": [
"--network=host"
]
},
"customizations": {
"vscode": {
"extensions": [
"tamasfe.even-better-toml", // TOML syntax support
"dbankier.vscode-quick-select", // Quick select with cmd/ctrl+k "
"charliermarsh.ruff"
]
}
},
"runArgs": [
"--network=host"
],
"remoteUser": "dev"
}

61 changes: 61 additions & 0 deletions .devcontainer/scripts/.bashrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# personalized PS1 prompt
PS1="\W \e[01;31m$\e[m "

# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac

# don't put duplicate lines or lines starting with space in the history.
# See bash(1) for more options
HISTCONTROL=ignoreboth

# append to the history file, don't overwrite it
shopt -s histappend

# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
HISTSIZE=1000
HISTFILESIZE=2000

# custom
alias python="python3"
alias l="ls -lah"
alias ..="cd .."

# git aliases
alias gs="git status"
alias gc="git commit -m "
alias ga="git add "
alias gp="git push"
alias gpl="git pull"
alias gl="git log --pretty=oneline"

# check the window size after each command and, if necessary
# update the values of LINES and COLUMNS.
shopt -s checkwinsize

# make less more friendly for non-text input files, see lesspipe(1)
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"


# Alias definitions in bash_aliases
if [ -f ~/work/scripts/.bash_aliases ]; then
. ~/work/scripts/.bash_aliases
fi

# enable programmable completion features (you don't need to enable
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
# sources /etc/bash.bashrc).
if ! shopt -oq posix; then
if [ -f /usr/share/bash-completion/bash_completion ]; then
. /usr/share/bash-completion/bash_completion
elif [ -f /etc/bash_completion ]; then
. /etc/bash_completion
fi
fi

export PATH=$PATH:/home/dev/.local/bin

if [ -f "$HOME/.cargo/env" ]; then . "$HOME/.cargo/env"; fi

21 changes: 21 additions & 0 deletions .devcontainer/scripts/gu
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash

STATUS=$(git status)

TEST=$(echo $STATUS | awk '{print $NF}')

if [ "$TEST" != "clean" ]; then
git add .
git status
echo -n "Sure you want to commit and push? (y/n) "
read INPUT
if [ "$INPUT" = "y" ]; then
echo -n "Commit message: "
read INPUT
git commit -m "$INPUT"
git push
else
echo "cancelled"
fi
fi

5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,8 @@ cython_debug/

# PyPI configuration file
.pypirc
h
.vscode

.ruff_cache

1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.10
62 changes: 62 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@



# Since we are using uv to manage our dependencies, we can utilize the "uv run python ..."
# command which makes sure to launch the python script with the dependencies installed as
# defined by the pyproject.toml file. That makes it the single source of truth and we
# can generate a requirements.txt file from there.



# We always want to run lint checks before we build or test
lint:
@echo "Linting src and tests"
@uv run ruff check src tests

# This will generate a python package that can be published and installs it locally for
# testing. Note, that it installs it with the -e (editable) option which means that when
# changing any library files, you can immediately test them and don't have to re-install
# with 'uv build'. However if we want to publish, we must always build.
build: lint
@rm -rf dist/
@uv build
@uv pip compile pyproject.toml -o requirements.txt

# Add all test files into /tests they will all get run when this target is invoked
test: lint
@uv run pytest

# Open a python repl for quick debugging
repl:
uv run python


clean:
uv cache clean
rm -r .pytest_cache .ruff_cache .venv dist



# Set token: export UV_PUBLISH_TOKEN=(token)
# check token: echo $UV_PUBLISH_TOKEN

check-publish-token:
@if [ -z "$(UV_PUBLISH_TOKEN)" ]; then \
echo "Error: UV_PUBLISH_TOKEN environment variable is not set"; \
exit 1; \
else \
echo "UV_PUBLISH_TOKEN is set"; \
fi



publish-test: check-publish-token build
@echo "Publishing to test.pypi.org"
@uv publish dist/* --index testpypi


publish: check-publish-token build
@echo "Publishing to pypi.org"
@uv publish dist/* --index pypi


11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
# roverlib-python
Building a service that runs on the rover? Then you'll need the roverlib. This is the variant for Python.
<h1 align="center"><code>roverlib-python</code> library</h1>
<div align="center">

<a href="https://ase.vu.nl/docs/category/roverlib-python">Documentation</a>
<br />
</div>
<br/>


43 changes: 43 additions & 0 deletions docs/00-usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Usage

After installation, you can use roverlib as follows:

```python
#!/usr/bin/python3
import roverlib
import signal
import time
import roverlib.rovercom as rovercom

def run(service : roverlib.Service, configuration : roverlib.ServiceConfiguration):

# Unlike roverlib-go, these functions do not return an error object, but rather throw an error on failure
speed = configuration.GetFloatSafe("speed")

name = configuration.GetStringSafe("name")

write_stream : roverlib.WriteStream = service.GetWriteStream("motor_movement")

write_stream.Write(

rovercom.SensorOutput(
sensor_id=2,
timestamp=int(time.time() * 1000),
controller_output=rovercom.ControllerOutput(
steering_angle=float(1),
left_throttle=float(speed),
right_throttle=float(speed),
front_lights=False
),
)
)




def on_terminate(sig : signal):
logger.info("Terminating")


roverlib.Run(run, on_terminate)
```
19 changes: 19 additions & 0 deletions docs/01-development.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# For Developers

The name of the package is `roverlib` which is the same as the module that is then imported by end users (`pip install roverlib` and `import roverlib` to keep consistency).

The following directory structure aims to separate library code from testing code:
* `src/roverlib` - contains all source code of the library
* `tests/` - contains python files that will all be part of the testing process

This repository is self-contained and relies heavily on `uv` for dependency management and building packages. The most important commands are wrapped by Makefile targets:

* `make build` - builds the library to `dist/` and installs it locally for quick testing
* `make test` - runs all files in the `tests/` directory
* `make publish-test` - requires setting an external token with `export PUBLISH_TOKEN=pypi-abc...` and uploads to pypi's test
* `make publish` - requires setting an external token with `export PUBLISH_TOKEN=pypi-def...` and uploads to the official pypi index


Before running the `make publish*` targets, make sure to set the correct token depending on which index you are uploading to.


41 changes: 41 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
[project]
name = "roverlib"
version = "0.5.3"
description = "ASE roverlib"
readme = "README.md"
authors = [
{ name = "NielsD1", email = "n.j.dijkstra@student.vu.nl" },
{ name = "maxgallup", email = "m.gallup@student.vu.nl" },

]
requires-python = ">=3.10"
dependencies = ["pyzmq", "loguru", "betterproto"]

[project.urls]
"Repository" = "https://github.com/vu-ase/roverlib-python"
"Issues" = "https://github.com/vu-ase/roverlib-python/issues"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[dependency-groups]
dev = ["pytest>=8.3.4", "ruff>=0.9.7"]

# Tell pytest that all files in the /tests directory are tests
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = "tests/*.py"
python_functions = "test_*"
python_classes = "Test*"


[[tool.uv.index]]
name = "pypi"
url = "https://pypi.org/simple/"
publish-url = "https://upload.pypi.org/legacy/"

[[tool.uv.index]]
name = "testpypi"
url = "https://test.pypi.org/simple/"
publish-url = "https://test.pypi.org/legacy/"
22 changes: 22 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# This file was autogenerated by uv via the following command:
# uv pip compile pyproject.toml -o requirements.txt
betterproto==1.2.5
# via roverlib (pyproject.toml)
grpclib==0.4.7
# via betterproto
h2==4.2.0
# via grpclib
hpack==4.1.0
# via h2
hyperframe==6.1.0
# via h2
loguru==0.7.3
# via roverlib (pyproject.toml)
multidict==6.1.0
# via grpclib
pyzmq==26.2.1
# via roverlib (pyproject.toml)
stringcase==1.2.0
# via betterproto
typing-extensions==4.12.2
# via multidict
8 changes: 8 additions & 0 deletions src/roverlib/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from .index import Run
from .bootinfo import Service, service_from_dict
from .configuration import ServiceConfiguration
from .streams import ReadStream, WriteStream
import roverlib.rovercom as rovercom


__all__ = ["Run", "Service", "service_from_dict", "ServiceConfiguration", "ReadStream", "WriteStream", "rovercom"]
Loading
Loading