Skip to content

Commit

Permalink
Tooling overhaul and package updates
Browse files Browse the repository at this point in the history
  • Loading branch information
AKuederle committed Oct 31, 2024
1 parent 66fd45a commit 078234e
Show file tree
Hide file tree
Showing 21 changed files with 1,427 additions and 1,829 deletions.
52 changes: 0 additions & 52 deletions .prospector.yml

This file was deleted.

43 changes: 29 additions & 14 deletions .ruff.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
line-length = 120
target-version = "py38"
target-version = "py39"

[lint]
select = [
# pyflakes
"F",
Expand Down Expand Up @@ -57,7 +58,15 @@ select = [
"TRY",
# flake8-use-pathlib
"PTH",
"RUF"
"RUF",
# Numpy rules
"NPY",
# Implicit namespace packages
"INP",
# No relative imports
"TID252",
# f-strings over string concatenation
"FLY",
]

ignore = [
Expand All @@ -72,24 +81,28 @@ ignore = [
"EM101",
"EM102",
"EM103",
# Multiline docstring summary
"D213",
# Exception strings
"TRY003",
# Varaibles before return
"RET504",
# Abstract raise into inner function
"TRY301",
# Use type-checking block
"TCH001",
"TCH002",
"TCH003",
# df as varaible name
"PD901",
# melt over stack
"PD013",
# I like more arguments
# No Any annotations
"ANN401",
# Self annotation
"ANN101",
# To many arguments
"PLR0913",
# I like long error messages
"TRY003"
# Class attribute shadows builtin
"A003",
# No typing for `cls`
"ANN102",
# Ignore because of formatting
"ISC001",
]


Expand All @@ -99,9 +112,11 @@ exclude = [
"doc/temp/*.py",
".eggs/*.py",
"example_data",
"examples"
]


[pydocstyle]
[lint.pydocstyle]
convention = "numpy"

[format]
docstring-code-format = true
docstring-code-line-length = 80
8 changes: 4 additions & 4 deletions _tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
HERE = Path(__file__).parent


def task_docs():
def task_docs() -> None:
"""Build the html docs using Sphinx."""
# Delete Autogenerated files from previous run
shutil.rmtree(str(HERE / "docs/modules/generated"), ignore_errors=True)
Expand All @@ -19,7 +19,7 @@ def task_docs():
subprocess.run(["make", "-C", HERE / "docs", "html"], shell=False, check=True)


def update_version_strings(file_path, new_version):
def update_version_strings(file_path, new_version) -> None:
# taken from:
# https://stackoverflow.com/questions/57108712/replace-updated-version-strings-in-files-via-python
version_regex = re.compile(r"(^_*?version_*?\s*=\s*\")(\d+\.\d+\.\d+-?\S*)\"", re.M)
Expand All @@ -36,7 +36,7 @@ def update_version_strings(file_path, new_version):
f.truncate()


def update_version(version):
def update_version(version) -> None:
subprocess.run(["poetry", "version", version], shell=False, check=True)
new_version = (
subprocess.run(["poetry", "version"], shell=False, check=True, capture_output=True)
Expand All @@ -47,5 +47,5 @@ def update_version(version):
update_version_strings(HERE.joinpath("imucal/__init__.py"), new_version)


def task_update_version():
def task_update_version() -> None:
update_version(sys.argv[1])
7 changes: 4 additions & 3 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
sys.path.insert(0, os.path.abspath(".."))

import contextlib
from typing import Optional

import imucal

Expand Down Expand Up @@ -150,7 +151,7 @@ def get_nested_attr(obj, attr):
return get_nested_attr(new_obj, attrs[1])


def linkcode_resolve(domain, info):
def linkcode_resolve(domain, info) -> Optional[str]:
if domain != "py":
return None
if not info["module"]:
Expand All @@ -172,12 +173,12 @@ def linkcode_resolve(domain, info):
return None


def skip_properties(app, what, name, obj, skip, options):
def skip_properties(app, what, name, obj, skip, options) -> Optional[bool]:
"""This removes all properties from the documentation as they are expected to be documented in the docstring."""
if isinstance(obj, property):
return True
return None


def setup(app):
def setup(app) -> None:
app.connect("autodoc-skip-member", skip_properties)
3 changes: 2 additions & 1 deletion examples/basic_ferraris.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,10 @@
# %%
# ... or use the provided management tools to save the file in a predefined folder structure.
# Read more about this in the our :ref:`guide on that topic <cal_store_guide>`.
from imucal.management import save_calibration_info
from datetime import datetime

from imucal.management import save_calibration_info

file_path = save_calibration_info(
cal_info, sensor_id="imu1", cal_time=datetime(2020, 8, 12, 13, 21), folder=Path(d.name)
)
Expand Down
1 change: 1 addition & 0 deletions examples/custom_calibration_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class ExtendedFerrarisCalibrationInfo(FerrarisCalibrationInfo):
# here to not clutter the example folder).
import tempfile
from pathlib import Path

from imucal.management import load_calibration_info

with tempfile.TemporaryDirectory() as d:
Expand Down
1 change: 1 addition & 0 deletions imucal/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""A library to calibrate 6 DOF IMUs."""

from imucal.calibration_info import CalibrationInfo
from imucal.ferraris_calibration import (
FerrarisCalibration,
Expand Down
62 changes: 29 additions & 33 deletions imucal/calibration_gui.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
"""Helper providing a small GUI to label timeseries data."""
import tkinter as tk # noqa: import-error

import tkinter as tk
from collections import OrderedDict
from collections.abc import Sequence
from itertools import chain
from tkinter.messagebox import showinfo # : import-error
from typing import Sequence, Optional
from tkinter.messagebox import showinfo
from typing import Optional

from matplotlib.backend_bases import MouseButton
import numpy as np


Expand All @@ -17,12 +18,12 @@ class CalibrationGui:
Examples
--------
>>> # This will launch the GUI and block execution until closed
>>> gui = CalibrationGui(acc, gyro, ['label1', 'label2'])
>>> gui = CalibrationGui(acc, gyro, ["label1", "label2"])
>>> # While the GUI is open the sections are labeled. Once closed the next line is executed
>>> labels = gui.section_list
>>> labels['label1'] # First value is start, second value is end of region
>>> labels["label1"] # First value is start, second value is end of region
(12, 355)
>>> labels['label2'] # First value is start, second value is end of region
>>> labels["label2"] # First value is start, second value is end of region
(500, 758)
"""
Expand Down Expand Up @@ -64,7 +65,7 @@ def __init__(
expected_labels: Sequence[str],
title: Optional[str] = None,
master: Optional[tk.Frame] = None,
):
) -> None:
"""Launch new GUI instance.
Parameters
Expand All @@ -81,22 +82,20 @@ def __init__(
Parent window if GUI should be embedded in larger application
"""
import matplotlib # : import-outside-toplevel
from matplotlib.backends.backend_tkagg import ( # : import-outside-toplevel
import matplotlib
from matplotlib.backends.backend_tkagg import (
FigureCanvasTkAgg,
NavigationToolbar2Tk,
)


class CustomToolbar(NavigationToolbar2Tk):
def __init__(self, canvas, window):
def __init__(self, canvas, window) -> None:
# List of buttons to remove
buttons_to_remove = ['Subplots', 'Save']
buttons_to_remove = ["Subplots", "Save"]
print(self.toolitems)
self.toolitems = [item for item in self.toolitems if item[0] not in buttons_to_remove]
super().__init__(canvas, window)


self.expected_labels = expected_labels
cmap = matplotlib.cm.get_cmap("Set3")
self.colors = {k: matplotlib.colors.to_hex(cmap(i / 12)) for i, k in enumerate(expected_labels)}
Expand Down Expand Up @@ -135,11 +134,11 @@ def __init__(self, canvas, window):

# To make the shortcut works, we need to manually forward the key event to the toolbar
# Bind keypress events to the canvas widget
self.canvas.get_tk_widget().bind("<p>", lambda event: toolbar.pan())
self.canvas.get_tk_widget().bind("<o>", lambda event: toolbar.zoom())
self.canvas.get_tk_widget().bind("<h>", lambda event: toolbar.home())
self.canvas.get_tk_widget().bind("<b>", lambda event: toolbar.back())
self.canvas.get_tk_widget().bind("<f>", lambda event: toolbar.forward())
self.canvas.get_tk_widget().bind("<p>", lambda _: toolbar.pan())
self.canvas.get_tk_widget().bind("<o>", lambda _: toolbar.zoom())
self.canvas.get_tk_widget().bind("<h>", lambda _: toolbar.home())
self.canvas.get_tk_widget().bind("<b>", lambda _: toolbar.back())
self.canvas.get_tk_widget().bind("<f>", lambda _: toolbar.forward())

# Bind mouse wheel event to scroll along the x-axis
self.canvas.get_tk_widget().bind("<MouseWheel>", self._scroll_x)
Expand All @@ -155,18 +154,17 @@ def __init__(self, canvas, window):

toolbar.pack(side=tk.TOP, fill=tk.X, expand=0)


# This way, we can start labeling right away
self.labels.selection_set(0)

master.mainloop()

def _scroll_x(self, event):
def _scroll_x(self, event) -> None:
ax = self.canvas.figure.gca()
x_min, x_max = ax.get_xlim()
data_min, data_max = ax.dataLim.intervalx
delta = (x_max - x_min)
scroll_in_units = delta * 0.1 # Adjust the scroll speed as needed
delta = x_max - x_min
scroll_in_units = delta * 0.1 # Adjust the scroll speed as needed

if data_min >= x_min and data_max <= x_max:
# No scrolling, when we see all the data
Expand All @@ -186,7 +184,7 @@ def _scroll_x(self, event):
ax.set_xlim(new_x_min, new_x_max)
self.canvas.draw_idle()

def _create_sidebar(self):
def _create_sidebar(self) -> None:
self.labels = tk.Listbox(master=self.side_bar, width=30)
self.labels.pack(side=tk.TOP, fill=tk.BOTH, expand=1)
help_button = tk.Button(master=self.side_bar, height=2, text="Help", command=self._show_help)
Expand All @@ -197,10 +195,10 @@ def _create_sidebar(self):

self._update_list_box()

def _show_help(self):
def _show_help(self) -> None:
showinfo("Window", self.manual)

def _select_next(self, current):
def _select_next(self, current) -> None:
next_val = (current + 1) % self.labels.size()

if all(list(self.section_list.values())[next_val]):
Expand All @@ -213,21 +211,19 @@ def _select_next(self, current):
self.labels.selection_anchor(next_val)
self.labels.selection_set(next_val)

def _update_list_box(self):
def _update_list_box(self) -> None:
for i, (key, val) in enumerate(self.section_list.items()):
self.labels.itemconfig(i, {"bg": self.colors[key]})
if all(val):
self.labels.itemconfig(i, {"fg": "#a5a9af"})


def _update_text_label(self, new_text):
def _update_text_label(self, new_text) -> None:
self.label_text.config(state=tk.NORMAL)
self.label_text.delete("1.0", tk.END)
self.label_text.insert(tk.END, new_text)
self.label_text.config(state=tk.DISABLED)


def _onclick(self, event):
def _onclick(self, event) -> None:
# Only listen to left and right mouse clicks and only if we are not in zoom or drag mode.
if event.button not in [1, 3] or str(self.canvas.toolbar.mode):
return
Expand Down Expand Up @@ -255,7 +251,7 @@ def _onclick(self, event):

self._update_list_box()

def _update_marker(self, key):
def _update_marker(self, key) -> None:
for line in chain(self.acc_list_markers[key], self.gyro_list_markers[key]):
line.remove()
self.acc_list_markers[key] = []
Expand Down Expand Up @@ -286,7 +282,7 @@ def _n_labels(self):


def _create_figure(acc, gyro):
from matplotlib.figure import Figure # : import-outside-toplevel
from matplotlib.figure import Figure

fig = Figure(figsize=(20, 10))
ax1 = fig.add_subplot(211)
Expand Down
Loading

0 comments on commit 078234e

Please sign in to comment.