Skip to content

Commit

Permalink
Set up code checks (#25)
Browse files Browse the repository at this point in the history
  • Loading branch information
jaagut authored Sep 18, 2023
2 parents a2268f9 + 65c0d14 commit 1452016
Show file tree
Hide file tree
Showing 14 changed files with 134 additions and 88 deletions.
4 changes: 4 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
Language: Cpp
BasedOnStyle: Google
ColumnLimit: 120
2 changes: 2 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Add git commit hashes to ignore for blame
0da6a5e499812b03d4135ff32a9b1ab01bd07ed9
16 changes: 16 additions & 0 deletions .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: Code style checks

on:
pull_request:
push:
branches: [main]

jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v3
- name: Install cppcheck
run: sudo apt install cppcheck -y
- uses: pre-commit/[email protected]
23 changes: 23 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.0.277
hooks:
- id: ruff
args:
- "--fix"
- "--exit-non-zero-on-fix"
- repo: https://github.com/psf/black
rev: 23.3.0
hooks:
- id: black
- repo: https://github.com/pocc/pre-commit-hooks
rev: v1.3.5
hooks:
- id: clang-format
args:
- "-i"
- id: cppcheck
args:
- "--suppress=missingInclude"
- "--suppress=unmatchedSuppression"
- "--suppress=unusedFunction"
71 changes: 32 additions & 39 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# -*- coding: utf-8 -*-
#
# Full list of options at http://www.sphinx-doc.org/en/master/config

# -- Path setup --------------------------------------------------------------
Expand All @@ -10,18 +8,20 @@
#
import os
import sys
import catkin_pkg.package

import catkin_pkg.package
from exhale import utils

package_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
catkin_package = catkin_pkg.package.parse_package(
os.path.join(package_dir, catkin_pkg.package.PACKAGE_MANIFEST_FILENAME))
os.path.join(package_dir, catkin_pkg.package.PACKAGE_MANIFEST_FILENAME)
)
sys.path.insert(0, os.path.abspath(os.path.join(package_dir, "src")))


# -- Helper functions --------------------------------------------------------


def count_files():
""":returns tuple of (num_py, num_cpp)"""
num_py = 0
Expand All @@ -42,7 +42,7 @@ def count_files():
# -- Project information -----------------------------------------------------

project = catkin_package.name
copyright = '2019, Bit-Bots'
copyright = "2019, Bit-Bots"
author = ", ".join([a.name for a in catkin_package.authors])

# The short X.Y version
Expand All @@ -60,27 +60,27 @@ def count_files():
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.doctest',
'sphinx.ext.intersphinx',
'sphinx.ext.todo',
'sphinx.ext.coverage',
'sphinx.ext.imgmath',
'sphinx.ext.viewcode',
'sphinx_rtd_theme',
"sphinx.ext.autodoc",
"sphinx.ext.doctest",
"sphinx.ext.intersphinx",
"sphinx.ext.todo",
"sphinx.ext.coverage",
"sphinx.ext.imgmath",
"sphinx.ext.viewcode",
"sphinx_rtd_theme",
]

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
templates_path = ["_templates"]

# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
source_suffix = ".rst"

# The master toctree document.
master_doc = 'index'
master_doc = "index"

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand All @@ -92,7 +92,7 @@ def count_files():
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = None
Expand All @@ -108,24 +108,17 @@ def count_files():

if num_files_cpp > 0:
extensions += [
'breathe',
'exhale',
"breathe",
"exhale",
]

breathe_projects = {
project: os.path.join("_build", "doxyoutput", "xml")
}
breathe_projects = {project: os.path.join("_build", "doxyoutput", "xml")}
breathe_default_project = project

def specifications_for_kind(kind):
# Show all members for classes and structs
if kind == "class" or kind == "struct":
return [
":members:",
":protected-members:",
":private-members:",
":undoc-members:"
]
return [":members:", ":protected-members:", ":private-members:", ":undoc-members:"]
# An empty list signals to Exhale to use the defaults
else:
return []
Expand All @@ -136,21 +129,19 @@ def specifications_for_kind(kind):
"rootFileName": "library_root.rst",
"rootFileTitle": "C++ Library API",
"doxygenStripFromPath": "..",
"customSpecificationsMapping": utils.makeCustomSpecificationsMapping(
specifications_for_kind
),
"customSpecificationsMapping": utils.makeCustomSpecificationsMapping(specifications_for_kind),
# Suggested optional arguments
"createTreeView": True,
"exhaleExecutesDoxygen": True,
"exhaleDoxygenStdin": "INPUT = {}".format(os.path.join(package_dir, "include"))
"exhaleDoxygenStdin": "INPUT = {}".format(os.path.join(package_dir, "include")),
}

# -- Options for HTML output -------------------------------------------------

# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
html_theme = "sphinx_rtd_theme"

# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
Expand All @@ -161,7 +152,7 @@ def specifications_for_kind(kind):
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
html_static_path = ["_static"]

# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
Expand All @@ -173,21 +164,23 @@ def specifications_for_kind(kind):
#
# html_sidebars = {}

html_logo = os.path.join('_static', 'logo.png')
html_favicon = os.path.join('_static', 'logo.png')
html_logo = os.path.join("_static", "logo.png")
html_favicon = os.path.join("_static", "logo.png")


