From 453cbca9da7fce999a049e71c4d4384dc9246c33 Mon Sep 17 00:00:00 2001 From: WillB97 Date: Sat, 6 Apr 2024 09:48:42 +0100 Subject: [PATCH 01/18] Transistion to pyproject.toml --- pyproject.toml | 59 ++++++++++++++++++++++++++++++++++++++++++++++++-- setup.cfg | 41 ----------------------------------- setup.py | 6 ----- 3 files changed, 57 insertions(+), 49 deletions(-) delete mode 100644 setup.cfg delete mode 100644 setup.py diff --git a/pyproject.toml b/pyproject.toml index b815a71..7b0e5a8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,9 +19,64 @@ disallow_untyped_decorators = true check_untyped_defs = true +[project] +name = "april_vision" +description = "An AprilTags wrapper with camera discovery and axis conversion." +readme = "README.md" +license = {file = "LICENSE"} +authors = [{name = "Will Barber"}, {name = "Joshua Perriman"}] + +classifiers = [ + "Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: Scientific/Engineering :: Image Recognition", + "Programming Language :: Python :: 3", + "Operating System :: OS Independent", + "Development Status :: 5 - Production/Stable", + "Typing :: Typed", + "License :: OSI Approved :: MIT License", +] + +dynamic = ["version"] +requires-python = ">=3.8" +dependencies = [ + "pyapriltags >=3.3.0.2,<4", + "numpy >= 1.21,<2", + "pyquaternion >=0.9.9,<1", + # winrt only supports upto python 3.10 + # winrt >=1.0.21033.1, <2; platform_system=='Windows' + "winsdk >=1.0.0b7,<2; platform_system=='Windows'", +] + +[project.optional-dependencies] +dev = [ + "flake8", + "isort", + "mypy", + "build", + "types-Pillow", + "types-tabulate", + "pytest", + "pytest-cov", +] +cli = [ + "Pillow >=9.4.0,<10", + "tabulate >=0.9.0,<1", + "font-roboto >=0.0.1", +] +opencv = ["opencv-python-headless >=4,<5"] + +[project.scripts] +april_vision = "april_vision.cli:main" + +[project.urls] +Repository = "https://github.com/WillB97/april_vision" + +[tool.setuptools.packages] +find = {} + [build-system] -requires = ["setuptools>=45", "wheel", "setuptools_scm>=6.2"] +requires = ["setuptools>=60", "wheel", "setuptools_scm>=8"] build-backend = "setuptools.build_meta" [tool.setuptools_scm] -write_to = "april_vision/_version.py" +version_file = "april_vision/_version.py" diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index efece86..0000000 --- a/setup.cfg +++ /dev/null @@ -1,41 +0,0 @@ -[metadata] -name = april_vision -description = An AprilTags wrapper with camera discovery and axis conversion. -long_description = file: README.md -long_description_content_type = text/markdown -license = MIT -author = "Will Barber, Joshua Perriman" -url = https://github.com/WillB97/april_vision - -[options] -python_requires = >=3.8 -packages = find: -include_package_data = True -install_requires = - pyapriltags >=3.3.0.2, <4 - numpy >= 1.21, <2 - pyquaternion >=0.9.9, <1 - # winrt only supports upto python 3.10 - # winrt >=1.0.21033.1, <2; platform_system=='Windows' - winsdk >=1.0.0b7, <2; platform_system=='Windows' - -[options.extras_require] -dev = - flake8 - isort - mypy - build - types-Pillow - types-tabulate - pytest - pytest-cov -cli = - Pillow >=9.4.0, <10 - tabulate >=0.9.0, <1 - font-roboto >=0.0.1 -opencv = - opencv-python-headless >=4, <5 - -[options.entry_points] -console_scripts = - april_vision = april_vision.cli:main diff --git a/setup.py b/setup.py deleted file mode 100644 index 71c50ee..0000000 --- a/setup.py +++ /dev/null @@ -1,6 +0,0 @@ -from setuptools import setup - -setup( - use_scm_version=True, - setup_requires=['setuptools_scm'], -) From 0b496bd4b44dcf53e1dab9f11e671c7ea0ecbcaf Mon Sep 17 00:00:00 2001 From: WillB97 Date: Sat, 6 Apr 2024 09:48:42 +0100 Subject: [PATCH 02/18] Initial ruff config --- .flake8 | 13 -------- .github/workflows/check.yml | 3 -- .gitignore | 3 ++ Makefile | 9 ++---- pyproject.toml | 64 ++++++++++++++++++++++++------------- 5 files changed, 47 insertions(+), 45 deletions(-) delete mode 100644 .flake8 diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 44a9b54..0000000 --- a/.flake8 +++ /dev/null @@ -1,13 +0,0 @@ -[flake8] -max_line_length = 95 -extend-ignore = - # Don't require imperative mood docstrings. - D401, - # Ignore docstrings on magic methods - D105, - # Ignore docstrings on init methods - D107, - # Ignore TODO comments - T000, -per-file-ignores = - april_vision/__init__.py:E402 diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 0cb14a8..106f7a6 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -21,9 +21,6 @@ jobs: - name: Lint run: | make lint - - name: Isort - run: | - make isort-check - name: Typecheck run: | make type diff --git a/.gitignore b/.gitignore index 7c5e172..e78d798 100644 --- a/.gitignore +++ b/.gitignore @@ -103,6 +103,9 @@ venv.bak/ # mypy .mypy_cache/ +# ruff +.ruff_cache/ + # PyCharm stuff .idea core diff --git a/Makefile b/Makefile index 7231313..f563fd4 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ TESTS:=tests all: lint isort-check type test lint: - flake8 $(PYMODULE) + ruff check $(PYMODULE) type: mypy $(PYMODULE) @@ -14,11 +14,8 @@ type: test: pytest --cov=$(PYMODULE) --cov-report=term --cov-report=xml $(TESTS) -isort-check: - python -m isort --check $(PYMODULE) - -isort: - python -m isort $(PYMODULE) +fix: + ruff check --fix-only $(PYMODULE) build: python -m build diff --git a/pyproject.toml b/pyproject.toml index 7b0e5a8..b580242 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,24 +1,3 @@ -[tool.mypy] -mypy_path = "stubs" - -warn_unused_ignores = true -warn_return_any = true -show_error_codes = true - -strict_optional = true -implicit_optional = true - -disallow_any_unimported = true -disallow_subclassing_any = true -#disallow_any_generics = true - -disallow_untyped_calls = true -disallow_untyped_defs = true -disallow_incomplete_defs = true -disallow_untyped_decorators = true - -check_untyped_defs = true - [project] name = "april_vision" description = "An AprilTags wrapper with camera discovery and axis conversion." @@ -49,8 +28,7 @@ dependencies = [ [project.optional-dependencies] dev = [ - "flake8", - "isort", + "ruff >=0.0.290,<1", "mypy", "build", "types-Pillow", @@ -80,3 +58,43 @@ build-backend = "setuptools.build_meta" [tool.setuptools_scm] version_file = "april_vision/_version.py" + +# ### Linting Rules ### +[tool.ruff] +ignore = [ + "D105", + "D107", + "D401", + "D203", + "D212", +] +line-length = 95 +select = [ + "D", + "E", + "F", + "I", + "W", +] + +# ### Formatting Rules ### +[tool.mypy] +mypy_path = "stubs" + +warn_unused_ignores = true +warn_return_any = true +show_error_codes = true + +strict_optional = true +implicit_optional = true + +disallow_any_unimported = true +disallow_subclassing_any = true +#disallow_any_generics = true + +disallow_untyped_calls = true +disallow_untyped_defs = true +disallow_incomplete_defs = true +disallow_untyped_decorators = true + +check_untyped_defs = true From 0164a1ee95d20c4a4655a7729fd97acba8675334 Mon Sep 17 00:00:00 2001 From: WillB97 Date: Sat, 6 Apr 2024 09:49:24 +0100 Subject: [PATCH 03/18] Initial lint fixes --- april_vision/__init__.py | 10 ++++-- april_vision/cli/calibrate.py | 18 +++++++--- april_vision/cli/live.py | 1 + april_vision/cli/marker_generator/__init__.py | 2 +- .../marker_generator/marker_modes/mode_cal.py | 3 +- .../marker_modes/mode_image.py | 3 +- .../marker_modes/mode_single.py | 16 ++++++--- .../marker_modes/mode_tile.py | 15 ++++++-- .../cli/marker_generator/marker_tile.py | 36 +++++++++++++------ april_vision/cli/marker_generator/utils.py | 12 +++---- april_vision/cli/tools/__init__.py | 1 + april_vision/cli/tools/family_details.py | 6 ++++ april_vision/cli/tools/list_cameras.py | 2 ++ april_vision/cli/utils.py | 9 +++-- april_vision/examples/camera.py | 20 +++++++---- april_vision/helpers/markers.py | 1 + april_vision/helpers/sender.py | 5 +-- april_vision/marker.py | 21 ++++++----- pyproject.toml | 21 +++++------ 19 files changed, 141 insertions(+), 61 deletions(-) diff --git a/april_vision/__init__.py b/april_vision/__init__.py index de7ce46..06dc40d 100644 --- a/april_vision/__init__.py +++ b/april_vision/__init__.py @@ -1,4 +1,5 @@ """An AprilTags wrapper with camera discovery and axis conversion.""" +# ruff: noqa: E402 import os os.environ["OPENCV_VIDEOIO_MSMF_ENABLE_HW_TRANSFORMS"] = "0" @@ -8,8 +9,13 @@ from .detect_cameras import CalibratedCamera, find_cameras from .frame_sources import FrameSource, USBCamera from .helpers import generate_marker_size_mapping -from .marker import (CartesianCoordinates, Marker, Orientation, - PixelCoordinates, SphericalCoordinate) +from .marker import ( + CartesianCoordinates, + Marker, + Orientation, + PixelCoordinates, + SphericalCoordinate, +) from .utils import Frame from .vision import Processor diff --git a/april_vision/cli/calibrate.py b/april_vision/cli/calibrate.py index a000810..b0445c1 100644 --- a/april_vision/cli/calibrate.py +++ b/april_vision/cli/calibrate.py @@ -1,6 +1,4 @@ -""" -Camera calibration script. -""" +"""Camera calibration script.""" import argparse import logging from datetime import datetime @@ -19,7 +17,8 @@ class CalBoard: - """Class used to represent a calibration board""" + """Class used to represent a calibration board.""" + def __init__( self, rows: int, @@ -38,10 +37,11 @@ def __init__( def corners_from_id(self, marker_id: int) -> List[Tuple[float, float, float]]: """ Takes an input of a marker ID and returns the coordinates of the corners of the marker. + The coordinates are 3D real world positions, top left of the board is 0,0,0. The Z coordinate of the board is always zero. The list of co-ords are in the order: - [bottom_left, bottom_right, top_right, top_left] + bottom_left, bottom_right, top_right, top_left """ marker_pixel_size = self.marker_size / self.marker_details.width_at_border @@ -90,6 +90,7 @@ def parse_detections( ) -> Tuple[List[Tuple[float, float, float]], List[Tuple[float, float]]]: """ Pairs up 2D pixel corners with 3D real world co-ords. + Takes the input of marker detections and the board design and outputs two lists where board_obj_points[i] pairs with board_img_points[i]. """ @@ -108,6 +109,7 @@ def parse_detections( def main(args: argparse.Namespace) -> None: + """Main function for calibrate command.""" # Setup the camera video_dev = cv2.VideoCapture(args.index) @@ -188,6 +190,12 @@ def write_cal_file( avg_reprojection_error: float, vidpid: Optional[str] = None, ) -> None: + """ + Write the calibration data to an XML file. + + This file can be loaded by the detect_cameras module. + The file is also compatible with the OpenCV calibration module. + """ LOGGER.info("Generating calibration XML file") output_filename = cal_filename if not output_filename.lower().endswith(".xml"): diff --git a/april_vision/cli/live.py b/april_vision/cli/live.py index 49a4362..04f8aba 100644 --- a/april_vision/cli/live.py +++ b/april_vision/cli/live.py @@ -25,6 +25,7 @@ def parse_properties(args: argparse.Namespace) -> List[Tuple[int, int]]: + """Parse the camera properties supplied on the command line.""" props = [] if args.set_fps is not None: diff --git a/april_vision/cli/marker_generator/__init__.py b/april_vision/cli/marker_generator/__init__.py index e0e9390..d1681c7 100644 --- a/april_vision/cli/marker_generator/__init__.py +++ b/april_vision/cli/marker_generator/__init__.py @@ -17,9 +17,9 @@ def create_subparser(subparsers: argparse._SubParsersAction) -> None: """ Marker_generator command parser. + Add multiple subparsers to deal with different modes of page generation. """ - parser = subparsers.add_parser( "marker_generator", description="Generate markers", diff --git a/april_vision/cli/marker_generator/marker_modes/mode_cal.py b/april_vision/cli/marker_generator/marker_modes/mode_cal.py index 7bfa523..0ac5b59 100644 --- a/april_vision/cli/marker_generator/marker_modes/mode_cal.py +++ b/april_vision/cli/marker_generator/marker_modes/mode_cal.py @@ -1,3 +1,4 @@ +"""Marker_generator subparser CAL_BOARD used to generate a calibration board.""" import argparse import logging @@ -14,7 +15,7 @@ def main(args: argparse.Namespace) -> None: - """Generate a calibration board""" + """Generate a calibration board.""" tag_data = get_tag_family(args.marker_family) LOGGER.info(tag_data) diff --git a/april_vision/cli/marker_generator/marker_modes/mode_image.py b/april_vision/cli/marker_generator/marker_modes/mode_image.py index 93fd72f..f0f7cd6 100644 --- a/april_vision/cli/marker_generator/marker_modes/mode_image.py +++ b/april_vision/cli/marker_generator/marker_modes/mode_image.py @@ -1,3 +1,4 @@ +"""Marker_generator subparser IMAGE used to generate an image of a marker.""" import argparse import logging @@ -14,7 +15,7 @@ def main(args: argparse.Namespace) -> None: - """Generate a marker image""" + """Generate a marker image.""" tag_data = get_tag_family(args.marker_family) LOGGER.info(tag_data) diff --git a/april_vision/cli/marker_generator/marker_modes/mode_single.py b/april_vision/cli/marker_generator/marker_modes/mode_single.py index 4b07172..7a0ec99 100644 --- a/april_vision/cli/marker_generator/marker_modes/mode_single.py +++ b/april_vision/cli/marker_generator/marker_modes/mode_single.py @@ -1,3 +1,4 @@ +"""Marker_generator subparser SINGLE used to generate a PDF of a marker.""" import argparse import logging from typing import Union @@ -8,15 +9,22 @@ from april_vision.marker import MarkerType from ..marker_tile import MarkerTile -from ..utils import (DEFAULT_COLOUR, DEFAULT_FONT, DEFAULT_FONT_SIZE, DPI, - CustomPageSize, PageSize, mm_to_pixels, - parse_marker_ranges) +from ..utils import ( + DEFAULT_COLOUR, + DEFAULT_FONT, + DEFAULT_FONT_SIZE, + DPI, + CustomPageSize, + PageSize, + mm_to_pixels, + parse_marker_ranges, +) LOGGER = logging.getLogger(__name__) def main(args: argparse.Namespace) -> None: - """Generate a single marker on a page with the provided arguments""" + """Generate a single marker on a page with the provided arguments.""" tag_data = get_tag_family(args.marker_family) LOGGER.info(tag_data) diff --git a/april_vision/cli/marker_generator/marker_modes/mode_tile.py b/april_vision/cli/marker_generator/marker_modes/mode_tile.py index 1c2b7dd..a4ada78 100644 --- a/april_vision/cli/marker_generator/marker_modes/mode_tile.py +++ b/april_vision/cli/marker_generator/marker_modes/mode_tile.py @@ -1,3 +1,4 @@ +"""Marker generator mode to generate a PDF with multiple markers per page.""" import argparse import logging @@ -7,14 +8,21 @@ from april_vision.marker import MarkerType from ..marker_tile import MarkerTile -from ..utils import (DEFAULT_COLOUR, DEFAULT_FONT, DEFAULT_FONT_SIZE, DPI, - PageSize, mm_to_pixels, parse_marker_ranges) +from ..utils import ( + DEFAULT_COLOUR, + DEFAULT_FONT, + DEFAULT_FONT_SIZE, + DPI, + PageSize, + mm_to_pixels, + parse_marker_ranges, +) LOGGER = logging.getLogger(__name__) def main(args: argparse.Namespace) -> None: - """Generate a page of multiple markers with the provided arguments""" + """Generate a page of multiple markers with the provided arguments.""" tag_data = get_tag_family(args.marker_family) LOGGER.info(tag_data) @@ -147,6 +155,7 @@ def main(args: argparse.Namespace) -> None: def create_subparser(subparsers: argparse._SubParsersAction) -> None: """ Marker_generator subparser TILE. + Used to generate a PDF with multiple markers per page. """ parser = subparsers.add_parser("TILE", help="Generate multiple markers per page") diff --git a/april_vision/cli/marker_generator/marker_tile.py b/april_vision/cli/marker_generator/marker_tile.py index c411381..3d09100 100644 --- a/april_vision/cli/marker_generator/marker_tile.py +++ b/april_vision/cli/marker_generator/marker_tile.py @@ -1,3 +1,8 @@ +""" +Used to generate an image tile which can be customised. + +These image tiles can be arranged on a page in the different modes. +""" from typing import NamedTuple import numpy as np @@ -11,12 +16,16 @@ class coord(NamedTuple): + """Simple class to store coordinates.""" + x: int y: int def generate_tag_array(tag_data: ApriltagFamily, tag_id: int) -> NDArray: """ + Generate a marker array for a given tag family and tag ID. + Uses the tag family object to generate a marker, returns this data as a 2d numpy array where each of the cells is 1 pixel of the marker. """ @@ -53,8 +62,10 @@ def generate_tag_array(tag_data: ApriltagFamily, tag_id: int) -> NDArray: class MarkerTile: """ Used to generate an image tile which can be customised. - These image tiles can be arranged on a page in the different modes + + These image tiles can be arranged on a page in the different modes. """ + def __init__( self, tag_data: ApriltagFamily, @@ -64,7 +75,8 @@ def __init__( ): """ Generate a basic marker, no overlays, scaled to the correct size. - The marker PIL.Image can be accessed via MarkerTile.image + + The marker PIL.Image can be accessed via MarkerTile.image. """ self.tag_data = tag_data self.tag_id = tag_id @@ -101,8 +113,9 @@ def add_border_line( border_colour: str, ) -> None: """ - Add a line arround the board of the marker, - changes the current marker design in place. + Add a line around the border of the marker. + + This changes the current marker design in place. """ bordered_image = ImageOps.expand( self.image, @@ -129,8 +142,9 @@ def add_centre_ticks( tick_colour: str, ) -> None: """ - Add tick lines half way along the border of the marker, - changes the current marker design in place. + Add tick lines half way along the border of the marker. + + This changes the current marker design in place. """ img_size = self.image.size[0] image_draw = ImageDraw.Draw(self.image) @@ -172,8 +186,9 @@ def add_id_number( text_colour: str, ) -> None: """ - Add the ID number in the top left square of the white border, - changes the current marker design in place. + Add the ID number in the top left square of the white border. + + This changes the current marker design in place. """ # Add text to the image marker_square_size = mm_to_pixels(self.pixel_size) @@ -211,8 +226,9 @@ def add_description_border( double_text: bool = False, ) -> None: """ - Expand the marker by one marker square and add description text to this area, - changes the current marker design in place. + Expand the marker by one marker square and add description text to this area. + + This changes the current marker design in place. """ marker_square_size = mm_to_pixels(self.pixel_size) diff --git a/april_vision/cli/marker_generator/utils.py b/april_vision/cli/marker_generator/utils.py index 0eef21f..9e90de4 100644 --- a/april_vision/cli/marker_generator/utils.py +++ b/april_vision/cli/marker_generator/utils.py @@ -1,3 +1,4 @@ +"""Utility functions for the marker generator.""" import logging from enum import Enum from typing import List, Tuple @@ -17,6 +18,7 @@ def parse_marker_ranges(marker_family: ApriltagFamily, range_str: str) -> List[int]: """ Utility function to parse the provided range of markers. + Also checks bounds against the marker family. """ if range_str == "ALL": @@ -37,17 +39,14 @@ def parse_marker_ranges(marker_family: ApriltagFamily, range_str: str) -> List[i def mm_to_pixels(mm: float) -> int: - """ - Convert millimeters to pixels - """ + """Convert millimeters to pixels.""" inches = mm / 25.4 return int(inches * DPI) class PageSize(Enum): - """ - Enum to define the dimentions of different page sizes - """ + """Enum to define the dimentions of different page sizes.""" + A3 = (297, 420) A3L = (420, 297) A4 = (210, 297) @@ -55,6 +54,7 @@ class PageSize(Enum): @property def pixels(self) -> Tuple[int, int]: + """Return the page size in pixels.""" return ( mm_to_pixels(self.value[0]), mm_to_pixels(self.value[1]), diff --git a/april_vision/cli/tools/__init__.py b/april_vision/cli/tools/__init__.py index 9a66094..c37e52f 100644 --- a/april_vision/cli/tools/__init__.py +++ b/april_vision/cli/tools/__init__.py @@ -8,6 +8,7 @@ def create_subparser(subparsers: argparse._SubParsersAction) -> None: + """Subparser for the tools commands.""" parser = subparsers.add_parser( "tools", description="A collection of useful tools", diff --git a/april_vision/cli/tools/family_details.py b/april_vision/cli/tools/family_details.py index f9127de..ea11f91 100644 --- a/april_vision/cli/tools/family_details.py +++ b/april_vision/cli/tools/family_details.py @@ -1,3 +1,8 @@ +""" +Provide the details about a marker family. + +The values are extracted from the AprilTag binary. +""" import argparse import logging @@ -9,6 +14,7 @@ def main(args: argparse.Namespace) -> None: + """Provide the details about a marker family.""" tag_data = get_tag_family(args.tag_family) print(tag_data) diff --git a/april_vision/cli/tools/list_cameras.py b/april_vision/cli/tools/list_cameras.py index b9a663e..846c929 100644 --- a/april_vision/cli/tools/list_cameras.py +++ b/april_vision/cli/tools/list_cameras.py @@ -1,3 +1,4 @@ +"""List out the available cameras connected to the system.""" import argparse from tabulate import tabulate @@ -7,6 +8,7 @@ def main(args: argparse.Namespace) -> None: + """List out the available cameras connected to the system.""" cameras = find_cameras(calibrations, include_uncalibrated=True) print(tabulate(cameras, headers="keys")) diff --git a/april_vision/cli/utils.py b/april_vision/cli/utils.py index 5ed672b..52a275e 100644 --- a/april_vision/cli/utils.py +++ b/april_vision/cli/utils.py @@ -1,9 +1,12 @@ +"""Utility functions for the CLI.""" from typing import List, NamedTuple, Tuple import pyapriltags class ApriltagFamily(NamedTuple): + """Class used to represent the inforamtion about a tag family.""" + ncodes: int codes: List[int] width_at_border: int @@ -29,6 +32,7 @@ def __str__(self) -> str: def get_tag_family(family: str) -> ApriltagFamily: """ Use the C-types in pyapriltags to get the tag family object. + This object contains the required data to draw all the tags for a given family. """ d = pyapriltags.Detector(families=family) @@ -53,8 +57,9 @@ def get_tag_family(family: str) -> ApriltagFamily: def parse_ranges(ranges: str) -> List[int]: """ - Parse a comma seprated list of numbers which may include ranges - specified as hyphen-separated numbers. + Parse a comma separated list of numbers which may include ranges. + + Ranges specified as hyphen-separated numbers. From https://stackoverflow.com/questions/6405208 """ result: List[int] = [] diff --git a/april_vision/examples/camera.py b/april_vision/examples/camera.py index a7ee0f3..7da0d70 100644 --- a/april_vision/examples/camera.py +++ b/april_vision/examples/camera.py @@ -1,12 +1,22 @@ +"""An example implementation for using april_vision as a library.""" + import logging from pathlib import Path from typing import Callable, Dict, Iterable, List, Optional, Union from numpy.typing import NDArray -from april_vision import (CalibratedCamera, Frame, Marker, Processor, - USBCamera, __version__, calibrations, find_cameras, - generate_marker_size_mapping) +from april_vision import ( + CalibratedCamera, + Frame, + Marker, + Processor, + USBCamera, + __version__, + calibrations, + find_cameras, + generate_marker_size_mapping, +) from april_vision.helpers import Base64Sender LOGGER = logging.getLogger(__name__) @@ -111,9 +121,7 @@ def set_marker_sizes( self._cam.set_marker_sizes(tag_sizes) def set_detection_hook(self, callback: Callable[[Frame, List[Marker]], None]) -> None: - """ - Setup a callback to be run after each dectection. - """ + """Setup a callback to be run after each dectection.""" self._cam.detection_hook = callback diff --git a/april_vision/helpers/markers.py b/april_vision/helpers/markers.py index 6883327..5a511f0 100644 --- a/april_vision/helpers/markers.py +++ b/april_vision/helpers/markers.py @@ -7,6 +7,7 @@ def generate_marker_size_mapping( ) -> Dict[int, float]: """ Unroll a dict of iterables into a dict of floats. + To be used in pose estimation. """ tag_sizes: Dict[int, float] = {} diff --git a/april_vision/helpers/sender.py b/april_vision/helpers/sender.py index 50bf1f8..1185972 100644 --- a/april_vision/helpers/sender.py +++ b/april_vision/helpers/sender.py @@ -1,3 +1,4 @@ +"""Helper classes for sending image data.""" import base64 from threading import Thread from typing import Callable, List, Optional @@ -21,6 +22,7 @@ class Base64Sender: :param threaded: Controls whether encoding and sending the image is processed in a thread or blocks. """ + def __init__( self, publish_callback: Callable[[str, bytes], None], @@ -62,8 +64,7 @@ def annotated_frame_hook(self, frame: Frame, markers: List[Marker]) -> None: def encode_and_send(self, frame: NDArray[np.uint8]) -> None: """ - Handle converting a frame to a base64 bytestring and sending it using - the publish callback. + Convert a frame to a base64 bytestring and send it using the publish callback. Can be run as a thread target. """ diff --git a/april_vision/marker.py b/april_vision/marker.py index 087e673..58804aa 100644 --- a/april_vision/marker.py +++ b/april_vision/marker.py @@ -1,6 +1,4 @@ -""" -Classes for marker detections and various axis representations. -""" +"""Classes for marker detections and various axis representations.""" from enum import Enum from math import acos, atan2, cos, degrees, sin from typing import NamedTuple, Optional, Tuple, cast @@ -210,7 +208,8 @@ def rotation_matrix(self) -> RotationMatrix: Conversion calculation: https://w.wiki/6gbp - Returns: + Returns + ------- A 3x3 rotation matrix as a tuple of tuples. """ psi, theta, phi = self.yaw, self.pitch, self.roll @@ -235,7 +234,8 @@ def quaternion(self) -> Tuple[float, float, float, float]: Conversion calculation: https://w.wiki/6gbq - Returns: + Returns + ------- A 4-tuple hamiltonian quaternion. """ psi_2, theta_2, phi_2 = self.yaw / 2, self.pitch / 2, self.roll / 2 @@ -251,9 +251,7 @@ def quaternion(self) -> Tuple[float, float, float, float]: class Marker(NamedTuple): - """ - Wrapper of a marker detection with axis and rotation calculated. - """ + """Wrapper of a marker detection with axis and rotation calculated.""" rvec: Optional[NDArray] tvec: Optional[NDArray] @@ -281,6 +279,12 @@ def from_detection( *, aruco_orientation: bool = False, ) -> 'Marker': + """ + Create a Marker object from a pyapriltags Detection object. + + :param marker: The marker detection object. + :param aruco_orientation: Rotate marker 180 for aruco orientation. + """ _tag_size = int((marker.tag_size or 0) * 1000) _pixel_corners = tuple( @@ -334,6 +338,7 @@ def from_detection( ) def has_pose(self) -> bool: + """Return True if the marker has pose estimation data.""" return (self.rvec is not None and self.tvec is not None) def __repr__(self) -> str: diff --git a/pyproject.toml b/pyproject.toml index b580242..490a947 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,19 +62,20 @@ version_file = "april_vision/_version.py" # ### Linting Rules ### [tool.ruff] ignore = [ - "D105", - "D107", - "D401", - "D203", - "D212", + "D104", # Ignoe missing docstring in public package + "D105", # Ignore missing docstring in magic method + "D107", # Ignore missing docstring in __init__ + "D401", # Ignore first line of docstring should be in imperative mood + "D203", # Ignore 1 blank line required before class docstring + "D212", # Ignore Multi-line docstring summary should start at the first line ] line-length = 95 select = [ - "D", - "E", - "F", - "I", - "W", + "D", # pydocstyle + "E", # pycodestyle error + "F", # pyflakes + "I", # isort + "W", # pycodestyle warning ] # ### Formatting Rules ### From 350d6a8822398b3d3dee7cba799872eb512b4123 Mon Sep 17 00:00:00 2001 From: WillB97 Date: Sat, 6 Apr 2024 09:49:24 +0100 Subject: [PATCH 04/18] Avoid putting the test data in the wheel --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 490a947..d5b19e7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,6 +52,9 @@ Repository = "https://github.com/WillB97/april_vision" [tool.setuptools.packages] find = {} +[tool.setuptools.exclude-package-data] +"tests.test_data" = ["*"] + [build-system] requires = ["setuptools>=60", "wheel", "setuptools_scm>=8"] build-backend = "setuptools.build_meta" From 731f292f41f4af9413a4dd7fdd5c93025efe6972 Mon Sep 17 00:00:00 2001 From: WillB97 Date: Sat, 6 Apr 2024 09:49:24 +0100 Subject: [PATCH 05/18] Add some badges --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 5f52e8d..0cfe293 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # april_vision +[![Lint & build](https://github.com/WillB97/april_vision/actions/workflows/check.yml/badge.svg)](https://github.com/WillB97/april_vision/actions/workflows/check.yml) +[![PyPI version](https://badge.fury.io/py/april-vision.svg)](https://badge.fury.io/py/april-vision) +[![MIT license](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)](https://opensource.org/licenses/MIT) + A fiducial marker system used by Student Robotics. Uses [april tag](https://april.eecs.umich.edu/software/apriltag) markers to provide detection, pose and distance estimation for these markers. From 7f674e13345b44844bc427371f4f84ec73e4b855 Mon Sep 17 00:00:00 2001 From: WillB97 Date: Sat, 6 Apr 2024 09:49:24 +0100 Subject: [PATCH 06/18] Add poethepoet to make the tooling cross-platform --- pyproject.toml | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index d5b19e7..80ef2c1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,6 +28,7 @@ dependencies = [ [project.optional-dependencies] dev = [ + "poethepoet >=0.0.1,<1", "ruff >=0.0.290,<1", "mypy", "build", @@ -102,3 +103,46 @@ disallow_incomplete_defs = true disallow_untyped_decorators = true check_untyped_defs = true + +# ### Tasks ### +[tool.poe.env] +PYMODULE = "april_vision" + +[tool.poe.tasks] +_upload = "python -m twine upload dist/*" + +[tool.poe.tasks.lint] +help = "Run ruff against the project to check for linting errors." +cmd = "ruff check $PYMODULE" + +[tool.poe.tasks.type] +help = "Run mypy against the project to check for type errors." +cmd = "python -m mypy $PYMODULE" + +[tool.poe.tasks.test] +help = "Run pytest against the project to check for test errors." +cmd = "python -m pytest --cov=$PYMODULE --cov-report=term --cov-report=xml tests" + +[tool.poe.tasks.check] +help = "Check the project for linting, type and test errors." +sequence = ["lint", "type", "test"] + +[tool.poe.tasks.fix] +help = "Use ruff to fix any auto-fixable linting errors." +cmd = "ruff check --fix-only $PYMODULE" + +[tool.poe.tasks.build] +help = "Build the wheel and source distributions." +cmd = "python -m build" + +[tool.poe.tasks.upload] +help = "Build and upload the wheel and source distributions to PyPI." +sequence = ["build", "_upload"] + +[tool.poe.tasks.clean] +help = "Clean the project of any build artifacts." +sequence = [ + "shutil:rmtree('dist', ignore_errors=1)", + "shutil:rmtree('build', ignore_errors=1)", +] +default_item_type = "script" From 5e316ed484fdd1c9489e39bf9d4389d6e0f57450 Mon Sep 17 00:00:00 2001 From: WillB97 Date: Sat, 6 Apr 2024 09:49:24 +0100 Subject: [PATCH 07/18] Switch to poe in CI --- .github/workflows/check.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 106f7a6..9fcc1e1 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -20,16 +20,16 @@ jobs: python -m pip install 'opencv-python-headless>=4.8,<4.9' - name: Lint run: | - make lint + poe lint - name: Typecheck run: | - make type + poe type - name: Test run: | - make test + poe test - name: Build package run: | - make build + poe build - name: Save built package uses: actions/upload-artifact@v3 with: From f9257ce9600f6b2b398ac0ee2ea7ba21a475e712 Mon Sep 17 00:00:00 2001 From: WillB97 Date: Sat, 6 Apr 2024 09:50:43 +0100 Subject: [PATCH 08/18] Update CI to test with matrix and use trusted publishing --- .github/workflows/check.yml | 44 ------------------ .github/workflows/test_build.yml | 76 ++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 44 deletions(-) delete mode 100644 .github/workflows/check.yml create mode 100644 .github/workflows/test_build.yml diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml deleted file mode 100644 index 9fcc1e1..0000000 --- a/.github/workflows/check.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Lint & build - -on: - push: - workflow_dispatch: - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Set up Python 3.8 - uses: actions/setup-python@v4 - with: - python-version: "3.8" - - name: Install dependencies - run: | - python -m pip install --upgrade pip - python -m pip install .[dev,cli] - python -m pip install 'opencv-python-headless>=4.8,<4.9' - - name: Lint - run: | - poe lint - - name: Typecheck - run: | - poe type - - name: Test - run: | - poe test - - name: Build package - run: | - poe build - - name: Save built package - uses: actions/upload-artifact@v3 - with: - name: package - path: | - dist - - name: Publish to PyPi - if: ${{ github.ref_type == 'tag' }} - uses: pypa/gh-action-pypi-publish@v1.6.4 - with: - password: ${{ secrets.PYPI_API_TOKEN }} - print_hash: true diff --git a/.github/workflows/test_build.yml b/.github/workflows/test_build.yml new file mode 100644 index 0000000..6a20e28 --- /dev/null +++ b/.github/workflows/test_build.yml @@ -0,0 +1,76 @@ +name: Lint & build + +on: + push: + workflow_dispatch: + +jobs: + test: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + py_version: ["3.8", "3.9", "3.10", "3.11"] + include: + - os: windows-latest + py_version: "3.8" + - os: windows-latest + py_version: "3.11" + - os: macos-latest + py_version: "3.8" + - os: macos-latest + py_version: "3.11" + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.py_version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install .[dev,cli] + python -m pip install 'opencv-python-headless>=4.8,<4.9' + - name: Lint + run: | + poe lint + - name: Typecheck + run: | + poe type + - name: Run tests + run: | + poe test + + build: + permissions: + id-token: write # IMPORTANT: this permission is mandatory for trusted publishing + runs-on: ubuntu-latest + needs: test + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Set up Python 3.8 + uses: actions/setup-python@v4 + with: + python-version: "3.8" + - name: Install dependencies + run: | + python -m pip install --upgrade pip build poethepoet + # Install package to generate version info + python -m pip install --no-deps . + - name: Build package + run: | + poe build + - name: Save built package + uses: actions/upload-artifact@v3 + with: + name: package + path: | + dist + - name: Publish to PyPi + if: ${{ github.ref_type == 'tag' }} + uses: pypa/gh-action-pypi-publish@release/v1 From 9c772a267179a06b96faa5ead0c4bcec47aa2153 Mon Sep 17 00:00:00 2001 From: WillB97 Date: Sat, 6 Apr 2024 09:50:43 +0100 Subject: [PATCH 09/18] Fix windows typing --- april_vision/detect_cameras.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/april_vision/detect_cameras.py b/april_vision/detect_cameras.py index 67d96aa..b5aa8dd 100644 --- a/april_vision/detect_cameras.py +++ b/april_vision/detect_cameras.py @@ -212,7 +212,9 @@ def windows_discovery() -> List[CameraIdentifier]: """ import asyncio - import winsdk.windows.devices.enumeration as windows_devices # type: ignore + assert sys.platform != 'win32', "This method is only for Windows" + + import winsdk.windows.devices.enumeration as windows_devices # type: ignore[import, unused-ignore] # noqa: E501 async def get_camera_info(): # type: ignore device_class = windows_devices.DeviceClass.VIDEO_CAPTURE From 6c438e9e039bacd5253aac403156aee34cd62e85 Mon Sep 17 00:00:00 2001 From: WillB97 Date: Sat, 6 Apr 2024 09:50:43 +0100 Subject: [PATCH 10/18] Missing whitespace --- april_vision/cli/marker_generator/marker_tile.py | 4 ++-- april_vision/cli/vision_debug.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/april_vision/cli/marker_generator/marker_tile.py b/april_vision/cli/marker_generator/marker_tile.py index 3d09100..8f8bce4 100644 --- a/april_vision/cli/marker_generator/marker_tile.py +++ b/april_vision/cli/marker_generator/marker_tile.py @@ -44,7 +44,7 @@ def generate_tag_array(tag_data: ApriltagFamily, tag_id: int) -> NDArray: left_border_edge = border_edge right_border_edge = border_edge + tag_data.width_at_border - 1 - for i in range(left_border_edge, right_border_edge+1): + for i in range(left_border_edge, right_border_edge + 1): tag[left_border_edge][i] = 0 tag[i][left_border_edge] = 0 tag[right_border_edge][i] = 0 @@ -54,7 +54,7 @@ def generate_tag_array(tag_data: ApriltagFamily, tag_id: int) -> NDArray: max_index = tag_data.nbits - 1 for i, (x, y) in enumerate(tag_data.bits): binary = bool(tag_data.codes[tag_id] & (1 << (max_index - i))) - tag[y+border_edge][x+border_edge] = 255 if binary else 0 + tag[y + border_edge][x + border_edge] = 255 if binary else 0 return tag diff --git a/april_vision/cli/vision_debug.py b/april_vision/cli/vision_debug.py index 9958425..5802cfd 100644 --- a/april_vision/cli/vision_debug.py +++ b/april_vision/cli/vision_debug.py @@ -81,12 +81,12 @@ def create_collage(files: List[str], out: str) -> None: img = Image.open(files[-1]) width, height = img.size - target_img = Image.new("RGB", (width*4, height*2)) + target_img = Image.new("RGB", (width * 4, height * 2)) for k, png in enumerate(files): col, row = divmod(k, 4) img = Image.open(png) img.thumbnail((width, height)) - target_img.paste(img, (width*row, height*col)) + target_img.paste(img, (width * row, height * col)) target_img.save(out) LOGGER.info("Generated debug collage.") From 1c1b1b50a396afab3fc3b435dc234b8b5e9a307b Mon Sep 17 00:00:00 2001 From: WillB97 Date: Sat, 6 Apr 2024 09:50:43 +0100 Subject: [PATCH 11/18] Drop makefile --- Makefile | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 Makefile diff --git a/Makefile b/Makefile deleted file mode 100644 index f563fd4..0000000 --- a/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -.PHONY: lint type test isort isort-check build upload - -PYMODULE:=april_vision -TESTS:=tests - -all: lint isort-check type test - -lint: - ruff check $(PYMODULE) - -type: - mypy $(PYMODULE) - -test: - pytest --cov=$(PYMODULE) --cov-report=term --cov-report=xml $(TESTS) - -fix: - ruff check --fix-only $(PYMODULE) - -build: - python -m build - -upload: - twine upload dist/* - -clean: - rm -rf dist/* build/* From 3be1377ffe8f622860c9665fd221fedaa558f863 Mon Sep 17 00:00:00 2001 From: WillB97 Date: Sat, 6 Apr 2024 09:50:43 +0100 Subject: [PATCH 12/18] More linting rules --- april_vision/frame_sources.py | 2 +- pyproject.toml | 24 ++++++++++++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/april_vision/frame_sources.py b/april_vision/frame_sources.py index 0321513..fc8b126 100644 --- a/april_vision/frame_sources.py +++ b/april_vision/frame_sources.py @@ -125,7 +125,7 @@ def from_calibration_file( camera_parameters=list(camera_props.items()), ) - def _set_camera_property(self, property: int, value: int) -> None: # noqa: A002 + def _set_camera_property(self, property: int, value: int) -> None: """Set an opencv property to a value and assert that it changed.""" self._camera.set(property, value) actual = self._camera.get(property) diff --git a/pyproject.toml b/pyproject.toml index 80ef2c1..f1479d3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,14 +65,6 @@ version_file = "april_vision/_version.py" # ### Linting Rules ### [tool.ruff] -ignore = [ - "D104", # Ignoe missing docstring in public package - "D105", # Ignore missing docstring in magic method - "D107", # Ignore missing docstring in __init__ - "D401", # Ignore first line of docstring should be in imperative mood - "D203", # Ignore 1 blank line required before class docstring - "D212", # Ignore Multi-line docstring summary should start at the first line -] line-length = 95 select = [ "D", # pydocstyle @@ -80,6 +72,22 @@ select = [ "F", # pyflakes "I", # isort "W", # pycodestyle warning + "RUF", # ruff-specific + "B006", # mutable default argument + "B021", # f-string docstring + "COM818", # warn about implicitly creating a tuple + # "SLF001", # warn about accessing private members, these can be noqa'd when necessary +] +preview = true # Enable preview to get the rest of pycodestyle errors +ignore = [ + "D104", # Ignoe missing docstring in public package + "D105", # Ignore missing docstring in magic method + "D107", # Ignore missing docstring in __init__ + "D401", # Ignore first line of docstring should be in imperative mood + "D203", # Ignore 1 blank line required before class docstring + "D212", # Ignore Multi-line docstring summary should start at the first line + "RUF005", # Allow alternate iterable unpacking + "RUF015", # Allow + concatenation ] # ### Formatting Rules ### From 41c786866a0cc0499d085b5bc15c7b69e4f635dd Mon Sep 17 00:00:00 2001 From: WillB97 Date: Sat, 6 Apr 2024 09:54:24 +0100 Subject: [PATCH 13/18] Correct CustomPageSize docstrings --- april_vision/cli/marker_generator/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/april_vision/cli/marker_generator/utils.py b/april_vision/cli/marker_generator/utils.py index 9e90de4..99c5db6 100644 --- a/april_vision/cli/marker_generator/utils.py +++ b/april_vision/cli/marker_generator/utils.py @@ -62,15 +62,15 @@ def pixels(self) -> Tuple[int, int]: class CustomPageSize: - """ - Class to define a custom page size - """ + """Class to define a custom page size.""" + def __init__(self, width: int, height: int) -> None: self.width = width self.height = height @property def pixels(self) -> Tuple[int, int]: + """Return the custom page size in pixels.""" return ( mm_to_pixels(self.width), mm_to_pixels(self.height), From c804ba7efd415e8e886594aad52c37ad08be79d2 Mon Sep 17 00:00:00 2001 From: WillB97 Date: Sat, 6 Apr 2024 10:30:30 +0100 Subject: [PATCH 14/18] Add updates for newer ruff versioning --- april_vision/__init__.py | 2 +- april_vision/cli/calibrate.py | 4 ++-- april_vision/cli/vision_debug.py | 2 +- april_vision/marker.py | 2 ++ pyproject.toml | 4 ++-- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/april_vision/__init__.py b/april_vision/__init__.py index 06dc40d..ab2c499 100644 --- a/april_vision/__init__.py +++ b/april_vision/__init__.py @@ -20,7 +20,6 @@ from .vision import Processor __all__ = [ - '__version__', 'CalibratedCamera', 'CartesianCoordinates', 'Frame', @@ -31,6 +30,7 @@ 'Processor', 'SphericalCoordinate', 'USBCamera', + '__version__', 'calibrations', 'find_cameras', 'generate_marker_size_mapping', diff --git a/april_vision/cli/calibrate.py b/april_vision/cli/calibrate.py index b0445c1..e794440 100644 --- a/april_vision/cli/calibrate.py +++ b/april_vision/cli/calibrate.py @@ -68,7 +68,7 @@ def frame_capture( LOGGER.info("Press space to capture frame.") while True: - ret, frame = cap.read() + _ret, frame = cap.read() cv2.imshow("Frame", frame) @@ -154,7 +154,7 @@ def main(args: argparse.Namespace) -> None: width, height = frames[0].grey_frame.shape[::-1] # Calculate the camera calibration - reproj_error, camera_matrix, dist_coeff, rvec, tvec = cv2.calibrateCamera( + reproj_error, camera_matrix, dist_coeff, _rvec, _tvec = cv2.calibrateCamera( objectPoints, imagePoints, (width, height), diff --git a/april_vision/cli/vision_debug.py b/april_vision/cli/vision_debug.py index 5802cfd..8137001 100644 --- a/april_vision/cli/vision_debug.py +++ b/april_vision/cli/vision_debug.py @@ -107,7 +107,7 @@ def main(args: argparse.Namespace) -> None: # change directory around the debug process with pushd(args.output_dir): results = detector.detect(frame) - LOGGER.info(f"Found {len(results)} {'marker' if len(results)==1 else 'markers'}") + LOGGER.info(f"Found {len(results)} {'marker' if len(results) == 1 else 'markers'}") process_debug( preserve=not args.cleanup, diff --git a/april_vision/marker.py b/april_vision/marker.py index 58804aa..120959c 100644 --- a/april_vision/marker.py +++ b/april_vision/marker.py @@ -211,6 +211,7 @@ def rotation_matrix(self) -> RotationMatrix: Returns ------- A 3x3 rotation matrix as a tuple of tuples. + """ psi, theta, phi = self.yaw, self.pitch, self.roll @@ -237,6 +238,7 @@ def quaternion(self) -> Tuple[float, float, float, float]: Returns ------- A 4-tuple hamiltonian quaternion. + """ psi_2, theta_2, phi_2 = self.yaw / 2, self.pitch / 2, self.roll / 2 w = cos(phi_2) * cos(theta_2) * cos(psi_2) + sin(phi_2) * sin(theta_2) * sin(psi_2) diff --git a/pyproject.toml b/pyproject.toml index f1479d3..d9b3187 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,7 @@ dependencies = [ [project.optional-dependencies] dev = [ "poethepoet >=0.0.1,<1", - "ruff >=0.0.290,<1", + "ruff >=0.3.0,<0.4", "mypy", "build", "types-Pillow", @@ -42,7 +42,7 @@ cli = [ "tabulate >=0.9.0,<1", "font-roboto >=0.0.1", ] -opencv = ["opencv-python-headless >=4,<5"] +opencv = ["opencv-python-headless >=4,<4.9"] [project.scripts] april_vision = "april_vision.cli:main" From 273d45390c216ae61f309912948d4dc2504f16c4 Mon Sep 17 00:00:00 2001 From: WillB97 Date: Sat, 6 Apr 2024 10:30:45 +0100 Subject: [PATCH 15/18] Update badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0cfe293..b1d941d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # april_vision -[![Lint & build](https://github.com/WillB97/april_vision/actions/workflows/check.yml/badge.svg)](https://github.com/WillB97/april_vision/actions/workflows/check.yml) +[![Lint & build](https://github.com/WillB97/april_vision/actions/workflows/test_build.yml/badge.svg)](https://github.com/WillB97/april_vision/actions/workflows/test_build.yml) [![PyPI version](https://badge.fury.io/py/april-vision.svg)](https://badge.fury.io/py/april-vision) [![MIT license](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)](https://opensource.org/licenses/MIT) From 0606da11e9889a70fdedc820ffd7004b3d25ad75 Mon Sep 17 00:00:00 2001 From: WillB97 Date: Sat, 6 Apr 2024 10:31:05 +0100 Subject: [PATCH 16/18] Fix win32 assert --- april_vision/detect_cameras.py | 4 ++-- pyproject.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/april_vision/detect_cameras.py b/april_vision/detect_cameras.py index b5aa8dd..e40eae9 100644 --- a/april_vision/detect_cameras.py +++ b/april_vision/detect_cameras.py @@ -212,9 +212,9 @@ def windows_discovery() -> List[CameraIdentifier]: """ import asyncio - assert sys.platform != 'win32', "This method is only for Windows" + assert sys.platform == 'win32', "This method is only for Windows" - import winsdk.windows.devices.enumeration as windows_devices # type: ignore[import, unused-ignore] # noqa: E501 + import winsdk.windows.devices.enumeration as windows_devices # type: ignore[import-not-found,unused-ignore] async def get_camera_info(): # type: ignore device_class = windows_devices.DeviceClass.VIDEO_CAPTURE diff --git a/pyproject.toml b/pyproject.toml index d9b3187..151abba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,7 @@ dependencies = [ dev = [ "poethepoet >=0.0.1,<1", "ruff >=0.3.0,<0.4", - "mypy", + "mypy==1.9.0", "build", "types-Pillow", "types-tabulate", From 366a1fe02af6eb817dbd65f10059c220cb008b2b Mon Sep 17 00:00:00 2001 From: WillB97 Date: Sat, 6 Apr 2024 10:48:35 +0100 Subject: [PATCH 17/18] Update ruff config --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 151abba..795af56 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,7 +66,7 @@ version_file = "april_vision/_version.py" # ### Linting Rules ### [tool.ruff] line-length = 95 -select = [ +lint.select = [ "D", # pydocstyle "E", # pycodestyle error "F", # pyflakes @@ -79,7 +79,7 @@ select = [ # "SLF001", # warn about accessing private members, these can be noqa'd when necessary ] preview = true # Enable preview to get the rest of pycodestyle errors -ignore = [ +lint.ignore = [ "D104", # Ignoe missing docstring in public package "D105", # Ignore missing docstring in magic method "D107", # Ignore missing docstring in __init__ From 6ebbc230041fe19e2d20e696d1da73a5f9061655 Mon Sep 17 00:00:00 2001 From: Will Barber Date: Sat, 6 Apr 2024 19:46:37 +0100 Subject: [PATCH 18/18] Update CI (#34) * Update CI versions * Update upload-artifact --- .github/workflows/test_build.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test_build.yml b/.github/workflows/test_build.yml index 6a20e28..e1518bd 100644 --- a/.github/workflows/test_build.yml +++ b/.github/workflows/test_build.yml @@ -22,11 +22,11 @@ jobs: py_version: "3.11" runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.py_version }} - name: Install dependencies @@ -50,11 +50,11 @@ jobs: runs-on: ubuntu-latest needs: test steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Python 3.8 - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.8" - name: Install dependencies @@ -66,7 +66,7 @@ jobs: run: | poe build - name: Save built package - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: package path: |