# -- Options for intersphinx extension ---------------------------------------

# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'https://docs.python.org/': None}
intersphinx_mapping = {"https://docs.python.org/": None}

# -- Options for todo extension ----------------------------------------------

# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True

# -- RST Standard variables ---------------------------------------------------
rst_prolog = ".. |project| replace:: {}\n".format(project)
rst_prolog = f".. |project| replace:: {project}\n"
rst_prolog += ".. |description| replace:: {}\n".format(catkin_package.description.replace("\n\n", "\n"))
rst_prolog += ".. |modindex| replace:: {}\n".format(":ref:`modindex`" if num_files_py > 0 else "Python module index is not available")
rst_prolog += ".. |modindex| replace:: {}\n".format(
":ref:`modindex`" if num_files_py > 0 else "Python module index is not available"
)
6 changes: 6 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[tool.black]
line-length = 120

[tool.ruff]
line-length = 120
select = ["F", "E", "W", "I", "N", "UP"]
48 changes: 23 additions & 25 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,29 @@
import glob

from setuptools import find_packages
from setuptools import setup
from setuptools import find_packages, setup

package_name = 'udp_bridge'
package_name = "udp_bridge"

setup(
name=package_name,
packages=find_packages(exclude=['test']),
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
('share/' + package_name + '/config', glob.glob('config/*.yaml')),
('share/' + package_name + '/launch', glob.glob('launch/*.launch')),
],
install_requires=[
'launch',
'setuptools',
],
zip_safe=True,
keywords=['ROS'],
license='MIT',
entry_points={
'console_scripts': [
f'receiver = {package_name}.receiver:main',
f'sender = {package_name}.sender:main',
],
}
name=package_name,
packages=find_packages(exclude=["test"]),
data_files=[
("share/ament_index/resource_index/packages", ["resource/" + package_name]),
("share/" + package_name, ["package.xml"]),
("share/" + package_name + "/config", glob.glob("config/*.yaml")),
("share/" + package_name + "/launch", glob.glob("launch/*.launch")),
],
install_requires=[
"launch",
"setuptools",
],
zip_safe=True,
keywords=["ROS"],
license="MIT",
entry_points={
"console_scripts": [
f"receiver = {package_name}.receiver:main",
f"sender = {package_name}.sender:main",
],
},
)
6 changes: 4 additions & 2 deletions test/rostests/test_sender.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#!/usr/bin/env python3
import rospy
import socket
from std_msgs import msg

import rospy
from bitbots_test.test_case import RosNodeTestCase
from std_msgs import msg


class SenderTestCase(RosNodeTestCase):
Expand All @@ -24,4 +25,5 @@ def test_topic_gets_published_and_sent(self):

if __name__ == "__main__":
from bitbots_test import run_rostests

run_rostests(SenderTestCase)
8 changes: 5 additions & 3 deletions test/rostests/test_sender_receiver.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#!/usr/bin/env python3
import rospy
from socket import gethostname
from std_msgs import msg
from bitbots_test.test_case import RosNodeTestCase

import rospy
from bitbots_test.mocks import MockSubscriber
from bitbots_test.test_case import RosNodeTestCase
from std_msgs import msg


class SenderReceiverTestCase(RosNodeTestCase):
Expand All @@ -23,4 +24,5 @@ def test_sent_message_gets_received_over_bridge(self):

if __name__ == "__main__":
from bitbots_test import run_rostests

run_rostests(SenderReceiverTestCase)
10 changes: 6 additions & 4 deletions test/unit_tests/test_aes_helper.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from udp_bridge import aes_helper
from hypothesis import given, assume
from hypothesis.strategies import text
from bitbots_test.test_case import TestCase
from hypothesis import assume, given
from hypothesis.strategies import text

from udp_bridge import aes_helper


class AesHelperTestCase(TestCase):
Expand All @@ -15,6 +16,7 @@ def test_decrypt_inverts_encrypt(self, message, key):
self.assertEqual(message, dec_text)


if __name__ == '__main__':
if __name__ == "__main__":
from bitbots_test import run_unit_tests

run_unit_tests(AesHelperTestCase)
3 changes: 1 addition & 2 deletions udp_bridge/aes_helper.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import base64
from typing import Optional

from cryptography.fernet import Fernet
from cryptography.hazmat.backends import default_backend
Expand All @@ -15,7 +14,7 @@ class AESCipher:
It is safe to keep one object because the internal python cipher is not reused.
"""

def __init__(self, key: Optional[str]):
def __init__(self, key: str | None):
"""
:param key: The passphrase used to encrypt and decrypt messages.
If it is None, no encryption/decryption takes place
Expand Down
3 changes: 1 addition & 2 deletions udp_bridge/message_handler.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import base64
import pickle

from typing import Optional
from udp_bridge.aes_helper import AESCipher


class MessageHandler:
PACKAGE_DELIMITER = b"\xff\xff\xff"

def __init__(self, encryption_key: Optional[str]):
def __init__(self, encryption_key: str | None):
self.cipher = AESCipher(encryption_key)

def encrypt_and_encode(self, data: dict) -> bytes:
Expand Down
Loading

0 comments on commit 1452016

Please sign in to comment.